XINFRA 部署与 CI/CD 报告¶
生成日期:2026-08-27 | 基于源码深度分析
一、Docker 部署 (deploy/docker/)¶
1.1 前端镜像 — Dockerfile.frontend¶
| 阶段 | 基础镜像 | 操作 |
|---|---|---|
| 构建 | node:22-alpine |
npm ci → npm run build → 产物 /src/frontend/dist |
| 运行 | nginx:1.27-alpine |
复制产物到 /usr/share/nginx/html,覆盖 nginx 默认配置 |
- 暴露端口:
80 - 本地镜像标签:
xinfra-frontend:latest(Makefile)
1.2 后端镜像 — Dockerfile.server¶
| 阶段 | 基础镜像 | 操作 |
|---|---|---|
| 构建 | golang:1.26-alpine |
Go 代理 goproxy.cn,编译 authserver 二进制 |
| 运行 | alpine:3.22 |
放置于 /usr/local/bin/authserver |
- 暴露端口:
8083 - 运行用户:
65532:65532(非 root) - 入口点:
/usr/local/bin/authserver - 本地镜像标签:
xinfra-server:latest(Makefile)
💡 多阶段构建
前端和后端都采用 Docker 多阶段构建:构建阶段使用完整工具链(Node/Go),运行阶段使用最小化镜像(nginx/alpine),最终镜像体积大幅减小。后端以非 root 用户(65532)运行,遵循最小权限原则。
1.3 Nginx 配置 — nginx.frontend.conf¶
监听端口: 80
反向代理规则:
| 路径 | 目标 | 说明 |
|---|---|---|
/api/ |
http://xinfra-backend:8083 |
API 代理 |
/auth/ |
http://xinfra-backend:8083 |
认证代理 |
/swagger/ |
http://xinfra-backend:8083 |
Swagger 文档 |
/ |
try_files $uri $uri/ /index.html |
SPA fallback |
代理头:Host、X-Real-IP
💡 Nginx 反向代理
Nginx 作为前端入口,将 /api/、/auth/、/swagger/ 统一代理到后端 8083 端口,SPA 路由通过 try_files fallback 到 index.html 实现前端路由。
1.4 本地开发数据库 — docker-compose.mysql.yml¶
MySQL 服务:
- 镜像:
mysql:8.0.46 - 容器名:
authserver-mysql - 端口映射:
3000:3306 - 环境变量:
MYSQL_ROOT_PASSWORD=root123456,MYSQL_DATABASE=authserver,MYSQL_USER=auth,MYSQL_PASSWORD=auth,TZ=Asia/Shanghai - 字符集:
utf8mb4/utf8mb4_unicode_ci - 认证插件:
mysql_native_password - 数据卷:
./data/mysql:/var/lib/mysql
Redis 服务:
- 镜像:
redis:7.4-alpine - 容器名:
authserver-redis - 端口映射:
6379:6379 - 持久化:
appendonly yes - 数据卷:
./data/redis:/data
二、Kubernetes 部署 (deploy/k8s/wayne-xinfra.yaml)¶
graph TD
subgraph K8s["Kubernetes Cluster"]
Secret["Secret: xinfra-secret"]
CM["ConfigMap: xinfra-configmap"]
Harbor["Secret: harbor-registry"]
Redis["StatefulSet: xinfra-redis\n(1 replica, 2Gi)"]
Backend["Deployment: xinfra-backend\n(1 replica)"]
Frontend["Deployment: xinfra-frontend\n(1 replica)"]
SVC_BE["Service: xinfra-backend\nClusterIP:8083"]
SVC_FE["Service: xinfra-frontend\nNodePort:80→32002"]
end
Secret --> Backend
CM --> Backend
Backend --> Redis
Frontend --> SVC_BE
SVC_FE --> Frontend
style Redis fill:#e1f5fe
style Backend fill:#e8f5e9
style Frontend fill:#fff3e0
单一 YAML 文件,包含以下资源,均标注 wayne-app: xinfra, wayne-ns: xinfra:
💡 K8s 部署
整个应用通过单一 YAML 文件部署到 K8s,使用 Wayne 平台管理。Redis 使用 StatefulSet 保证持久化,前后端使用 Deployment 支持滚动更新。前端通过 NodePort 32002 暴露到外部。
2.1 Secret: xinfra-secret (Opaque)¶
| 键 | 说明 |
|---|---|
MYSQL_DSN |
MySQL 连接字符串(集群内 Service DNS) |
JWT_SECRET |
64 字节 hex 字符串 |
BOOTSTRAP_ADMIN_PASSWORD |
初始管理员密码 |
OAUTH_WAYNE_CLIENT_SECRET |
Wayne OAuth 客户端密钥 |
OIDC_CLOUDDM_CLIENT_SECRET |
CloudDM OIDC 客户端密钥 |
AWX_TOKEN / AWX_USERNAME / AWX_PASSWORD |
AWX 凭据 |
AWX_WEBHOOK_TOKEN |
AWX Webhook Token |
NOTIFY_WECOM_WEBHOOK_URL |
企业微信群机器人 Webhook |
DELIVERY_CREDENTIAL_SECRET / DELIVERY_SERVICE_TOKEN |
交付系统凭据 |
REDIS_PASSWORD |
Redis 密码 |
2.2 Secret: harbor-registry (kubernetes.io/dockerconfigjson)¶
- Harbor 地址:
218.11.5.223:30006 - 用户:
admin
2.3 ConfigMap: xinfra-configmap¶
关键配置项:
| 域 | 配置 |
|---|---|
| 应用 | APP_ENV=prod, HTTP_ADDR=:8083, AUTO_MIGRATE=true |
| Redis | REDIS_ADDR=xinfra-redis:6379, REDIS_DB=0 |
| SSO | SSO_ENABLED=false |
| 公网地址 | PUBLIC_BASE_URL=http://218.11.5.223:32002 |
| JWT | JWT_ISSUER=authserver, JWT_TTL_MINUTES=120 |
| SAML | IDP metadata URL、ACS URL、SP 证书路径 |
| OIDC | authorization/token/userinfo/jwks 端点 |
| Wayne | WAYNE_API_BASE_URL=http://wayne-backend.demo.svc.cluster.local:8080 |
| Archery | ARCHERY_API_BASE_URL=http://archery.archery.svc.cluster.local:9123 |
| AWX | AWX_BASE_URL=http://awx-demo-service.awx.svc.cluster.local |
| 交付调度 | DELIVERY_SCHEDULER_ENABLED=true, 限制参数: global=2, target=2, host_instance=4 |
| Vault | VAULT_ENABLED=true, VAULT_ADDR=http://vault-active.vault.svc.cluster.local:8200 |
| PostgreSQL HA | pgbackrest、postgres_exporter、etcd 组件 URL、digest、模板 ID |
| Sina | SINA_BASE_URL=https://sinai.qiniu.io:443, 同步间隔 30 分钟 |
2.4 StatefulSet: xinfra-redis¶
- 镜像:
redis:7.4-alpine - 副本:1
- 持久化存储:2Gi,
storageClassName: local-path - 资源:requests 50m/128Mi, limits 500m/512Mi
- 探针:readiness/liveness 均通过
redis-cli ping检测
2.5 Deployment: xinfra-backend¶
- 镜像:
218.11.5.223:30006/xinfra/xinfra-backend:latest - 镜像拉取策略:
Always - 副本:1,滚动更新(maxSurge 20%, maxUnavailable 1)
- 环境来源:
envFrom—xinfra-configmap,xinfra-secret,xinfra-vault-approle - 挂载卷:
xinfra-saml-certs→/authserver/backend/certs(只读) - 资源:requests 500m/3Gi, limits 1 CPU/3Gi
- 探针:readiness
/readyz(10s 延迟), liveness/healthz(20s 延迟)
2.6 Deployment: xinfra-frontend¶
- 镜像:
218.11.5.223:30006/xinfra/xinfra-frontend:latest - 副本:1,滚动更新
- 资源:requests 50m/64Mi, limits 500m/256Mi
- 探针:readiness/liveness 均检测
/
2.7 Service¶
| Service | 类型 | 端口映射 |
|---|---|---|
xinfra-backend |
ClusterIP | 8083 |
xinfra-frontend |
NodePort | 80 → 32002 |
三、CI/CD (.github/workflows/ci.yml)¶
3.1 触发条件¶
push到main分支- 所有
pull_request
3.2 全局配置¶
- 并发控制:
ci-${{ github.workflow }}-${{ github.ref }},取消进行中的同组任务 - 权限:
contents: read - Go 缓存: 自定义 GOPATH,GOMODCACHE, GOCACHE
- S3 缓存: 七牛 S3 兼容存储(
las-github-runner-dal,s3.us-north-1.qiniucs.com)
3.3 Job 依赖图¶
graph TD
Prepare["prepare\nGo mod hash"] --> GoCache["go-mod-cache\n依赖缓存"]
GoCache --> Backend["backend-unit\ngo vet + test"]
FE["frontend-validation\nnpm test + build"] --> Integration["integration\n端到端测试"]
Backend --> Integration
Backend --> Coverage["coverage-upload\nCodecov"]
FE --> Coverage
Integration --> Coverage
style Prepare fill:#e1f5fe
style Backend fill:#e8f5e9
style FE fill:#fff3e0
style Integration fill:#fce4ec
💡 CI 流水线
流水线采用 5 个 Job:prepare 计算 Go 模块 hash → go-mod-cache 缓存依赖 → backend-unit 并行跑后端单测 → frontend-validation 并行跑前端测试+构建 → integration 启动真实 MySQL 做端到端验证。最后 coverage-upload 汇总覆盖率上传 Codecov。
3.4 Job 详情¶
prepare¶
- Runner:
github-runner-ubuntu-24-04 - 仅限仓库
1024XEngineer/xinfra - 输出:
ci_go_mod_hash(对go.mod+go.sum做双重 SHA256)
go-mod-cache¶
- 依赖:
prepare - 步骤:checkout → Go 环境准备 →
go mod download→ 保存到 S3
backend-unit¶
- 依赖:
prepare,go-mod-cache - 步骤:
- Checkout + Go 环境准备
go vet ./...go test -race -covermode=atomic -coverprofile=coverage.out ./...- (仅 main push)上传 coverage 到 S3
frontend-validation¶
- 无依赖(可并行)
- 步骤:
- Checkout + Node.js setup(版本来自
.nvmrc,缓存 npm) npm cinpm run test:coveragenpm run build- (仅 main push)上传 lcov.info 到 S3
integration¶
- 依赖:
prepare,go-mod-cache,backend-unit,frontend-validation - Services: MySQL 8.0.46(端口 3306)
- 步骤:
- Checkout + Go 环境准备
- 运行
scripts/ci/integration.sh:- 启动后端(
go run ./cmd/server) - 等待
/readyz返回status: ok(最多 30 次,每次 2s) - 验证
/healthz和/api/v1/ping - 运行集成测试
- 启动后端(
- 环境变量:
APP_ENV=test,HTTP_ADDR=127.0.0.1:8080,AUTO_MIGRATE=true,SSO_ENABLED=false
coverage-upload¶
- 依赖:
backend-unit,frontend-validation,integration - 仅在
main分支 push 时运行 - 从 S3 下载前后端 coverage 文件
- 使用
codecov/codecov-action@v7上传
3.5 Composite Actions¶
ci-go-prep (.github/actions/ci-go-prep/action.yml)¶
actions/setup-go@v6,版本来自server/go.mod- 创建 Go 目录
- 从 S3 恢复 Go 模块缓存
ci-s3-prep (.github/actions/ci-s3-prep/action.yml)¶
- 安装
rclone(如果不存在)
3.6 CI 辅助脚本¶
| 脚本 | 功能 |
|---|---|
s3-cache-common.sh |
封装 rclone 配置七牛 S3,提供 s3_cache_get/put/upload_if_changed/upload_if_missing 函数 |
save-go-cache.sh |
将 Go 模块缓存打包为 .tar.zst 上传到 S3 |
restore-go-cache.sh |
从 S3 下载并解压 Go 模块缓存 |
coverage-report-s3.sh |
覆盖率报告的 S3 上传/下载工具 |
四、Makefile¶
| Target | 功能 |
|---|---|
help |
显示帮助信息(默认目标) |
build |
构建前后端(build-frontend + build-server) |
build-frontend |
npm install && npm run build(带 nvm 切换) |
build-server |
go build -o bin/xinfra ./cmd/server |
publish-harbor [IMAGE_TAG=<tag>] |
调用 scripts/publish-harbor.sh 构建并推送镜像到 Harbor |
run |
并行启动前后端开发服务器 |
run-frontend |
仅启动前端开发服务器 |
run-server |
仅启动后端开发服务器 |
test |
运行所有测试(test-frontend + test-server) |
test-frontend |
npm run test |
test-server |
go test ./... |
docker |
构建 Docker 镜像(docker-frontend + docker-server) |
docker-frontend |
docker build -t xinfra-frontend:latest -f deploy/docker/Dockerfile.frontend . |
docker-server |
docker build -t xinfra-server:latest -f deploy/docker/Dockerfile.server . |
clean |
清理 frontend/dist, node_modules, server/bin, server/vendor |
dev-up |
docker compose -f server/docker-compose.mysql.yml up -d |
dev-down |
docker compose -f server/docker-compose.mysql.yml down |
swagger |
swag init -g internal/router/router.go -o ./docs |
migrate-up |
go run ./cmd/server migrate up |
migrate-down |
go run ./cmd/server migrate down |
publish-harbor.sh 脚本详情¶
- Harbor 地址:
218.11.5.223:30006,项目:xinfra - Tag 策略:默认取
git rev-parse --short=12 HEAD;工作区有改动时追加-dirty-<时间戳> - 构建命令:
docker buildx build --platform linux/amd64,同时打tag和latest - 推送两个镜像:
xinfra/xinfra-backend和xinfra/xinfra-frontend
五、本地开发配置 (config/local/)¶
5.1 PostgreSQL 交付 AWX 开发配置¶
AWX_BASE_URL=http://127.0.0.1:59123- AWX 对象:Project、Inventory、Job Template、Rollback Template
- 目标主机:
218.11.5.224(SSH via192.168.1.5) - Playbook:
postgresql-deploy.yml/postgresql-rollback.yml
5.2 PostgreSQL HA E2E 测试配置¶
AWX_BASE_URL=http://218.11.5.223:31768- EE 镜像:
192.168.1.4:30006/xinfra/awx-ee - Workflow:
XINFRA PostgreSQL HA E2E Delivery v1 - Container Group:CPU 250m/2, Memory 256Mi/2Gi
5.3 后端 PostgreSQL 交付运行时配置¶
- 调度器参数:
DELIVERY_SCHEDULER_ENABLED=true,DELIVERY_POLL_SECONDS=3 - MySQL 模板:Config Apply, Decommission(保留 15 天), Restore, Purge
六、Nginx 配置汇总¶
6.1 生产 Docker 配置 (deploy/docker/nginx.frontend.conf)¶
简单 SPA 配置,监听 80 端口,反向代理 /api/、/auth/、/swagger/ 到 xinfra-backend:8083。
6.2 本地开发网关 (local/nginx.local.conf)¶
监听端口: 8089
Upstream 后端:
authserver_backend→127.0.0.1:8083(keepalive 32)authserver_frontend→127.0.0.1:5173(Vite dev server)wayne_backend→127.0.0.1:8080wayne_frontend→127.0.0.1:4200
路由规则:
/healthz,/readyz→ authserver_backend/auth/api/,/auth/oauth/,/auth/.well-known/→ authserver_backend/wayne/→ wayne_frontend(rewrite 去掉/wayne/前缀)/api/→ wayne_backend(携带 Authorization 和 X-Wayne-Emergency-Authorization 头)/→ authserver_frontend(SPA 默认)
七、关键端口汇总¶
| 服务 | 端口 | 场景 |
|---|---|---|
| 前端 (nginx) | 80 | Docker/K8s |
| 后端 (authserver) | 8083 | 全场景 |
| MySQL | 3306 (映射到 3000) | 本地开发 |
| Redis | 6379 | 本地开发 / K8s |
| 本地网关 nginx | 8089 | 本地开发 |
| Vite dev server | 5173 | 本地开发 |
| Wayne 后端 | 8080 | 本地开发 |
| Wayne 前端 | 4200 | 本地开发 |
| K8s NodePort (前端) | 32002 | K8s 生产 |
| AWX API | 59123 | 本地开发 |
八、关键镜像汇总¶
| 镜像 | 版本 |
|---|---|
node |
22-alpine |
nginx |
1.27-alpine |
golang |
1.26-alpine |
alpine |
3.22 |
mysql |
8.0.46 |
redis |
7.4-alpine |
218.11.5.223:30006/xinfra/xinfra-backend |
latest (K8s) |
218.11.5.223:30006/xinfra/xinfra-frontend |
latest (K8s) |
192.168.1.4:30006/xinfra/awx-ee |
sha256:d6fca88c... |