# CI/CD自动化流水线
## 🎯 学习目标
通过本章学习,您将能够:
- 理解现代CI/CD流水线的设计理念和最佳实践
- 掌握GitHub Actions、GitLab CI等自动化工具
- 学会为Chat-Room项目设计完整的CI/CD流程
- 实现代码质量检查和自动化部署机制
## 🔄 CI/CD流水线架构
### CI/CD流程图
```mermaid
graph LR
subgraph "持续集成 (CI)"
A[代码提交
Code Commit] --> B[代码检查
Code Review]
B --> C[自动构建
Build]
C --> D[单元测试
Unit Tests]
D --> E[集成测试
Integration Tests]
E --> F[代码质量检查
Quality Check]
F --> G[安全扫描
Security Scan]
end
subgraph "持续部署 (CD)"
G --> H[构建镜像
Build Image]
H --> I[推送镜像
Push Image]
I --> J[部署到测试环境
Deploy to Test]
J --> K[自动化测试
Automated Tests]
K --> L[部署到生产环境
Deploy to Prod]
L --> M[监控和告警
Monitor & Alert]
end
style A fill:#e8f5e8
style M fill:#f8d7da
```
### 流水线阶段详解
```mermaid
graph TB
subgraph "代码阶段"
A1[源码管理
Source Control] --> A2[分支策略
Branch Strategy]
A2 --> A3[代码审查
Code Review]
A3 --> A4[合并请求
Merge Request]
end
subgraph "构建阶段"
B1[依赖安装
Install Dependencies] --> B2[代码编译
Compile Code]
B2 --> B3[静态分析
Static Analysis]
B3 --> B4[构建产物
Build Artifacts]
end
subgraph "测试阶段"
C1[单元测试
Unit Tests] --> C2[集成测试
Integration Tests]
C2 --> C3[端到端测试
E2E Tests]
C3 --> C4[性能测试
Performance Tests]
end
subgraph "部署阶段"
D1[镜像构建
Image Build] --> D2[镜像扫描
Image Scan]
D2 --> D3[环境部署
Environment Deploy]
D3 --> D4[健康检查
Health Check]
end
A4 --> B1
B4 --> C1
C4 --> D1
style A1 fill:#e8f5e8
style D4 fill:#f8d7da
```
## 🔧 CI/CD实现
### GitHub Actions配置
```yaml
# .github/workflows/ci-cd.yml - GitHub Actions CI/CD流水线
name: Chat-Room CI/CD Pipeline
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
release:
types: [ published ]
env:
PYTHON_VERSION: '3.11'
NODE_VERSION: '18'
DOCKER_REGISTRY: ghcr.io
IMAGE_NAME: chatroom
jobs:
# 代码质量检查
code-quality:
runs-on: ubuntu-latest
steps:
- name: Checkout代码
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: 设置Python环境
uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: 安装依赖
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install -r requirements-dev.txt
- name: 代码格式检查
run: |
black --check .
isort --check-only .
flake8 .
- name: 类型检查
run: mypy .
- name: 安全扫描
run: |
bandit -r . -f json -o bandit-report.json
safety check --json --output safety-report.json
- name: 上传安全报告
uses: actions/upload-artifact@v3
if: always()
with:
name: security-reports
path: |
bandit-report.json
safety-report.json
# 单元测试
unit-tests:
runs-on: ubuntu-latest
needs: code-quality
strategy:
matrix:
python-version: ['3.10', '3.11', '3.12']
steps:
- name: Checkout代码
uses: actions/checkout@v4
- name: 设置Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: 安装依赖
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install -r requirements-dev.txt
- name: 运行单元测试
run: |
pytest tests/unit/ \
--cov=. \
--cov-report=xml \
--cov-report=html \
--junitxml=junit.xml \
-v
- name: 上传覆盖率报告
uses: codecov/codecov-action@v3
with:
file: ./coverage.xml
flags: unittests
name: codecov-umbrella
- name: 上传测试结果
uses: actions/upload-artifact@v3
if: always()
with:
name: test-results-${{ matrix.python-version }}
path: |
junit.xml
htmlcov/
# 集成测试
integration-tests:
runs-on: ubuntu-latest
needs: unit-tests
services:
postgres:
image: postgres:15
env:
POSTGRES_PASSWORD: postgres
POSTGRES_DB: chatroom_test
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
redis:
image: redis:7
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 6379:6379
steps:
- name: Checkout代码
uses: actions/checkout@v4
- name: 设置Python环境
uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: 安装依赖
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install -r requirements-dev.txt
- name: 运行集成测试
env:
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/chatroom_test
REDIS_URL: redis://localhost:6379/0
run: |
pytest tests/integration/ \
--cov=. \
--cov-append \
--cov-report=xml \
--junitxml=integration-junit.xml \
-v
- name: 上传集成测试结果
uses: actions/upload-artifact@v3
if: always()
with:
name: integration-test-results
path: integration-junit.xml
# Docker镜像构建
build-image:
runs-on: ubuntu-latest
needs: [unit-tests, integration-tests]
if: github.event_name != 'pull_request'
outputs:
image-tag: ${{ steps.meta.outputs.tags }}
image-digest: ${{ steps.build.outputs.digest }}
steps:
- name: Checkout代码
uses: actions/checkout@v4
- name: 设置Docker Buildx
uses: docker/setup-buildx-action@v3
- name: 登录Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.DOCKER_REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: 提取元数据
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.DOCKER_REGISTRY }}/${{ github.repository }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha,prefix={{branch}}-
- name: 构建并推送Docker镜像
id: build
uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: 镜像安全扫描
uses: aquasecurity/trivy-action@master
with:
image-ref: ${{ steps.meta.outputs.tags }}
format: 'sarif'
output: 'trivy-results.sarif'
- name: 上传安全扫描结果
uses: github/codeql-action/upload-sarif@v2
if: always()
with:
sarif_file: 'trivy-results.sarif'
# 部署到测试环境
deploy-staging:
runs-on: ubuntu-latest
needs: build-image
if: github.ref == 'refs/heads/develop'
environment:
name: staging
url: https://staging.chatroom.example.com
steps:
- name: Checkout代码
uses: actions/checkout@v4
- name: 设置kubectl
uses: azure/setup-kubectl@v3
with:
version: 'latest'
- name: 配置Kubernetes上下文
run: |
echo "${{ secrets.KUBE_CONFIG_STAGING }}" | base64 -d > kubeconfig
export KUBECONFIG=kubeconfig
- name: 部署到测试环境
run: |
export KUBECONFIG=kubeconfig
kubectl set image deployment/chatroom-server \
chatroom-server=${{ needs.build-image.outputs.image-tag }} \
-n chatroom-staging
kubectl rollout status deployment/chatroom-server -n chatroom-staging
- name: 运行端到端测试
run: |
npm install
npm run test:e2e -- --baseUrl=https://staging.chatroom.example.com
# 部署到生产环境
deploy-production:
runs-on: ubuntu-latest
needs: [build-image, deploy-staging]
if: github.event_name == 'release'
environment:
name: production
url: https://chatroom.example.com
steps:
- name: Checkout代码
uses: actions/checkout@v4
- name: 设置kubectl
uses: azure/setup-kubectl@v3
with:
version: 'latest'
- name: 配置Kubernetes上下文
run: |
echo "${{ secrets.KUBE_CONFIG_PROD }}" | base64 -d > kubeconfig
export KUBECONFIG=kubeconfig
- name: 蓝绿部署到生产环境
run: |
export KUBECONFIG=kubeconfig
# 创建新的部署版本
kubectl patch deployment chatroom-server \
-p '{"spec":{"template":{"spec":{"containers":[{"name":"chatroom-server","image":"${{ needs.build-image.outputs.image-tag }}"}]}}}}' \
-n chatroom-production
# 等待部署完成
kubectl rollout status deployment/chatroom-server -n chatroom-production
# 健康检查
kubectl wait --for=condition=available --timeout=300s deployment/chatroom-server -n chatroom-production
- name: 生产环境烟雾测试
run: |
curl -f https://chatroom.example.com/health || exit 1
curl -f https://chatroom.example.com/api/status || exit 1
- name: 通知部署成功
uses: 8398a7/action-slack@v3
with:
status: success
text: '🚀 Chat-Room已成功部署到生产环境!'
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}
# 性能测试
performance-tests:
runs-on: ubuntu-latest
needs: deploy-staging
if: github.ref == 'refs/heads/develop'
steps:
- name: Checkout代码
uses: actions/checkout@v4
- name: 设置Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: 安装K6
run: |
sudo gpg -k
sudo gpg --no-default-keyring --keyring /usr/share/keyrings/k6-archive-keyring.gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys C5AD17C747E3415A3642D57D77C6C491D6AC1D69
echo "deb [signed-by=/usr/share/keyrings/k6-archive-keyring.gpg] https://dl.k6.io/deb stable main" | sudo tee /etc/apt/sources.list.d/k6.list
sudo apt-get update
sudo apt-get install k6
- name: 运行性能测试
run: |
k6 run tests/performance/load-test.js \
--env BASE_URL=https://staging.chatroom.example.com \
--out json=performance-results.json
- name: 上传性能测试结果
uses: actions/upload-artifact@v3
with:
name: performance-results
path: performance-results.json
- name: 分析性能结果
run: |
python scripts/analyze-performance.py performance-results.json
```
### GitLab CI配置
```yaml
# .gitlab-ci.yml - GitLab CI/CD流水线
stages:
- validate
- test
- build
- deploy-staging
- deploy-production
variables:
PYTHON_VERSION: "3.11"
DOCKER_REGISTRY: $CI_REGISTRY
IMAGE_NAME: $CI_REGISTRY_IMAGE
POSTGRES_DB: chatroom_test
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
# 代码质量检查
code-quality:
stage: validate
image: python:$PYTHON_VERSION
before_script:
- pip install -r requirements-dev.txt
script:
- black --check .
- isort --check-only .
- flake8 .
- mypy .
- bandit -r . -f json -o bandit-report.json
artifacts:
reports:
codequality: bandit-report.json
expire_in: 1 week
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == "main"
- if: $CI_COMMIT_BRANCH == "develop"
# 单元测试
unit-tests:
stage: test
image: python:$PYTHON_VERSION
services:
- postgres:15
- redis:7
variables:
DATABASE_URL: postgresql://postgres:postgres@postgres:5432/chatroom_test
REDIS_URL: redis://redis:6379/0
before_script:
- pip install -r requirements.txt
- pip install -r requirements-dev.txt
script:
- pytest tests/unit/ --cov=. --cov-report=xml --cov-report=html --junitxml=junit.xml
coverage: '/TOTAL.+ ([0-9]{1,3}%)/'
artifacts:
reports:
junit: junit.xml
coverage_report:
coverage_format: cobertura
path: coverage.xml
paths:
- htmlcov/
expire_in: 1 week
# 集成测试
integration-tests:
stage: test
image: python:$PYTHON_VERSION
services:
- postgres:15
- redis:7
variables:
DATABASE_URL: postgresql://postgres:postgres@postgres:5432/chatroom_test
REDIS_URL: redis://redis:6379/0
before_script:
- pip install -r requirements.txt
- pip install -r requirements-dev.txt
script:
- pytest tests/integration/ --junitxml=integration-junit.xml
artifacts:
reports:
junit: integration-junit.xml
expire_in: 1 week
# Docker镜像构建
build-image:
stage: build
image: docker:latest
services:
- docker:dind
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
script:
- docker build -t $IMAGE_NAME:$CI_COMMIT_SHA .
- docker build -t $IMAGE_NAME:latest .
- docker push $IMAGE_NAME:$CI_COMMIT_SHA
- docker push $IMAGE_NAME:latest
rules:
- if: $CI_COMMIT_BRANCH == "main"
- if: $CI_COMMIT_BRANCH == "develop"
# 部署到测试环境
deploy-staging:
stage: deploy-staging
image: bitnami/kubectl:latest
environment:
name: staging
url: https://staging.chatroom.example.com
before_script:
- echo $KUBE_CONFIG_STAGING | base64 -d > kubeconfig
- export KUBECONFIG=kubeconfig
script:
- kubectl set image deployment/chatroom-server chatroom-server=$IMAGE_NAME:$CI_COMMIT_SHA -n chatroom-staging
- kubectl rollout status deployment/chatroom-server -n chatroom-staging
rules:
- if: $CI_COMMIT_BRANCH == "develop"
# 部署到生产环境
deploy-production:
stage: deploy-production
image: bitnami/kubectl:latest
environment:
name: production
url: https://chatroom.example.com
before_script:
- echo $KUBE_CONFIG_PROD | base64 -d > kubeconfig
- export KUBECONFIG=kubeconfig
script:
- kubectl set image deployment/chatroom-server chatroom-server=$IMAGE_NAME:$CI_COMMIT_SHA -n chatroom-production
- kubectl rollout status deployment/chatroom-server -n chatroom-production
- kubectl wait --for=condition=available --timeout=300s deployment/chatroom-server -n chatroom-production
when: manual
rules:
- if: $CI_COMMIT_BRANCH == "main"
```
## 🎯 实践练习
### 练习1:多分支部署策略
```python
class BranchDeploymentStrategy:
"""
多分支部署策略练习
要求:
1. 实现feature分支的临时环境部署
2. 支持hotfix分支的快速部署
3. 实现环境的自动清理机制
4. 添加部署通知和状态跟踪
"""
def deploy_feature_branch(self, branch_name: str) -> Dict[str, Any]:
"""部署feature分支"""
# TODO: 实现feature分支部署
pass
def cleanup_temporary_environment(self, env_name: str) -> bool:
"""清理临时环境"""
# TODO: 实现环境清理
pass
```
### 练习2:部署质量门禁
```python
class DeploymentQualityGates:
"""
部署质量门禁练习
要求:
1. 实现代码覆盖率门禁
2. 添加安全扫描门禁
3. 实现性能测试门禁
4. 支持手动审批流程
"""
def check_coverage_gate(self, coverage_percentage: float) -> bool:
"""检查覆盖率门禁"""
# TODO: 实现覆盖率门禁
pass
def security_scan_gate(self, scan_results: Dict[str, Any]) -> bool:
"""安全扫描门禁"""
# TODO: 实现安全门禁
pass
```
## ✅ 学习检查
完成本章学习后,请确认您能够:
- [ ] 理解CI/CD流水线的设计原理和最佳实践
- [ ] 配置GitHub Actions和GitLab CI流水线
- [ ] 实现自动化测试和代码质量检查
- [ ] 设计多环境部署和发布策略
- [ ] 配置安全扫描和质量门禁
- [ ] 完成实践练习
## 📚 下一步
CI/CD自动化掌握后,请继续学习:
- [运维监控](./monitoring-operations.md)
---
**恭喜!您已经掌握了现代CI/CD自动化技术!** 🔄