- 新增 .drone.yml 流水线配置(server/admin/web 三服务并行构建+部署) - 新增 web/Dockerfile 和 web/nginx.conf(H5 Web Docker打包) - 新增 docker-compose.yml(使用Harbor镜像部署) - 新增 CI-CD部署文档.md - 更新 server Dockerfile 基础镜像为内网Harbor地址
16 KiB
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 创建项目
- 访问 Harbor 管理界面:
http://192.168.195.25:19900 - 创建一个新项目,名称使用项目标识(如
my-project) - 设置为私有项目(推送需要认证)
2.2 在 Drone CI 激活仓库
- 访问 Drone CI:
http://192.168.195.25:13080 - 使用 Gitea/Gogs 账号登录(Drone 与代码仓库联动)
- 在仓库列表中找到你的项目,点击 Activate
- 进入仓库设置 → 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 单服务项目模板
适用于只有一个服务需要构建和部署的项目:
---
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)需要分别构建的项目:
---
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 个步骤:
build-api— 构建小程序 API 镜像build-admin— 构建后台管理 API 镜像(并行)deploy— SSH 部署(等待前两步完成)
4.3 完整 .drone.yml
---
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 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 中使用内网镜像
# 使用内网 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
# 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 信任该仓库:
# 编辑 /etc/docker/daemon.json
{
"insecure-registries": ["192.168.195.25:19900"]
}
# 重启 Docker
systemctl restart docker
6.3 登录 Harbor
docker login 192.168.195.25:19900
# 输入用户名和密码
6.4 创建部署目录
mkdir -p /disk/docker-compose/my-project
cd /disk/docker-compose/my-project
6.5 编写 docker-compose.yml
示例(单服务):
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):
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 高级配置示例
按分支部署到不同环境
---
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 # 生产服务器
# ... 其他配置同上
添加构建通知(钉钉/企业微信)
- 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: 部署后服务没更新?
- 检查
docker compose pull是否拉到了新镜像 - 确认服务器 Docker 已配置
insecure-registries - 检查容器状态:
docker compose ps/docker compose logs
Q: 如何回滚到指定版本?
使用 commit SHA 标签:
cd /disk/docker-compose/my-project
# 修改 docker-compose.yml 中的镜像标签
# 将 :latest 改为 :a1b2c3d4(对应 commit SHA 前8位)
# 然后重新部署
docker compose up -d
Q: 如何手动触发构建?
在 Drone 界面找到对应仓库,点击 New Build,选择分支即可。
Q: 如何只部署不重新构建?
直接在服务器上操作:
cd /disk/docker-compose/my-project
docker compose pull
docker compose up -d
Q: 构建步骤超时?
在 .drone.yml 的 step 中添加超时配置(Drone 默认 60 分钟):
- name: build
image: plugins/docker
settings:
# ...
# Drone 2.x 不直接支持 step 级别 timeout,
# 可在仓库设置中调整全局超时时间
Q: 如何查看构建日志?
访问 Drone CI 界面 http://192.168.195.25:13080,找到对应仓库和构建编号,点击查看每个步骤的日志。