跳转至

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 ci
  • npm run test:coverage
  • npm 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 via 192.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:8080
  • wayne_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...