diff --git a/CI-CD部署文档.md b/CI-CD部署文档.md index 90acddb..88d2f8c 100644 --- a/CI-CD部署文档.md +++ b/CI-CD部署文档.md @@ -1,6 +1,6 @@ # CI/CD 部署文档 -本文档描述学业邑规划项目的 CI/CD 流水线配置,基于 Drone CI + Docker + Harbor 私有镜像仓库。 +本文档描述 LiveForum 论坛社区项目的 CI/CD 流水线配置,基于 Drone CI + Docker + Harbor 私有镜像仓库。 ## 一、整体架构 @@ -10,346 +10,114 @@ | 组件 | 说明 | |------|------| -| CI 平台 | Drone CI | -| 镜像仓库 | Harbor (`docker.shhmkjgs.cn`) | +| CI 平台 | Drone CI (`192.168.195.25:13080`) | +| 镜像仓库 | Harbor (`192.168.195.25:19900`,HTTP) | | 部署方式 | Docker Compose | +| 部署服务器 | `192.168.195.15` | | 触发条件 | `master` 分支 push 事件 | -## 二、流水线步骤说明 +## 二、构建的镜像 -当前 `.drone.yml` 定义了 3 个步骤: +| 镜像 | 说明 | Dockerfile | 构建上下文 | +|------|------|-----------|-----------| +| `live-forum/webapi` | 小程序 API(.NET 8) | `server/webapi/LiveForum/LiveForum.WebApi/Dockerfile` | `server/webapi/LiveForum` | +| `live-forum/admin-api` | 后台管理 API(.NET 8) | `server/admin/ZrAdminNetCore/ZR.Admin.WebApi/Dockerfile` | `server/admin/ZrAdminNetCore` | +| `live-forum/admin-web` | 后台管理前端(Vue 3 + Nginx) | `server/admin/ZrAdminNetCore/ZR.Vue/Dockerfile` | `server/admin/ZrAdminNetCore/ZR.Vue` | -### 2.1 build-api — 构建小程序 API 镜像 +每个镜像打两个标签:`latest` 和 commit SHA 前 8 位(用于回滚)。 -- 使用 `plugins/docker` 插件构建并推送镜像 -- Dockerfile 路径:`server/MiAssessment/src/MiAssessment.Api/Dockerfile` -- 构建上下文:`server/MiAssessment` -- 镜像地址:`docker.shhmkjgs.cn/mi-assessment/api` -- 标签:`latest` + commit SHA 前 8 位 +## 三、流水线步骤 -### 2.2 build-admin — 构建后台管理系统镜像 +`.drone.yml` 定义了 4 个步骤: -- Dockerfile 路径:`server/MiAssessment/src/MiAssessment.Admin/Dockerfile` -- 构建上下文:`server/MiAssessment` -- 镜像地址:`docker.shhmkjgs.cn/mi-assessment/admin` -- 标签策略同上 +1. `build-webapi` — 构建小程序 API 镜像 +2. `build-admin-api` — 构建后台管理 API 镜像 +3. `build-admin-web` — 构建后台管理前端镜像 +4. `deploy` — SSH 部署(等待前三步完成) -> `build-api` 和 `build-admin` 默认并行执行。 +> 三个构建步骤默认并行执行,deploy 步骤通过 `depends_on` 等待全部完成后执行。 -### 2.3 deploy — SSH 部署 +## 四、基础镜像(内网 Harbor) -- 等待两个构建步骤完成后执行(`depends_on`) -- SSH 连接到目标服务器 `192.168.195.15` -- 执行 `docker compose pull` 拉取最新镜像 -- 执行 `docker compose up -d` 重启服务 +所有 Dockerfile 的基础镜像已切换到内网 Harbor,避免依赖外网: -## 三、前置条件 +| 基础镜像 | 内网地址 | 用途 | +|---------|---------|------| +| `dotnet/aspnet:8.0` | `192.168.195.25:19900/library/dotnet/aspnet:8.0` | .NET 运行时 | +| `dotnet/sdk:8.0` | `192.168.195.25:19900/library/dotnet/sdk:8.0` | .NET 构建 | +| `node:18-alpine` | `192.168.195.25:19900/library/node:18-alpine` | Vue 前端构建 | +| `nginx:alpine` | `192.168.195.25:19900/library/nginx:alpine` | 前端运行 | -### 3.1 Drone CI 配置 +如需更新基础镜像,在能访问外网的机器上拉取、tag、push: -1. 在 Drone 管理界面激活本仓库 -2. 确保仓库根目录存在 `.drone.yml` 文件 -3. 配置以下 Secrets(在 Drone 仓库设置 → Secrets 中添加): +```bash +docker pull mcr.microsoft.com/dotnet/aspnet:8.0 +docker tag mcr.microsoft.com/dotnet/aspnet:8.0 192.168.195.25:19900/library/dotnet/aspnet:8.0 +docker push 192.168.195.25:19900/library/dotnet/aspnet:8.0 +``` -| Secret 名称 | 说明 | 示例 | -|-------------|------|------| -| `harbor_username` | Harbor 仓库用户名 | `admin` | -| `harbor_password` | Harbor 仓库密码 | `****` | -| `ssh_username` | 部署服务器 SSH 用户名 | `root` | -| `ssh_password` | 部署服务器 SSH 密码 | `****` | +## 五、前置条件 -### 3.2 Harbor 镜像仓库 +### 5.1 Drone CI Secrets -1. 在 Harbor 中创建项目 `mi-assessment` -2. 确保推送账号有该项目的写权限 -3. 当前使用 HTTP(`insecure: true`),生产环境建议配置 HTTPS +在 Drone 仓库设置 → Secrets 中配置: -### 3.3 部署服务器 +| Secret 名称 | 说明 | +|-------------|------| +| `harbor_username` | Harbor 仓库用户名 | +| `harbor_password` | Harbor 仓库密码 | +| `ssh_username` | 部署服务器 SSH 用户名 | +| `ssh_password` | 部署服务器 SSH 密码 | -服务器上需要准备: +### 5.2 Harbor 镜像仓库 + +1. 在 Harbor 中创建项目 `live-forum` 和 `library` +2. `library` 为公开项目,存放基础镜像(pull 不需要登录) +3. `live-forum` 存放业务镜像,推送需要认证 +4. 当前使用 HTTP(`insecure: true`) + +### 5.3 部署服务器(192.168.195.15) 1. 安装 Docker 和 Docker Compose -2. 创建部署目录和 compose 文件: +2. 配置 Docker 信任 Harbor(HTTP): ```bash -mkdir -p /disk/docker-compose/mi-assessment -``` - -3. 编写 `docker-compose.yml`(参考模板): - -```yaml -version: "3.8" - -services: - api: - image: docker.shhmkjgs.cn/mi-assessment/api:latest - container_name: mi-assessment-api - ports: - - "5238:5238" - environment: - - ASPNETCORE_ENVIRONMENT=Production - - ConnectionStrings__DefaultConnection=Server=sqlserver;Database=MiAssessment_Business;User Id=sa;Password=****;TrustServerCertificate=true - - ConnectionStrings__AdminConnection=Server=sqlserver;Database=MiAssessment_Admin;User Id=sa;Password=****;TrustServerCertificate=true - - Redis__ConnectionString=redis:6379 - depends_on: - - sqlserver - - redis - restart: always - - admin: - image: docker.shhmkjgs.cn/mi-assessment/admin:latest - container_name: mi-assessment-admin - ports: - - "8080:8080" - environment: - - ASPNETCORE_ENVIRONMENT=Production - - ConnectionStrings__DefaultConnection=Server=sqlserver;Database=MiAssessment_Business;User Id=sa;Password=****;TrustServerCertificate=true - - ConnectionStrings__AdminConnection=Server=sqlserver;Database=MiAssessment_Admin;User Id=sa;Password=****;TrustServerCertificate=true - - Redis__ConnectionString=redis:6379 - depends_on: - - sqlserver - - redis - restart: always - - sqlserver: - image: mcr.microsoft.com/mssql/server:2022-latest - container_name: mi-assessment-db - ports: - - "1433:1433" - environment: - - ACCEPT_EULA=Y - - MSSQL_SA_PASSWORD=YourStrong!Passw0rd - volumes: - - sqlserver-data:/var/opt/mssql - restart: always - - redis: - image: redis:7-alpine - container_name: mi-assessment-redis - ports: - - "6379:6379" - volumes: - - redis-data:/data - restart: always - -volumes: - sqlserver-data: - redis-data: -``` - -4. 配置 Docker 信任 Harbor 仓库(HTTP 方式): - -```bash -# 编辑 /etc/docker/daemon.json +# /etc/docker/daemon.json { - "insecure-registries": ["docker.shhmkjgs.cn"] + "insecure-registries": ["192.168.195.25:19900"] } # 重启 Docker systemctl restart docker ``` -5. 登录 Harbor: +3. 登录 Harbor: ```bash -docker login docker.shhmkjgs.cn +docker login 192.168.195.25:19900 ``` -## 四、.drone.yml 配置详解 - -```yaml ---- -kind: pipeline -type: docker -name: mi-assessment - -# 触发条件:master 分支的 push 事件 -trigger: - branch: - - master - event: - - push - -steps: - # 步骤1:构建 API 镜像 - - name: build-api - image: plugins/docker # Drone 官方 Docker 构建插件 - settings: - registry: docker.shhmkjgs.cn # Harbor 地址 - repo: docker.shhmkjgs.cn/mi-assessment/api # 镜像全名 - dockerfile: server/MiAssessment/src/MiAssessment.Api/Dockerfile - context: server/MiAssessment # Docker 构建上下文 - tags: - - latest - - ${DRONE_COMMIT_SHA:0:8} # commit 短哈希作为版本标签 - username: - from_secret: harbor_username - password: - from_secret: harbor_password - insecure: true # 允许 HTTP 推送 - - # 步骤2:构建 Admin 镜像 - - name: build-admin - image: plugins/docker - settings: - registry: docker.shhmkjgs.cn - repo: docker.shhmkjgs.cn/mi-assessment/admin - dockerfile: server/MiAssessment/src/MiAssessment.Admin/Dockerfile - context: server/MiAssessment - tags: - - latest - - ${DRONE_COMMIT_SHA:0:8} - username: - from_secret: harbor_username - password: - from_secret: harbor_password - insecure: true - - # 步骤3:SSH 部署(等待构建完成) - - name: deploy - image: appleboy/drone-ssh # SSH 远程执行插件 - settings: - host: 192.168.195.15 - username: - from_secret: ssh_username - password: - from_secret: ssh_password - port: 22 - script: - - cd /disk/docker-compose/mi-assessment - - docker compose pull # 拉取最新镜像 - - docker compose up -d # 重启容器 - depends_on: - - build-api - - build-admin -``` - -## 五、如何修改和扩展 - -### 5.1 添加多环境支持 - -如果需要区分 dev / staging / production,可以用分支触发不同流水线: - -```yaml ---- -kind: pipeline -type: docker -name: deploy-dev - -trigger: - branch: - - develop - event: - - push - -steps: - - name: build-api - image: plugins/docker - settings: - repo: docker.shhmkjgs.cn/mi-assessment/api - tags: - - dev-latest - - dev-${DRONE_COMMIT_SHA:0:8} - # ... 其他配置同上 - - - name: deploy-dev - image: appleboy/drone-ssh - settings: - host: 192.168.195.20 # 开发环境服务器 - script: - - cd /disk/docker-compose/mi-assessment-dev - - docker compose pull - - docker compose up -d - depends_on: - - build-api -``` - -### 5.2 添加单元测试步骤 - -在构建之前加入测试: - -```yaml -steps: - - name: test - image: mcr.microsoft.com/dotnet/sdk:10.0-preview - commands: - - cd server/MiAssessment - - dotnet restore - - dotnet test --no-restore --verbosity normal - - - name: build-api - # ... - depends_on: - - test -``` - -### 5.3 添加构建通知 - -使用钉钉或企业微信通知构建结果: - -```yaml - - name: notify - image: plugins/webhook - settings: - urls: https://oapi.dingtalk.com/robot/send?access_token=xxxx - content_type: application/json - template: | - { - "msgtype": "text", - "text": { - "content": "MiAssessment 部署完成\n分支: {{build.branch}}\n提交: {{build.commit}}\n状态: {{build.status}}" - } - } - depends_on: - - deploy - when: - status: - - success - - failure -``` - -### 5.4 添加 admin-web 前端构建 - -如果后台前端需要独立构建和部署: - -```yaml - - name: build-admin-web - image: plugins/docker - settings: - registry: docker.shhmkjgs.cn - repo: docker.shhmkjgs.cn/mi-assessment/admin-web - dockerfile: server/MiAssessment/src/MiAssessment.Admin/admin-web/Dockerfile - context: server/MiAssessment/src/MiAssessment.Admin/admin-web - tags: - - latest - - ${DRONE_COMMIT_SHA:0:8} - username: - from_secret: harbor_username - password: - from_secret: harbor_password - insecure: true -``` +4. 部署目录:`/disk/docker-compose/live-forum-new` ## 六、常见问题 -### Q: 构建失败怎么排查? +### Q: 构建时拉取基础镜像失败? -1. 在 Drone 界面查看失败步骤的日志 -2. 常见原因: - - Secrets 未配置或配置错误 - - Dockerfile 路径不对 - - Harbor 仓库项目不存在 - - 网络不通(CI Runner 无法访问 Harbor) +基础镜像需要提前推送到内网 Harbor。Drone CI 的 Docker daemon 也需要配置 `insecure-registries`(在 `.drone.yml` 中通过 `insecure: true` 处理推送,但 Dockerfile 中的 FROM 拉取需要 runner 层面配置)。 + +### Q: Harbor 认证失败(unauthorized)? + +检查 Drone Secrets 中的 `harbor_username` / `harbor_password` 是否正确且未过期。 ### Q: 部署后服务没更新? 1. 检查 `docker compose pull` 是否拉到了新镜像 2. 确认服务器 Docker 已配置 `insecure-registries` -3. 检查容器是否正常启动:`docker compose ps` / `docker compose logs` +3. 检查容器状态:`docker compose ps` / `docker compose logs` ### Q: 如何回滚? -使用 commit SHA 标签回滚: +使用 commit SHA 标签: ```bash # 在服务器上修改 docker-compose.yml 中的镜像标签 @@ -357,6 +125,10 @@ steps: docker compose up -d ``` +### Q: admin-web 构建报 COPY failed: stat app/dist? + +`vite.config.js` 中 `outDir` 配置了服务器绝对路径,Dockerfile 中已通过 `npx vite build --mode production --outDir dist` 覆盖输出到 `dist` 目录。 + ### Q: 如何手动触发构建? -在 Drone 界面找到对应仓库,点击 "New Build" 按钮,选择分支即可。 +在 Drone 界面找到对应仓库,点击 "New Build",选择分支即可。