HtmlToPdf/CI-CD部署文档.md
zpc 0a1eb497bd ci: Add Drone CI/CD pipeline configuration and deployment documentation
- Add `.drone.yml` with Drone CI pipeline for automated Docker image building and deployment
- Configure multi-stage build process: build Docker images and push to Harbor registry, then deploy via SSH
- Add CI-CD deployment documentation with architecture overview, quick start guide, and configuration templates
- Include single-service and multi-service project templates for reference
- Update `src/Dockerfile` for CI/CD integration
- Enable automated deployment to staging server on master branch push events
2026-04-05 14:20:14 +08:00

604 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 配置信任内网 HarborHTTP
由于 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`,找到对应仓库和构建编号,点击查看每个步骤的日志。