Files
easygoadmin-wiki/EasyGoAdmin_Beego_AntdVue/zh/deploy/ci-cd.md
T
2026-10-20 21:19:44 +08:00

355 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 11.11 CI/CD 流水线
:::tip 概述
本节介绍项目的持续集成/持续部署(CI/CD)方案,包括 GitHub Actions 和 GitLab CI 的配置示例,以及自动化测试、构建和部署流程。
:::
## 流水线架构
```text
代码提交 → 代码检查 → 单元测试 → 构建打包 → 部署上线
│ │ │ │ │
▼ ▼ ▼ ▼ ▼
Git Push ESLint PHPUnit Docker 生产环境
PHPStan Vitest Image
```
## GitHub Actions
### 后端 CI 配置
```yaml
# =============================================================================
# .github/workflows/backend-ci.yml — 后端持续集成
# =============================================================================
# 触发条件:push 到 main/develop 分支,或向 main 发起 PR
# 执行环境:Ubuntu 最新版 + MySQL 8.0 服务容器
# 流程:代码检查 → 静态分析 → 单元测试 → 覆盖率上传
# =============================================================================
name: Backend CI
on:
push:
branches: [main, develop] # push 到这些分支时触发
pull_request:
branches: [main] # 向 main 发起 PR 时触发
jobs:
test:
runs-on: ubuntu-latest # 使用 GitHub 托管的最新 Ubuntu 运行器
# -------------------------------------------------------------------------
# 服务容器(GitHub Actions 自动启动,与运行器共享网络)
# -------------------------------------------------------------------------
services:
mysql:
image: mysql:8.0 # MySQL 8.0 官方镜像
env:
MYSQL_ROOT_PASSWORD: root # 测试环境密码(仅用于 CI)
MYSQL_DATABASE: test_db # 自动创建的测试数据库
ports:
- 3306:3306 # 暴露端口供测试连接
# 健康检查:确保 MySQL 就绪后再执行后续步骤
options: >-
--health-cmd="mysqladmin ping" # 用 mysqladmin ping 检测
--health-interval=10s # 每 10 秒检查一次
--health-timeout=5s # 超时时间
--health-retries=3 # 重试 3 次后判定失败
steps:
# 拉取代码(checkout@v4 是 GitHub 官方 Action)
- uses: actions/checkout@v4
# 安装 PHP 8.2 及所需扩展
- name: Setup PHP
uses: shivammathur/setup-php@v2 # 第三方 Action,自动安装 PHP
with:
php-version: '8.2' # PHP 版本
extensions: pdo_mysql, gd, redis # 安装的扩展
coverage: xdebug # 代码覆盖率工具
# 安装 Composer 依赖(--no-progress 隐藏进度条,--prefer-dist 下载压缩包更快)
- name: Install Dependencies
run: composer install --no-progress --prefer-dist
# 准备运行环境
- name: Prepare Environment
run: |
cp .env.example .env # 复制环境配置模板
php think db:migrate # 执行数据库迁移
# 代码风格检查(PSR-12 标准)
- name: Code Style Check
run: vendor/bin/phpcs --standard=PSR12 app/
# 静态分析(level=5 为严格模式,可发现潜在 bug)
- name: Static Analysis
run: vendor/bin/phpstan analyse app/ --level=5
# 运行单元测试(--coverage-text 输出文本格式覆盖率报告)
- name: Run Tests
run: php think test --coverage-text
# 上传覆盖率报告到 Codecov(免费的覆盖率追踪平台)
- name: Upload Coverage
uses: codecov/codecov-action@v3
with:
file: ./coverage.xml # 覆盖率报告文件
```
### 前端 CI 配置
```yaml
# =============================================================================
# .github/workflows/frontend-ci.yml — 前端持续集成
# =============================================================================
# 触发条件:仅当 ui/ 目录下的文件变更时触发(避免后端改动触发前端 CI)
# 流程:Lint → 类型检查 → 单元测试 → 构建
# =============================================================================
name: Frontend CI
on:
push:
branches: [main, develop]
paths:
- 'ui/**' # 仅 ui/ 目录变更时触发
pull_request:
branches: [main]
paths:
- 'ui/**'
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# 安装 Node.js 18 并配置 pnpm 缓存
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18' # Node.js 版本
cache: 'pnpm' # 启用 pnpm 缓存(加速依赖安装)
cache-dependency-path: ui/pnpm-lock.yaml # 缓存依赖的 lockfile 路径
# 全局安装 pnpm 包管理器
- name: Install pnpm
run: npm install -g pnpm
# 安装前端依赖(--frozen-lockfile 确保版本与 lockfile 一致)
- name: Install Dependencies
working-directory: ui # 在 ui/ 目录下执行
run: pnpm install --frozen-lockfile
# ESLint 代码风格检查
- name: Lint
working-directory: ui
run: pnpm lint:eslint
# TypeScript 类型检查(发现类型错误)
- name: Type Check
working-directory: ui
run: pnpm type:check
# 运行单元测试(Vitest)
- name: Run Tests
working-directory: ui
run: pnpm test
# 生产环境构建(验证构建是否成功)
- name: Build
working-directory: ui
run: pnpm build
```
### 自动部署配置
```yaml
# =============================================================================
# .github/workflows/deploy.yml — 自动部署
# =============================================================================
# 触发条件:push 到 main 分支,或打 v* 标签
# 流程:构建 Docker 镜像 → 推送到镜像仓库 → SSH 部署到服务器
# =============================================================================
name: Deploy
on:
push:
branches: [main]
tags:
- 'v*' # 匹配 v1.0.0、v2.1.3 等标签
jobs:
deploy:
runs-on: ubuntu-latest
needs: [test] # 依赖 test job 通过后才执行
if: github.ref == 'refs/heads/main' # 仅 main 分支触发部署
steps:
- uses: actions/checkout@v4
# 构建 Docker 镜像(用 git commit SHA 作为版本标签)
- name: Build Docker Image
run: |
docker build -t myapp:${{ github.sha }} . # 用 commit SHA 标记
docker tag myapp:${{ github.sha }} myapp:latest # 同时打 latest 标签
# 推送镜像到 Docker Hub(secrets 在 GitHub 仓库设置中配置)
- name: Push to Registry
run: |
echo ${{ secrets.DOCKER_PASSWORD }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin
docker push myapp:${{ github.sha }} # 推送版本标签
docker push myapp:latest # 推送 latest 标签
# 通过 SSH 连接服务器执行部署命令
- name: Deploy to Server
uses: appleboy/ssh-action@v1 # 第三方 SSH Action
with:
host: ${{ secrets.SERVER_HOST }} # 服务器地址
username: ${{ secrets.SERVER_USER }} # SSH 用户名
key: ${{ secrets.SSH_KEY }} # SSH 私钥
script: |
cd /opt/myapp # 进入项目目录
docker-compose pull # 拉取最新镜像
docker-compose up -d # 重建并启动容器
php think db:migrate # 执行数据库迁移
```
## GitLab CI
```yaml
# =============================================================================
# .gitlab-ci.yml — GitLab CI/CD 配置
# =============================================================================
# 阶段:test → build → deploy
# 缓存:vendor/ 和 node_modules/ 按分支缓存,加速后续构建
# =============================================================================
stages:
- test # 测试阶段
- build # 构建阶段
- deploy # 部署阶段
# 全局变量(所有 job 共享)
variables:
MYSQL_ROOT_PASSWORD: root # 测试数据库密码
MYSQL_DATABASE: test_db # 测试数据库名
# -----------------------------------------------------------------------------
# 后端测试
# -----------------------------------------------------------------------------
backend:test:
stage: test
image: php:8.2-cli # PHP 8.2 CLI 镜像
services:
- mysql:8.0 # MySQL 服务容器
script:
# 安装系统依赖(PHP 扩展编译需要)
- apt-get update && apt-get install -y libpq-dev libzip-dev
# 安装 PHP 扩展
- docker-php-ext-install pdo_mysql zip
# 安装 Composer 依赖
- composer install --no-progress
# 准备环境并执行测试
- cp .env.example .env
- php think db:migrate # 数据库迁移
- php think test # 运行测试
cache:
key: ${CI_COMMIT_REF_SLUG} # 按分支名缓存
paths:
- vendor/ # 缓存 Composer 依赖
# -----------------------------------------------------------------------------
# 前端测试
# -----------------------------------------------------------------------------
frontend:test:
stage: test
image: node:18 # Node.js 18 镜像
script:
- cd ui
- npm install -g pnpm # 全局安装 pnpm
- pnpm install --frozen-lockfile # 安装依赖
- pnpm lint:eslint # 代码风格检查
- pnpm test # 单元测试
- pnpm build # 生产构建
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- ui/node_modules/ # 缓存前端依赖
# -----------------------------------------------------------------------------
# 生产部署(仅 main 分支)
# -----------------------------------------------------------------------------
deploy:production:
stage: deploy
only:
- main # 仅 main 分支触发
script:
- docker build -t myapp:$CI_COMMIT_SHA . # 构建镜像
- docker push myapp:$CI_COMMIT_SHA # 推送到仓库
# SSH 到服务器执行部署
- ssh $SERVER_USER@$SERVER_HOST "cd /opt/myapp && docker-compose pull && docker-compose up -d"
environment:
name: production
url: https://api.example.com
```
## 部署策略
### 蓝绿部署
```text
当前版本(蓝) → 新版本(绿)
│ │
▼ ▼
Nginx 切换流量 ← 验证通过
```
### 滚动更新
```bash
# Docker Swarm 滚动更新
# --update-parallelism 1 → 每次只更新 1 个容器实例
# --update-delay 30s → 每批更新间隔 30 秒(观察健康状态)
# --image myapp:v2.0 → 新版本镜像
# myapp_web → 服务名称
docker service update \
--update-parallelism 1 \
--update-delay 30s \
--image myapp:v2.0 \
myapp_web
```
## 通知集成
### 部署通知(钉钉/飞书)
```yaml
# GitHub Actions 部署成功通知(发送到钉钉机器人)
- name: Notify on Success
if: success() # 仅在部署成功时执行
run: |
# curl 发送 POST 请求到钉钉 Webhook
# -H → 设置请求头为 JSON 格式
# -d → 发送 JSON 消息体(Markdown 格式)
curl -X POST "${{ secrets.DINGTALK_WEBHOOK }}" \
-H 'Content-Type: application/json' \
-d '{
"msgtype": "markdown",
"markdown": {
"title": "部署成功",
"text": "## ✅ 部署成功\n- **项目**: myapp\n- **分支**: ${{ github.ref_name }}\n- **提交**: ${{ github.sha }}\n- **时间**: $(date)"
}
}'
```
## 相关文档
- [Docker 生产部署](/zh/deploy/docker.html)
- [后端部署](/zh/deploy/backend.html)
- [前端部署](/zh/deploy/frontend.html)