跳转至

版本控制与 CI/CD

概述

现代软件开发离不开版本控制和持续集成/持续部署(CI/CD)。本文涵盖 Git 工作流、GitHub Actions、Docker 容器化和 Kubernetes 基础。


1. Git 版本控制

1.1 Git 核心概念

工作区 (Working Directory)
    │ git add
    ▼
暂存区 (Staging Area / Index)
    │ git commit
    ▼
本地仓库 (Local Repository)
    │ git push
    ▼
远程仓库 (Remote Repository)

1.2 分支模型

Git Flow

gitGraph
    commit id: "init"
    branch develop
    checkout develop
    commit id: "feat-start"
    branch feature/login
    checkout feature/login
    commit id: "login-impl"
    commit id: "login-test"
    checkout develop
    merge feature/login id: "merge-login"
    branch release/1.0
    checkout release/1.0
    commit id: "bugfix"
    checkout main
    merge release/1.0 id: "v1.0" tag: "v1.0"
    checkout develop
    merge release/1.0 id: "sync"
分支 用途 生命周期
main 生产环境代码 永久
develop 开发集成 永久
feature/* 新功能开发 临时
release/* 发布准备 临时
hotfix/* 紧急修复 临时

Trunk-Based Development

main ──●──●──●──●──●──●──●──●──
       │     │        │
       └─●─┘ └──●──┘  └─●─┘
       短命分支(< 1-2 天)
  • 主干始终保持可部署状态
  • 分支生命周期极短(几小时到一两天)
  • 依赖特性开关(Feature Flags)隐藏未完成功能
  • 适合 CI/CD 成熟的团队

1.3 Merge vs Rebase

Merge:创建合并提交,保留完整历史

git checkout main
git merge feature/login
# 创建一个合并提交

Rebase:将分支的提交"移植"到目标分支上

git checkout feature/login
git rebase main
# 将 feature 的提交重放到 main 之上
git checkout main
git merge feature/login  # fast-forward
方式 历史 优势 劣势
Merge 非线性 保留真实历史 历史混乱
Rebase 线性 历史清晰 改写历史,协作需谨慎

1.4 Cherry-pick

将特定提交应用到其他分支:

git checkout main
git cherry-pick abc1234     # 将某个提交应用到 main
git cherry-pick abc..def    # 应用一个范围

使用场景:将 hotfix 从 main 同步到 develop,或选择性地移植功能。


2. GitHub Actions

2.1 Workflow 基本结构

# .github/workflows/ci.yml
name: CI Pipeline

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

env:
  PYTHON_VERSION: '3.11'

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ['3.10', '3.11', '3.12']

    steps:
      - uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python-version }}

      - name: Cache dependencies
        uses: actions/cache@v4
        with:
          path: ~/.cache/pip
          key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }}

      - name: Install dependencies
        run: pip install -r requirements.txt

      - name: Run tests
        run: pytest --cov=src tests/

      - name: Upload coverage
        uses: codecov/codecov-action@v4

  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: pip install ruff
      - run: ruff check src/

  deploy:
    needs: [test, lint]
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    steps:
      - uses: actions/checkout@v4
      - name: Deploy to production
        run: ./deploy.sh

2.2 常用 Actions

Action 用途
actions/checkout 检出代码
actions/setup-python 配置 Python
actions/setup-node 配置 Node.js
actions/cache 缓存依赖
docker/build-push-action 构建推送 Docker 镜像
peaceiris/actions-gh-pages 部署到 GitHub Pages

3. Docker

3.1 核心概念

Dockerfile → docker build → Image → docker run → Container
  (配方)                     (镜像)                 (运行实例)
概念 类比 说明
Image 只读模板,包含应用和依赖
Container 实例 Image 的运行实例,可读写
Dockerfile 蓝图 定义如何构建 Image
Registry 仓库 存储和分发 Image(如 Docker Hub)

3.2 Dockerfile 最佳实践

# 多阶段构建
FROM python:3.11-slim AS builder

WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir --user -r requirements.txt

FROM python:3.11-slim AS runtime

# 非 root 用户
RUN useradd --create-home appuser
USER appuser

WORKDIR /app
COPY --from=builder /root/.local /home/appuser/.local
COPY . .

ENV PATH=/home/appuser/.local/bin:$PATH

EXPOSE 8000
HEALTHCHECK CMD curl -f http://localhost:8000/health || exit 1

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

优化技巧

  • 利用构建缓存:先 COPY 依赖文件,再 COPY 源码
  • 多阶段构建减小镜像体积
  • 使用 .dockerignore 排除不需要的文件
  • 选择 slimalpine 基础镜像

3.3 Docker Compose

# docker-compose.yml
version: '3.8'

services:
  web:
    build: .
    ports:
      - "8000:8000"
    environment:
      - DATABASE_URL=postgresql://user:pass@db:5432/mydb
      - REDIS_URL=redis://redis:6379
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_started

  db:
    image: postgres:16
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
      POSTGRES_DB: mydb
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user"]
      interval: 5s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7-alpine

volumes:
  pgdata:

4. Kubernetes 基础

4.1 核心概念

概念 说明
Pod 最小部署单元,包含一个或多个容器
Service 为 Pod 提供稳定的网络访问
Deployment 管理 Pod 的副本、更新、回滚
ConfigMap/Secret 配置和敏感信息管理
Namespace 资源隔离的虚拟集群
Ingress HTTP/HTTPS 外部访问入口

4.2 基本资源定义

# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
  labels:
    app: web
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
        - name: web
          image: myapp:v1.0
          ports:
            - containerPort: 8000
          resources:
            requests:
              cpu: 100m
              memory: 128Mi
            limits:
              cpu: 500m
              memory: 512Mi
          livenessProbe:
            httpGet:
              path: /health
              port: 8000
            initialDelaySeconds: 10
            periodSeconds: 30
---
apiVersion: v1
kind: Service
metadata:
  name: web-service
spec:
  selector:
    app: web
  ports:
    - port: 80
      targetPort: 8000
  type: ClusterIP

4.3 滚动更新

# 更新镜像版本
kubectl set image deployment/web-app web=myapp:v2.0

# 查看更新状态
kubectl rollout status deployment/web-app

# 回滚
kubectl rollout undo deployment/web-app

5. CI/CD 完整流水线

graph LR
    A[代码提交] --> B[CI: 构建]
    B --> C[CI: 测试]
    C --> D[CI: 代码质量]
    D --> E[CD: 构建镜像]
    E --> F[CD: 推送 Registry]
    F --> G{环境}
    G -->|staging| H[部署 Staging]
    H --> I[集成测试]
    I --> J[人工审批]
    J --> K[部署 Production]
    G -->|直接| K

    style A fill:#f9f
    style K fill:#bfb

5.1 完整示例:GitHub Actions + Docker + K8s

name: Deploy Pipeline

on:
  push:
    branches: [main]

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Run tests
        run: |
          pip install -r requirements.txt
          pytest tests/

      - name: Build Docker image
        run: |
          docker build -t myregistry/myapp:${{ github.sha }} .

      - name: Push to registry
        run: |
          echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin
          docker push myregistry/myapp:${{ github.sha }}

      - name: Deploy to Kubernetes
        uses: azure/k8s-deploy@v5
        with:
          manifests: k8s/
          images: myregistry/myapp:${{ github.sha }}

6. 最佳实践

Git 规范

  • 提交信息:使用 Conventional Commits(feat:, fix:, docs:, refactor:
  • 分支保护:main 分支要求 PR + Code Review + CI 通过
  • 签名提交:GPG 签名重要提交

CI/CD 原则

  • 快速反馈:测试应在 10 分钟内完成
  • 不可变制品:同一个构建产物部署到所有环境
  • 基础设施即代码:所有配置版本化管理
  • 渐进式发布:金丝雀发布、蓝绿部署

与其他主题的关系

  • 参见 测试与质量保障,理解自动化验证如何成为持续集成的核心输入
  • 参见 全栈开发,理解前后端协作时如何管理分支、构建和部署
  • 参见 云服务,理解镜像仓库、容器部署和云环境交付链路
  • 参见 软件工程概述,理解版本控制与交付流程在软件生命周期中的位置

参考文献

  • "Pro Git" - Scott Chacon & Ben Straub
  • GitHub Actions 官方文档
  • Docker 官方文档
  • Kubernetes 官方文档

评论 #