chore(ci): 迁移CI/CD到内网Harbor
All checks were successful
continuous-integration/drone/push Build is passing

- Dockerfile基础镜像切换到内网Harbor (192.168.195.25:19900)
- .drone.yml registry从外网域名改为内网Harbor
- Admin Dockerfile增加前端构建阶段(多阶段构建)
- 新增基础镜像推送脚本 (push-base-images.ps1/sh)
- 更新CI-CD部署文档
This commit is contained in:
zpc 2026-03-24 15:10:19 +08:00
parent 2f4290d5e2
commit 2b10624c21
7 changed files with 279 additions and 13 deletions

View File

@ -14,8 +14,8 @@ steps:
- name: build-api
image: plugins/docker
settings:
registry: docker.shhmkjgs.cn
repo: docker.shhmkjgs.cn/mi-assessment/api
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:
@ -27,12 +27,12 @@ steps:
from_secret: harbor_password
insecure: true
# ==================== 构建并推送 Admin 镜像 ====================
# ==================== 构建并推送 Admin API 镜像 ====================
- name: build-admin
image: plugins/docker
settings:
registry: docker.shhmkjgs.cn
repo: docker.shhmkjgs.cn/mi-assessment/admin
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:

135
docs/CI-CD部署文档.md Normal file
View File

@ -0,0 +1,135 @@
# CI/CD 部署文档
本文档描述 MiAssessment 学业邑规划项目的 CI/CD 流水线配置,基于 Drone CI + Docker + Harbor 私有镜像仓库(内网)。
## 一、整体架构
```
代码推送 (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 事件 |
## 二、构建的镜像
| 镜像 | 说明 | 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 位(用于回滚)。
## 三、流水线步骤
`.drone.yml` 定义了 3 个步骤:
1. `build-api` — 构建小程序 API 镜像
2. `build-admin` — 构建后台管理 API 镜像
3. `deploy` — SSH 部署(等待前两步完成)
> 两个构建步骤默认并行执行deploy 步骤通过 `depends_on` 等待全部完成后执行。
## 四、基础镜像(内网 Harbor
所有 Dockerfile 的基础镜像已切换到内网 Harbor避免依赖外网
| 基础镜像 | 内网地址 | 用途 |
|---------|---------|------|
| `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` | Admin 前端构建 |
### 一键推送基础镜像
在能访问外网的机器上执行脚本,将基础镜像推送到内网 Harbor
```bash
bash scripts/push-base-images.sh
```
如需手动推送单个镜像:
```bash
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.1 Drone CI Secrets
在 Drone 仓库设置 → Secrets 中配置:
| Secret 名称 | 说明 |
|-------------|------|
| `harbor_username` | Harbor 仓库用户名 |
| `harbor_password` | Harbor 仓库密码 |
| `ssh_username` | 部署服务器 SSH 用户名 |
| `ssh_password` | 部署服务器 SSH 密码 |
### 5.2 Harbor 镜像仓库
1. 在 Harbor 中创建项目 `mi-assessment``library`
2. `library` 为公开项目存放基础镜像pull 不需要登录)
3. `mi-assessment` 存放业务镜像,推送需要认证
4. 当前使用 HTTP`insecure: true`
### 5.3 部署服务器192.168.195.15
1. 安装 Docker 和 Docker Compose
2. 配置 Docker 信任 HarborHTTP
```bash
# /etc/docker/daemon.json
{
"insecure-registries": ["192.168.195.25:19900"]
}
# 重启 Docker
systemctl restart docker
```
3. 登录 Harbor
```bash
docker login 192.168.195.25:19900
```
4. 部署目录:`/disk/docker-compose/mi-assessment`
## 六、常见问题
### Q: 构建时拉取基础镜像失败?
基础镜像需要提前推送到内网 Harbor。运行 `bash scripts/push-base-images.sh` 一键推送。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`
### Q: 如何回滚?
使用 commit SHA 标签:
```bash
# 在服务器上修改 docker-compose.yml 中的镜像标签
# 例如将 :latest 改为 :a1b2c3d4
docker compose up -d
```
### Q: 如何手动触发构建?
在 Drone 界面找到对应仓库,点击 "New Build",选择分支即可。

View File

@ -0,0 +1,62 @@
# ============================================================
# 一键推送基础镜像到内网 Harbor (Windows PowerShell)
# 用法: powershell -ExecutionPolicy Bypass -File scripts/push-base-images.ps1
# ============================================================
$HarborHost = "192.168.195.25:19900"
$HarborProject = "library"
# 需要推送的基础镜像: 外网地址 -> 内网路径
$Images = @(
@{ Src = "mcr.microsoft.com/dotnet/aspnet:10.0-preview"; Dst = "dotnet/aspnet:10.0-preview" },
@{ Src = "mcr.microsoft.com/dotnet/sdk:10.0-preview"; Dst = "dotnet/sdk:10.0-preview" },
@{ Src = "node:20-alpine"; Dst = "node:20-alpine" }
)
Write-Host "==========================================" -ForegroundColor Cyan
Write-Host " 推送基础镜像到内网 Harbor" -ForegroundColor Cyan
Write-Host " Harbor: $HarborHost" -ForegroundColor Cyan
Write-Host "==========================================" -ForegroundColor Cyan
# 登录 Harbor
Write-Host "`n[登录] Harbor $HarborHost" -ForegroundColor Yellow
docker login $HarborHost
if ($LASTEXITCODE -ne 0) {
Write-Host "登录失败,请检查用户名密码" -ForegroundColor Red
exit 1
}
$Success = 0
$Fail = 0
foreach ($img in $Images) {
$src = $img.Src
$target = "$HarborHost/$HarborProject/$($img.Dst)"
Write-Host "`n------------------------------------------" -ForegroundColor Gray
Write-Host "[拉取] $src" -ForegroundColor Yellow
docker pull $src
if ($LASTEXITCODE -eq 0) {
Write-Host "[标签] $target" -ForegroundColor Yellow
docker tag $src $target
Write-Host "[推送] $target" -ForegroundColor Yellow
docker push $target
if ($LASTEXITCODE -eq 0) {
Write-Host "[完成] $($img.Dst)" -ForegroundColor Green
$Success++
} else {
Write-Host "[失败] 推送失败: $($img.Dst)" -ForegroundColor Red
$Fail++
}
} else {
Write-Host "[失败] 拉取失败: $src" -ForegroundColor Red
$Fail++
}
}
Write-Host "`n==========================================" -ForegroundColor Cyan
Write-Host " 完成: 成功 $Success, 失败 $Fail" -ForegroundColor Cyan
Write-Host "==========================================" -ForegroundColor Cyan

View File

@ -0,0 +1,62 @@
#!/bin/bash
# ============================================================
# 一键推送基础镜像到内网 Harbor
# 在能访问外网的机器上执行
# 用法: bash scripts/push-base-images.sh
# ============================================================
set -e
HARBOR_HOST="192.168.195.25:19900"
HARBOR_PROJECT="library"
# 需要推送的基础镜像映射: "外网镜像|内网路径"
IMAGES=(
"mcr.microsoft.com/dotnet/aspnet:10.0-preview|dotnet/aspnet:10.0-preview"
"mcr.microsoft.com/dotnet/sdk:10.0-preview|dotnet/sdk:10.0-preview"
"node:20-alpine|node:20-alpine"
)
echo "=========================================="
echo " 推送基础镜像到内网 Harbor"
echo " Harbor: ${HARBOR_HOST}"
echo "=========================================="
# 登录 Harbor
echo ""
echo "[登录] Harbor ${HARBOR_HOST}"
docker login "${HARBOR_HOST}"
SUCCESS=0
FAIL=0
for item in "${IMAGES[@]}"; do
SRC="${item%%|*}"
DST="${item##*|}"
TARGET="${HARBOR_HOST}/${HARBOR_PROJECT}/${DST}"
echo ""
echo "------------------------------------------"
echo "[拉取] ${SRC}"
if docker pull "${SRC}"; then
echo "[标签] ${TARGET}"
docker tag "${SRC}" "${TARGET}"
echo "[推送] ${TARGET}"
if docker push "${TARGET}"; then
echo "[完成] ✓ ${DST}"
((SUCCESS++))
else
echo "[失败] ✗ 推送失败: ${DST}"
((FAIL++))
fi
else
echo "[失败] ✗ 拉取失败: ${SRC}"
((FAIL++))
fi
done
echo ""
echo "=========================================="
echo " 完成: 成功 ${SUCCESS}, 失败 ${FAIL}"
echo "=========================================="

View File

@ -1,8 +1,13 @@
FROM mcr.microsoft.com/dotnet/aspnet:10.0-preview AS base
# ==================== 前端构建阶段 ====================
FROM 192.168.195.25:19900/library/node:20-alpine AS frontend
WORKDIR /app
EXPOSE 8080
COPY src/MiAssessment.Admin/admin-web/package*.json ./
RUN rm -f package-lock.json && npm install
COPY src/MiAssessment.Admin/admin-web/ .
RUN npx vite build --outDir dist
FROM mcr.microsoft.com/dotnet/sdk:10.0-preview AS build
# ==================== 后端构建阶段 ====================
FROM 192.168.195.25:19900/library/dotnet/sdk:10.0-preview AS build
WORKDIR /src
COPY ["src/MiAssessment.Admin/MiAssessment.Admin.csproj", "src/MiAssessment.Admin/"]
COPY ["src/MiAssessment.Admin.Business/MiAssessment.Admin.Business.csproj", "src/MiAssessment.Admin.Business/"]
@ -13,7 +18,9 @@ RUN dotnet restore "src/MiAssessment.Admin/MiAssessment.Admin.csproj"
COPY . .
RUN dotnet publish "src/MiAssessment.Admin/MiAssessment.Admin.csproj" -c Release -o /app/publish --no-restore
FROM base AS final
# ==================== 最终运行阶段 ====================
FROM 192.168.195.25:19900/library/dotnet/aspnet:10.0-preview AS final
WORKDIR /app
COPY --from=build /app/publish .
COPY --from=frontend /app/dist ./wwwroot
ENTRYPOINT ["dotnet", "MiAssessment.Admin.dll"]

View File

@ -1,5 +1,5 @@
# 构建阶段
FROM node:20-alpine AS build
FROM 192.168.195.25:19900/library/node:20-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN rm -f package-lock.json && npm install
@ -7,7 +7,7 @@ COPY . .
RUN npm run build
# 生产阶段
FROM nginx:alpine
FROM 192.168.195.25:19900/library/nginx:alpine
COPY --from=build /wwwroot /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80

View File

@ -1,8 +1,8 @@
FROM mcr.microsoft.com/dotnet/aspnet:10.0-preview AS base
FROM 192.168.195.25:19900/library/dotnet/aspnet:10.0-preview AS base
WORKDIR /app
EXPOSE 5238
FROM mcr.microsoft.com/dotnet/sdk:10.0-preview AS build
FROM 192.168.195.25:19900/library/dotnet/sdk:10.0-preview AS build
WORKDIR /src
COPY ["src/MiAssessment.Api/MiAssessment.Api.csproj", "src/MiAssessment.Api/"]
COPY ["src/MiAssessment.Model/MiAssessment.Model.csproj", "src/MiAssessment.Model/"]