部署流水线设计原则
一个可靠的部署工作流需要解决以下核心问题:
不可变镜像(Immutable Images)
每次构建生成唯一标识的镜像(如 commit SHA 作为 tag),部署时始终指定具体版本而非 latest 标签。latest 标签在多环境部署中会导致版本不确定性。
环境保护(Environment Protection)
生产部署需要手动审批(GitHub Environment protection rules),staging 自动部署,production 需要相关人员点击批准。防止意外将 bug 直接推送到生产环境。
部署验证(Deployment Verification)
部署后立即运行冒烟测试(Smoke Tests)验证服务可用性,失败时自动触发回滚。kubectl rollout status / aws ecs wait services-stable 是等待部署完成的标准方式。
回滚策略(Rollback Strategy)
deployment 失败时 if: failure() 触发自动回滚;保留历史镜像版本(至少 3-5 个)确保回滚可用;记录部署日志方便事后审查。
Docker 镜像构建与推送
推送到 GitHub Container Registry(GHCR)
name: Build and Push Docker Image
on:
push:
branches: [main]
tags: ['v*']
jobs:
docker:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write # 允许推送到 GHCR
steps:
- uses: actions/checkout@v4
# 提取 Docker 元数据(标签、标记)
- name: Docker 元数据
id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/${{ github.repository }}
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha,prefix=,format=short
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }}
# 设置 QEMU(多架构构建支持)
- uses: docker/setup-qemu-action@v3
# 设置 Buildx(高级构建功能)
- uses: docker/setup-buildx-action@v3
# 登录 GHCR
- name: 登录 GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# 构建并推送(多架构)
- name: 构建并推送
uses: docker/build-push-action@v6
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
部署到 AWS
部署到 AWS ECS(Elastic Container Service)
jobs:
deploy-ecs:
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v4
# 配置 AWS 凭证(使用 OIDC,无需长期密钥 - 见第9章)
- name: 配置 AWS 凭证
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_DEPLOY_ROLE_ARN }}
aws-region: us-east-1
# 登录 ECR
- name: 登录 Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v2
# 构建并推送到 ECR
- name: 推送到 ECR
id: build-image
env:
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
IMAGE_TAG: ${{ github.sha }}
run: |
docker build -t $ECR_REGISTRY/my-app:$IMAGE_TAG .
docker push $ECR_REGISTRY/my-app:$IMAGE_TAG
echo "image=$ECR_REGISTRY/my-app:$IMAGE_TAG" >> $GITHUB_OUTPUT
# 更新 ECS Task Definition
- name: 更新 ECS Task Definition
id: task-def
uses: aws-actions/amazon-ecs-render-task-definition@v1
with:
task-definition: task-definition.json
container-name: my-app
image: ${{ steps.build-image.outputs.image }}
# 部署到 ECS Service
- name: 部署到 ECS
uses: aws-actions/amazon-ecs-deploy-task-definition@v1
with:
task-definition: ${{ steps.task-def.outputs.task-definition }}
service: my-app-service
cluster: my-cluster
wait-for-service-stability: true
部署到 Google Cloud Run
jobs:
deploy-cloud-run:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: 配置 GCP 认证
uses: google-github-actions/auth@v2
with:
workload_identity_provider: ${{ secrets.GCP_WORKLOAD_IDENTITY }}
service_account: ${{ secrets.GCP_SERVICE_ACCOUNT }}
- name: 配置 gcloud CLI
uses: google-github-actions/setup-gcloud@v2
- name: 构建并推送到 Artifact Registry
run: |
gcloud builds submit \
--tag us-central1-docker.pkg.dev/${{ secrets.GCP_PROJECT }}/my-repo/my-app:${{ github.sha }}
- name: 部署到 Cloud Run
run: |
gcloud run deploy my-app \
--image us-central1-docker.pkg.dev/${{ secrets.GCP_PROJECT }}/my-repo/my-app:${{ github.sha }} \
--region us-central1 \
--platform managed \
--allow-unauthenticated \
--memory 512Mi \
--cpu 1
Kubernetes 滚动更新
jobs:
deploy-k8s:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: 构建并推送镜像
run: |
docker build -t registry.example.com/my-app:${{ github.sha }} .
docker push registry.example.com/my-app:${{ github.sha }}
# 配置 kubectl
- name: 配置 kubeconfig
run: |
mkdir -p ~/.kube
echo "${{ secrets.KUBE_CONFIG }}" | base64 -d > ~/.kube/config
# 更新镜像触发滚动更新
- name: 更新 Kubernetes Deployment
run: |
kubectl set image deployment/my-app \
my-app=registry.example.com/my-app:${{ github.sha }} \
-n production
# 等待滚动更新完成
kubectl rollout status deployment/my-app -n production --timeout=5m
# 部署失败时自动回滚
- name: 回滚(如果失败)
if: failure()
run: |
kubectl rollout undo deployment/my-app -n production
echo "⚠️ 部署失败,已自动回滚到上一个版本"
静态网站部署(GitHub Pages / Vercel)
name: Deploy to GitHub Pages
on:
push:
branches: [main]
permissions:
contents: read
pages: write # 允许部署到 Pages
id-token: write # OIDC 认证
# 只允许一个 deployment 同时运行
concurrency:
group: pages
cancel-in-progress: false
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci && npm run build
- name: 上传 Pages 产物
uses: actions/upload-pages-artifact@v3
with:
path: dist/ # 构建输出目录
deploy:
needs: build
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: 部署到 GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
蓝绿部署 vs 滚动更新 vs 金丝雀发布
滚动更新(Rolling Update):逐步替换旧版 Pod,资源占用少,但短暂存在新旧版本共存。蓝绿部署(Blue-Green):同时运行两套环境,切换流量实现零停机,需要双倍资源。金丝雀发布(Canary):先将 5-10% 流量导到新版本,验证无问题后再全量切换,降低风险。生产环境推荐使用 ArgoCD 或 Flux 等 GitOps 工具实现更可靠的 Kubernetes 部署管理。
本章小结
本章核心要点
- 不可变镜像:用 commit SHA 作为镜像 tag,确保每次部署的版本可追溯;docker/metadata-action 自动生成符合语义化版本规范的标签。
- 多架构构建:docker/setup-buildx-action + platforms: linux/amd64,linux/arm64 构建支持 x86 和 ARM 的镜像;cache-from/cache-to: type=gha 复用 GitHub Actions 缓存层加速构建。
- 云平台部署:AWS 推荐 ECS(托管容器)+ OIDC 无密钥认证;GCP 推荐 Cloud Run(Serverless 容器);K8s 用 kubectl set image + rollout status 实现滚动更新。
- 自动回滚:部署步骤后加 if: failure() + 回滚命令,确保失败时自动恢复;kubectl rollout undo / aws ecs update-service 是常用的回滚命令。
- Environment 保护:staging 自动部署,production 配置 Required Reviewers 手动审批;Environment URL 字段让每次部署都能点击查看结果。