307 lines
11 KiB
Markdown
307 lines
11 KiB
Markdown
# BuildFlow CICD 设计文档
|
||
|
||
- **日期**:2026-06-27
|
||
- **状态**:待主公审阅
|
||
- **范围**:将 `buildflow` 门户网站接入现有 Jenkins + 私有 Registry 的 CICD 体系,并初始化为独立 Gitea 仓库
|
||
|
||
---
|
||
|
||
## 1. 背景与目标
|
||
|
||
### 1.1 背景
|
||
|
||
`buildflow` 是 BuildFlow 低代码平台的门户网站(React 18 + Vite 6 + Tailwind + Nginx 静态托管),项目骨架已搭好,具备:
|
||
|
||
- 完整源码与 4 个页面(首页 / 功能 / 组件库 / 定价)
|
||
- 多阶段 `Dockerfile`(Node 构建 + Nginx 运行)
|
||
- `docker-compose.yml`、`nginx.conf`、`.gitignore`
|
||
|
||
同 workspace 的 `rag-frontend` 已有成熟的 Jenkins CICD 流水线,复用同一套基建(私有 Registry、部署目录、Jenkins agent)。
|
||
|
||
### 1.2 目标
|
||
|
||
1. 把 `buildflow` 初始化为独立 git 仓库并推送到 Gitea(`192.168.1.154`)。
|
||
2. 为 `buildflow` 配置 Jenkins 流水线:提交代码即自动构建镜像 → 推送 Registry → 部署到 `192.168.1.154`。
|
||
3. 在 rag-frontend 模式基础上做**轻量增强**:加入质量门禁(lint + 类型检查)与部署后健康检查。
|
||
|
||
### 1.3 非目标(YAGNI)
|
||
|
||
- 不做单元测试、镜像漏洞扫描、蓝绿/回滚、构建缓存优化(留待后续按需迭代)。
|
||
- 不改造其他仓库的 CICD。
|
||
|
||
---
|
||
|
||
## 2. 现状分析(已勘验)
|
||
|
||
### 2.1 buildflow 现状
|
||
|
||
| 项 | 现状 | 备注 |
|
||
|---|---|---|
|
||
| 构建 | `pnpm build` = `tsc -b && vite build`,产物 `dist/` | 质量门禁可用 `pnpm lint` + `pnpm check` |
|
||
| Dockerfile | 多阶段:`node:20-alpine` 构建 → `nginx:1.27-alpine` 运行 | 仅 `pnpm build`,无 lint/check |
|
||
| nginx.conf | `listen 80` | **需改为 5173** |
|
||
| docker-compose.yml | bridge 网络,`ports: 80:80` | 需改端口与网络策略 |
|
||
| 端口占用 | 占宿主 80 | 与 rag-frontend(host 模式占 80)冲突 |
|
||
|
||
### 2.2 现有 CICD 基建(取自 `rag-frontend/Jenkinsfile`)
|
||
|
||
- **私有 Registry**:`192.168.1.154:31010`
|
||
- **Registry 账号**:`docker` / `dockerxn001624.`(与 rag-frontend 一致)
|
||
- **镜像命名**:`docker/<name>`,双 tag:`$BUILD_NUMBER` + `latest`
|
||
- **部署目录**:`/home/xiangning/deploy/<name>`
|
||
- **部署方式**:Jenkins agent 在 `192.168.1.154` 本机执行 `docker compose`,生成 `network_mode: host` 的 compose 文件,`pull → down → up`
|
||
- **流水线阶段**:Checkout → Build → Push → Deploy(无质量门禁、无健康检查)
|
||
|
||
---
|
||
|
||
## 3. 关键设计决策
|
||
|
||
### 3.1 端口与网络策略(核心关隘)
|
||
|
||
**问题**:主公要求部署到 154、端口 5173,并沿用 rag-frontend 的 `network_mode: host`。host 模式下容器端口即宿主端口;若镜像内 Nginx 仍 `listen 80`,则与 rag-frontend 争夺宿主 80 端口。
|
||
|
||
**决策**:让镜像内 Nginx **监听 5173**,host 模式下 5173 直接暴露在宿主,互不冲突。
|
||
|
||
| 环境 | 网络模式 | 端口 | 访问 |
|
||
|---|---|---|---|
|
||
| 本地 `docker compose up` | bridge | `5173:5173` | `http://localhost:5173` |
|
||
| 生产(Jenkins 部署) | host | Nginx 监听 5173 | `http://192.168.1.154:5173` |
|
||
|
||
> 镜像统一 `listen 5173`;本地用 bridge 映射规避 macOS host 网络限制,生产用 host 与 rag-frontend 体系一致。
|
||
|
||
### 3.2 质量门禁的落点
|
||
|
||
**问题**:rag-frontend 流水线无质量检查。若在 Jenkins 增加 `pnpm lint` stage,需 Jenkins agent 预装 Node + pnpm。
|
||
|
||
**决策**:将质量门禁**内嵌进 Dockerfile 的 builder 阶段**(`pnpm lint && pnpm check && pnpm build`),随 `docker build` 自动执行,失败即构建失败。
|
||
|
||
**收益**:
|
||
|
||
- 不依赖 Jenkins agent 的 Node 环境
|
||
- Jenkins 结构保持与 rag-frontend 一致(改动最小)
|
||
- 质量门禁与构建产物同源,本地 `docker build` 也强制过门禁
|
||
|
||
### 3.3 部署后健康检查
|
||
|
||
在 Deploy 之后增加一个轻量 HealthCheck stage,`wget --spider http://127.0.0.1:5173`,确认服务起来;失败则流水线标红。
|
||
|
||
---
|
||
|
||
## 4. 文件改动清单
|
||
|
||
| 文件 | 动作 | 改动要点 |
|
||
|---|---|---|
|
||
| `buildflow/Jenkinsfile` | 新建 | 见 §5 |
|
||
| `buildflow/Dockerfile` | 改 | builder 阶段插入 `pnpm lint && pnpm check`(见 §6.1) |
|
||
| `buildflow/nginx.conf` | 改 | `listen 80` → `listen 5173`(见 §6.2) |
|
||
| `buildflow/docker-compose.yml` | 改 | bridge `5173:5173`,注释说明生产用 host(见 §6.3) |
|
||
| `buildflow/README.md` | 改 | 部署端口 80 → 5173,补 CICD 段落 |
|
||
| `buildflow/.gitignore` | 不动 | 已忽略 `node_modules`/`dist`,足够 |
|
||
|
||
---
|
||
|
||
## 5. Jenkinsfile 设计
|
||
|
||
结构与 rag-frontend 对齐,仅新增 HealthCheck stage,质量门禁由 Dockerfile 承担。
|
||
|
||
```groovy
|
||
pipeline {
|
||
agent any
|
||
|
||
environment {
|
||
CI_REGISTRY = '192.168.1.154:31010'
|
||
DOCKER_IMAGE = 'docker/buildflow-web'
|
||
DOCKER_TAG = "${BUILD_NUMBER}"
|
||
DEPLOY_DIR = '/home/xiangning/deploy/buildflow'
|
||
APP_PORT = '5173'
|
||
}
|
||
|
||
stages {
|
||
stage('Checkout') {
|
||
steps {
|
||
checkout scm
|
||
sh 'git log --oneline -5'
|
||
}
|
||
}
|
||
|
||
stage('Build') {
|
||
// docker build 内部执行 pnpm install → lint → check → build
|
||
// 任一步失败则本 stage 失败(质量门禁)
|
||
steps {
|
||
sh """
|
||
docker build -t ${DOCKER_IMAGE}:${DOCKER_TAG} .
|
||
docker tag ${DOCKER_IMAGE}:${DOCKER_TAG} ${DOCKER_IMAGE}:latest
|
||
"""
|
||
}
|
||
}
|
||
|
||
stage('Push') {
|
||
steps {
|
||
sh """
|
||
echo 'dockerxn001624.' | docker login -u docker --password-stdin ${CI_REGISTRY}
|
||
docker tag ${DOCKER_IMAGE}:${DOCKER_TAG} ${CI_REGISTRY}/${DOCKER_IMAGE}:${DOCKER_TAG}
|
||
docker tag ${DOCKER_IMAGE}:latest ${CI_REGISTRY}/${DOCKER_IMAGE}:latest
|
||
docker push ${CI_REGISTRY}/${DOCKER_IMAGE}:${DOCKER_TAG}
|
||
docker push ${CI_REGISTRY}/${DOCKER_IMAGE}:latest
|
||
"""
|
||
}
|
||
}
|
||
|
||
stage('Deploy') {
|
||
steps {
|
||
sh """
|
||
mkdir -p ${DEPLOY_DIR}
|
||
cd ${DEPLOY_DIR}
|
||
cat > docker-compose.yml << 'DCOF'
|
||
services:
|
||
buildflow-web:
|
||
image: ${CI_REGISTRY}/${DOCKER_IMAGE}:latest
|
||
container_name: buildflow-web
|
||
network_mode: host
|
||
restart: unless-stopped
|
||
DCOF
|
||
docker compose pull
|
||
docker compose down --remove-orphans || true
|
||
docker compose up -d
|
||
docker image prune -f
|
||
docker compose ps
|
||
"""
|
||
}
|
||
}
|
||
|
||
stage('HealthCheck') {
|
||
steps {
|
||
// 等待 Nginx 起来后探测本机 5173
|
||
sh """
|
||
sleep 3
|
||
wget -q --spider http://127.0.0.1:${APP_PORT}/ || exit 1
|
||
echo "=== HealthCheck OK: http://192.168.1.154:${APP_PORT} ==="
|
||
"""
|
||
}
|
||
}
|
||
}
|
||
|
||
post {
|
||
success { echo '=== BuildFlow CI/CD SUCCESS ===' }
|
||
failure { echo '=== BuildFlow CI/CD FAILED ===' }
|
||
always { deleteDir() }
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 6. 其他文件改动细节
|
||
|
||
### 6.1 Dockerfile(builder 阶段加质量门禁)
|
||
|
||
```dockerfile
|
||
# 现状:RUN pnpm build
|
||
# 改为:
|
||
RUN pnpm lint && pnpm check && pnpm build
|
||
```
|
||
|
||
> `pnpm check` = `tsc -b --noEmit`,`pnpm lint` = `eslint .`。两者皆过方进入 `vite build`。
|
||
|
||
### 6.2 nginx.conf
|
||
|
||
```diff
|
||
- listen 80;
|
||
- listen [::]:80;
|
||
+ listen 5173;
|
||
+ listen [::]:5173;
|
||
```
|
||
|
||
Dockerfile 的 `EXPOSE 80` 同步改为 `EXPOSE 5173`;`HEALTHCHECK` 探测 `http://127.0.0.1:5173/`。
|
||
|
||
### 6.3 docker-compose.yml(本地)
|
||
|
||
```yaml
|
||
services:
|
||
buildflow-web:
|
||
build: { context: ., dockerfile: Dockerfile }
|
||
image: buildflow-web:latest
|
||
container_name: buildflow-web
|
||
restart: unless-stopped
|
||
ports:
|
||
- "5173:5173" # 本地 bridge;生产由 Jenkins 生成 host network compose
|
||
healthcheck:
|
||
test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:5173/"]
|
||
interval: 30s
|
||
timeout: 3s
|
||
retries: 3
|
||
start_period: 5s
|
||
networks: [buildflow-net]
|
||
networks:
|
||
buildflow-net: { driver: bridge }
|
||
```
|
||
|
||
---
|
||
|
||
## 7. Gitea 仓库初始化与推送
|
||
|
||
由末将代为执行:
|
||
|
||
```bash
|
||
cd buildflow
|
||
git init
|
||
git add .
|
||
git commit -m "chore: init buildflow repo with CICD"
|
||
git branch -M main
|
||
git remote add origin http://<token>@<gitea-host>:<port>/<owner>/buildflow.git
|
||
git push -u origin main
|
||
```
|
||
|
||
**待主公提供(实现前)**:
|
||
|
||
| 项 | 说明 | 默认值 |
|
||
|---|---|---|
|
||
| Gitea 端口 | 主公给 3000,但 Grafana 亦占 3000,须核实 | 待确认 |
|
||
| owner | 用户名或组织名 | 待确认 |
|
||
| 仓库名 | | 默认 `buildflow` |
|
||
| access token | 推送凭证 | 待提供 |
|
||
|
||
> 安全:token 仅用于本次 `git push` 的 URL,末将提醒主公**事后清理 shell history**,并建议使用 Gitea 的限定范围 token(仅 `repo` 写权限)。
|
||
|
||
---
|
||
|
||
## 8. 部署参数总览
|
||
|
||
| 项 | 值 |
|
||
|---|---|
|
||
| Registry | `192.168.1.154:31010` |
|
||
| 镜像 | `docker/buildflow-web`(tag: `$BUILD_NUMBER` + `latest`) |
|
||
| 部署目录 | `/home/xiangning/deploy/buildflow` |
|
||
| 生产网络 | `network_mode: host` |
|
||
| 访问地址 | `http://192.168.1.154:5173` |
|
||
|
||
---
|
||
|
||
## 9. 风险与待确认项
|
||
|
||
1. **Gitea 端口冲突**:`192.168.1.154:3000` 既标为 Gitea,又是 Grafana(`docker-compose.infra.yml`)端口。需主公确认 Gitea 真实端口,否则推送地址错误。
|
||
2. **5173 占用**:需确认 154 上 5173 空闲(Vite dev 默认端口,生产服务器一般空闲)。
|
||
3. **Jenkins agent 假设**:沿用 rag-frontend 的"agent 在 154 本机执行 docker compose"假设,需确认 buildflow 使用的 agent 节点一致。
|
||
4. **lint 严格度**:buildflow 现为默认 eslint 配置,质量门禁应可通过;若规则触发误报,可调整规则或暂将 `pnpm lint` 降级为告警。
|
||
5. **本地 macOS host 网络**:本地 `docker compose` 采用 bridge 规避,生产用 host,两者端口访问一致。
|
||
|
||
---
|
||
|
||
## 10. 验收标准
|
||
|
||
- [ ] `buildflow` 已 git 初始化并成功推送到 Gitea。
|
||
- [ ] Gitea Webhook/轮询触发 Jenkins 构建(或手动触发)。
|
||
- [ ] `docker build` 内 lint + typecheck + build 全通过。
|
||
- [ ] 镜像成功推送至 `192.168.1.154:31010/docker/buildflow-web`。
|
||
- [ ] `192.168.1.154` 上容器以 host 模式运行,`http://192.168.1.154:5173` 可访问且返回门户首页。
|
||
- [ ] HealthCheck stage 通过。
|
||
|
||
---
|
||
|
||
## 11. 后续可选迭代(非本期)
|
||
|
||
- Jenkinsfile 参数化(环境、版本号)。
|
||
- 失败通知(钉钉/企业微信 webhook)。
|
||
- 构建缓存优化(pnpm store 缓存层)。
|
||
- 单元测试与镜像扫描。
|