diff --git a/docs/CI-CD部署文档.md b/docs/CI-CD部署文档.md new file mode 100644 index 0000000..e727d09 --- /dev/null +++ b/docs/CI-CD部署文档.md @@ -0,0 +1,603 @@ +# CI/CD 部署文档 + +本文档描述基于 Drone CI + Docker + Harbor 私有镜像仓库(内网)的 CI/CD 流水线配置。其他项目可参考本文档搭建自己的 CI/CD 流程。 + +## 一、整体架构 + +``` +代码推送 (master) → Drone CI 触发 → 构建 Docker 镜像 → 推送内网 Harbor → SSH 部署到服务器 +``` + +| 组件 | 地址/说明 | +|------|----------| +| CI 平台 | Drone CI (`192.168.195.25:13080`) | +| 镜像仓库 | Harbor (`192.168.195.25:19900`,HTTP) | +| 部署方式 | Docker Compose | +| 部署服务器 | `192.168.195.15`(可按项目分配不同服务器) | +| 触发条件 | `master` 分支 push 事件 | + +## 二、快速开始(新项目接入指南) + +### 2.1 在 Harbor 创建项目 + +1. 访问 Harbor 管理界面:`http://192.168.195.25:19900` +2. 创建一个新项目,名称使用项目标识(如 `my-project`) +3. 设置为私有项目(推送需要认证) + +### 2.2 在 Drone CI 激活仓库 + +1. 访问 Drone CI:`http://192.168.195.25:13080` +2. 使用 Gitea/Gogs 账号登录(Drone 与代码仓库联动) +3. 在仓库列表中找到你的项目,点击 **Activate** +4. 进入仓库设置 → **Secrets**,添加以下密钥: + +| Secret 名称 | 说明 | 示例值 | +|-------------|------|--------| +| `harbor_username` | Harbor 仓库用户名 | `admin` | +| `harbor_password` | Harbor 仓库密码 | `Harbor12345` | +| `ssh_username` | 部署服务器 SSH 用户名 | `root` | +| `ssh_password` | 部署服务器 SSH 密码 | `your-password` | + +### 2.3 编写 `.drone.yml` + +在项目根目录创建 `.drone.yml`,参考下方模板。 + +### 2.4 编写 Dockerfile + +为每个需要构建的服务编写 Dockerfile。 + +### 2.5 编写 `docker-compose.yml` + +在部署服务器上创建 docker-compose 配置。 + +### 2.6 推送代码触发流水线 + +推送代码到 `master` 分支,Drone 会自动触发构建和部署。 + +## 三、`.drone.yml` 配置模板 + +### 3.1 单服务项目模板 + +适用于只有一个服务需要构建和部署的项目: + +```yaml +--- +kind: pipeline +type: docker +name: my-project # ← 改为你的项目名 + +trigger: + branch: + - master # ← 触发分支,可改为 main + event: + - push + +steps: + # ==================== 构建并推送镜像 ==================== + - name: build + image: plugins/docker + settings: + registry: 192.168.195.25:19900 + repo: 192.168.195.25:19900/my-project/app # ← 改为 Harbor项目名/镜像名 + dockerfile: Dockerfile # ← Dockerfile 路径 + context: . # ← 构建上下文目录 + tags: + - latest + - ${DRONE_COMMIT_SHA:0:8} # commit SHA 前8位,用于回滚 + username: + from_secret: harbor_username + password: + from_secret: harbor_password + insecure: true # Harbor 使用 HTTP 时必须 + + # ==================== 部署到服务器 ==================== + - name: deploy + image: appleboy/drone-ssh + settings: + host: 192.168.195.15 # ← 改为你的部署服务器 IP + username: + from_secret: ssh_username + password: + from_secret: ssh_password + port: 22 + script: + - cd /disk/docker-compose/my-project # ← 改为服务器上的部署目录 + - docker compose pull + - docker compose up -d + depends_on: + - build +``` + +### 3.2 多服务项目模板 + +适用于有多个服务(如 API + Admin)需要分别构建的项目: + +```yaml +--- +kind: pipeline +type: docker +name: my-project + +trigger: + branch: + - master + event: + - push + +steps: + # ==================== 构建服务 A ==================== + - name: build-service-a + image: plugins/docker + settings: + registry: 192.168.195.25:19900 + repo: 192.168.195.25:19900/my-project/service-a + dockerfile: src/ServiceA/Dockerfile + context: src + tags: + - latest + - ${DRONE_COMMIT_SHA:0:8} + username: + from_secret: harbor_username + password: + from_secret: harbor_password + insecure: true + + # ==================== 构建服务 B ==================== + - name: build-service-b + image: plugins/docker + settings: + registry: 192.168.195.25:19900 + repo: 192.168.195.25:19900/my-project/service-b + dockerfile: src/ServiceB/Dockerfile + context: src + tags: + - latest + - ${DRONE_COMMIT_SHA:0:8} + username: + from_secret: harbor_username + password: + from_secret: harbor_password + insecure: true + + # ==================== 部署到服务器 ==================== + - name: deploy + image: appleboy/drone-ssh + settings: + host: 192.168.195.15 + username: + from_secret: ssh_username + password: + from_secret: ssh_password + port: 22 + script: + - cd /disk/docker-compose/my-project + - docker compose pull + - docker compose up -d + depends_on: + - build-service-a # 等待所有构建完成 + - build-service-b +``` + +> 多个 build 步骤默认并行执行,deploy 通过 `depends_on` 等待全部完成后执行。 + +## 四、MiAssessment 项目实际配置 + +本项目(学业邑规划)的实际配置如下,供参考: + +### 4.1 构建的镜像 + +| 镜像 | 说明 | Dockerfile | 构建上下文 | +|------|------|-----------|-----------| +| `mi-assessment/api` | 小程序 API(.NET 10) | `server/MiAssessment/src/MiAssessment.Api/Dockerfile` | `server/MiAssessment` | +| `mi-assessment/admin` | 后台管理 API + 前端(.NET 10,内含 admin-web 构建产物) | `server/MiAssessment/src/MiAssessment.Admin/Dockerfile` | `server/MiAssessment` | + +每个镜像打两个标签:`latest` 和 commit SHA 前 8 位(用于回滚)。 + +### 4.2 流水线步骤 + +`.drone.yml` 定义了 3 个步骤: + +1. `build-api` — 构建小程序 API 镜像 +2. `build-admin` — 构建后台管理 API 镜像(并行) +3. `deploy` — SSH 部署(等待前两步完成) + +### 4.3 完整 `.drone.yml` + +```yaml +--- +kind: pipeline +type: docker +name: mi-assessment + +trigger: + branch: + - master + event: + - push + +steps: + - name: build-api + image: plugins/docker + settings: + registry: 192.168.195.25:19900 + repo: 192.168.195.25:19900/mi-assessment/api + dockerfile: server/MiAssessment/src/MiAssessment.Api/Dockerfile + context: server/MiAssessment + tags: + - latest + - ${DRONE_COMMIT_SHA:0:8} + username: + from_secret: harbor_username + password: + from_secret: harbor_password + insecure: true + + - name: build-admin + image: plugins/docker + settings: + registry: 192.168.195.25:19900 + repo: 192.168.195.25:19900/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 + + - name: deploy + image: appleboy/drone-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 为什么需要内网基础镜像 + +内网环境无法直接拉取 Docker Hub / MCR 的镜像,需要提前将基础镜像推送到内网 Harbor 的 `library` 项目中。 + +### 5.2 推送基础镜像 + +在能访问外网的机器上执行: + +```bash +# 一键推送(如果项目提供了脚本) +bash scripts/push-base-images.sh + +# 手动推送单个镜像 +docker pull mcr.microsoft.com/dotnet/aspnet:10.0-preview +docker tag mcr.microsoft.com/dotnet/aspnet:10.0-preview 192.168.195.25:19900/library/dotnet/aspnet:10.0-preview +docker push 192.168.195.25:19900/library/dotnet/aspnet:10.0-preview +``` + +### 5.3 常用基础镜像 + +| 基础镜像 | 内网地址 | 用途 | +|---------|---------|------| +| `dotnet/aspnet:10.0-preview` | `192.168.195.25:19900/library/dotnet/aspnet:10.0-preview` | .NET 运行时 | +| `dotnet/sdk:10.0-preview` | `192.168.195.25:19900/library/dotnet/sdk:10.0-preview` | .NET 构建 | +| `node:20-alpine` | `192.168.195.25:19900/library/node:20-alpine` | Node.js 前端构建 | +| `python:3.12-slim` | `192.168.195.25:19900/library/python:3.12-slim` | Python 项目 | +| `golang:1.22-alpine` | `192.168.195.25:19900/library/golang:1.22-alpine` | Go 项目 | +| `nginx:alpine` | `192.168.195.25:19900/library/nginx:alpine` | 静态文件服务 | + +### 5.4 Dockerfile 中使用内网镜像 + +```dockerfile +# 使用内网 Harbor 的基础镜像 +FROM 192.168.195.25:19900/library/node:20-alpine AS build +WORKDIR /app +COPY . . +RUN npm install && npm run build + +FROM 192.168.195.25:19900/library/nginx:alpine +COPY --from=build /app/dist /usr/share/nginx/html +``` + +## 六、部署服务器配置 + +### 6.1 安装 Docker 和 Docker Compose + +```bash +# CentOS / RHEL +yum install -y docker-ce docker-compose-plugin + +# Ubuntu / Debian +apt-get install -y docker-ce docker-compose-plugin + +# 启动 Docker +systemctl enable docker +systemctl start docker +``` + +### 6.2 配置信任内网 Harbor(HTTP) + +由于 Harbor 使用 HTTP 而非 HTTPS,需要配置 Docker 信任该仓库: + +```bash +# 编辑 /etc/docker/daemon.json +{ + "insecure-registries": ["192.168.195.25:19900"] +} + +# 重启 Docker +systemctl restart docker +``` + +### 6.3 登录 Harbor + +```bash +docker login 192.168.195.25:19900 +# 输入用户名和密码 +``` + +### 6.4 创建部署目录 + +```bash +mkdir -p /disk/docker-compose/my-project +cd /disk/docker-compose/my-project +``` + +### 6.5 编写 `docker-compose.yml` + +示例(单服务): + +```yaml +version: "3.8" + +services: + app: + image: 192.168.195.25:19900/my-project/app:latest + container_name: my-project-app + ports: + - "8080:8080" + environment: + - ASPNETCORE_ENVIRONMENT=Production + restart: unless-stopped +``` + +示例(多服务,参考 MiAssessment): + +```yaml +version: "3.8" + +services: + api: + image: 192.168.195.25:19900/mi-assessment/api:latest + container_name: mi-assessment-api + ports: + - "5000:8080" + environment: + - ASPNETCORE_ENVIRONMENT=Production + volumes: + - ./appsettings.api.json:/app/appsettings.Production.json + restart: unless-stopped + + admin: + image: 192.168.195.25:19900/mi-assessment/admin:latest + container_name: mi-assessment-admin + ports: + - "5001:8080" + environment: + - ASPNETCORE_ENVIRONMENT=Production + volumes: + - ./appsettings.admin.json:/app/appsettings.Production.json + restart: unless-stopped +``` + +## 七、Drone CI 配置详解 + +### 7.1 关键字段说明 + +| 字段 | 说明 | +|------|------| +| `kind: pipeline` | 流水线类型 | +| `type: docker` | 使用 Docker 执行器 | +| `trigger.branch` | 触发分支 | +| `trigger.event` | 触发事件(push / pull_request / tag) | +| `settings.registry` | Harbor 仓库地址 | +| `settings.repo` | 镜像完整路径(含 registry) | +| `settings.dockerfile` | Dockerfile 相对路径 | +| `settings.context` | Docker 构建上下文目录 | +| `settings.tags` | 镜像标签列表 | +| `settings.insecure` | 允许 HTTP 推送(Harbor 非 HTTPS 时必须) | +| `from_secret` | 引用 Drone Secrets 中的密钥 | +| `depends_on` | 步骤依赖,等待指定步骤完成后执行 | + +### 7.2 常用 Drone 变量 + +| 变量 | 说明 | 示例值 | +|------|------|--------| +| `${DRONE_COMMIT_SHA}` | 完整 commit SHA | `a1b2c3d4e5f6...` | +| `${DRONE_COMMIT_SHA:0:8}` | commit SHA 前 8 位 | `a1b2c3d4` | +| `${DRONE_BRANCH}` | 当前分支名 | `master` | +| `${DRONE_TAG}` | Git 标签(tag 事件时) | `v1.0.0` | +| `${DRONE_BUILD_NUMBER}` | 构建编号 | `42` | +| `${DRONE_REPO_NAME}` | 仓库名 | `mi-assessment` | + +### 7.3 高级配置示例 + +#### 按分支部署到不同环境 + +```yaml +--- +kind: pipeline +type: docker +name: deploy-staging + +trigger: + branch: + - develop + event: + - push + +steps: + - name: build + image: plugins/docker + settings: + registry: 192.168.195.25:19900 + repo: 192.168.195.25:19900/my-project/app + tags: + - staging + - ${DRONE_COMMIT_SHA:0:8} + # ... 其他配置同上 + + - name: deploy-staging + image: appleboy/drone-ssh + settings: + host: 192.168.195.20 # 测试服务器 + username: + from_secret: ssh_username + password: + from_secret: ssh_password + port: 22 + script: + - cd /disk/docker-compose/my-project-staging + - docker compose pull + - docker compose up -d + depends_on: + - build + +--- +kind: pipeline +type: docker +name: deploy-production + +trigger: + branch: + - master + event: + - push + +steps: + - name: build + image: plugins/docker + settings: + registry: 192.168.195.25:19900 + repo: 192.168.195.25:19900/my-project/app + tags: + - latest + - ${DRONE_COMMIT_SHA:0:8} + # ... 其他配置同上 + + - name: deploy-production + image: appleboy/drone-ssh + settings: + host: 192.168.195.15 # 生产服务器 + # ... 其他配置同上 +``` + +#### 添加构建通知(钉钉/企业微信) + +```yaml + - name: notify + image: plugins/webhook + settings: + urls: https://oapi.dingtalk.com/robot/send?access_token=xxx + content_type: application/json + template: | + { + "msgtype": "text", + "text": { + "content": "✅ {{repo.name}} 部署成功\n分支: {{build.branch}}\n提交: {{build.commit}}" + } + } + depends_on: + - deploy + when: + status: + - success +``` + +## 八、新项目接入清单 + +按以下清单逐项完成,即可为新项目接入 CI/CD: + +| # | 步骤 | 操作位置 | 说明 | +|---|------|---------|------| +| 1 | 创建 Harbor 项目 | Harbor Web UI | 项目名与代码仓库名一致 | +| 2 | 推送基础镜像 | 外网机器 | 将 Dockerfile 中用到的基础镜像推送到 `library` | +| 3 | 编写 Dockerfile | 代码仓库 | 使用内网基础镜像地址 | +| 4 | 编写 `.drone.yml` | 代码仓库根目录 | 参考上方模板 | +| 5 | 激活 Drone 仓库 | Drone Web UI | 点击 Activate | +| 6 | 配置 Drone Secrets | Drone Web UI | 添加 harbor / ssh 凭证 | +| 7 | 创建部署目录 | 部署服务器 | `/disk/docker-compose/{项目名}` | +| 8 | 编写 `docker-compose.yml` | 部署服务器 | 配置镜像、端口、环境变量 | +| 9 | 配置 `insecure-registries` | 部署服务器 | Docker daemon 信任 Harbor | +| 10 | 推送代码触发 | 代码仓库 | push 到 master 分支 | + +## 九、常见问题 + +### Q: 构建时拉取基础镜像失败? + +基础镜像需要提前推送到内网 Harbor。Drone Runner 的 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` + +### Q: 如何回滚到指定版本? + +使用 commit SHA 标签: + +```bash +cd /disk/docker-compose/my-project + +# 修改 docker-compose.yml 中的镜像标签 +# 将 :latest 改为 :a1b2c3d4(对应 commit SHA 前8位) +# 然后重新部署 +docker compose up -d +``` + +### Q: 如何手动触发构建? + +在 Drone 界面找到对应仓库,点击 **New Build**,选择分支即可。 + +### Q: 如何只部署不重新构建? + +直接在服务器上操作: + +```bash +cd /disk/docker-compose/my-project +docker compose pull +docker compose up -d +``` + +### Q: 构建步骤超时? + +在 `.drone.yml` 的 step 中添加超时配置(Drone 默认 60 分钟): + +```yaml + - name: build + image: plugins/docker + settings: + # ... + # Drone 2.x 不直接支持 step 级别 timeout, + # 可在仓库设置中调整全局超时时间 +``` + +### Q: 如何查看构建日志? + +访问 Drone CI 界面 `http://192.168.195.25:13080`,找到对应仓库和构建编号,点击查看每个步骤的日志。