🔄 第22课:CI/CD流水线

📌 课程阶段:实战项目(2/5)|预计时间:60分钟|难度:⭐⭐⭐⭐☆

一、K8s CI/CD架构

在K8s上构建CI/CD流水线,实现代码提交→构建镜像→测试→部署的全自动化。核心原则:一切皆代码(GitOps)。

┌─────────── CI/CD流水线 ──────────────┐
│                                        │
│  Developer                             │
│     │ git push                         │
│  ┌──▼──────────────────────────────┐   │
│  │  CI (Continuous Integration)    │   │
│  │  1. 代码检出                     │   │
│  │  2. 单元测试                     │   │
│  │  3. 代码扫描                     │   │
│  │  4. 构建Docker镜像               │   │
│  │  5. 推送镜像仓库                  │   │
│  │  6. 更新Helm values              │   │
│  └──┬─────────────────────────────┘   │
│     │                                   │
│  ┌──▼──────────────────────────────┐   │
│  │  CD (Continuous Delivery)       │   │
│  │  方式A: ArgoCD (GitOps)         │   │
│  │  方式B: Flux (GitOps)           │   │
│  │  方式C: Jenkins/Pipeline        │   │
│  │  → 自动部署到K8s集群             │   │
│  └──┬─────────────────────────────┘   │
│     │                                   │
│  ┌──▼──────────────────────────────┐   │
│  │  部署策略                        │   │
│  │  • 滚动更新 (RollingUpdate)     │   │
│  │  • 金丝雀发布 (Canary)          │   │
│  │  • 蓝绿部署 (Blue-Green)        │   │
│  │  • 渐进式交付 (Progressive)     │   │
│  └──────────────────────────────────┘   │
└────────────────────────────────────────┘

二、GitHub Actions CI流水线

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

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

env:
  REGISTRY: registry.example.com
  IMAGE_NAME: shop/user-service

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    
    - name: Set up Go
      uses: actions/setup-go@v5
      with:
        go-version: '1.22'
    
    - name: Run unit tests
      run: go test -v -race -coverprofile=coverage.out ./...
    
    - name: Run linter
      uses: golangci/golangci-lint-action@v4
      with:
        version: latest
    
    - name: Security scan
      uses: securego/gosec@master
      with:
        args: ./...

  build:
    needs: test
    runs-on: ubuntu-latest
    if: github.event_name == 'push'
    outputs:
      image_tag: ${{ steps.meta.outputs.tags }}
    steps:
    - uses: actions/checkout@v4
    
    - name: Login to registry
      uses: docker/login-action@v3
      with:
        registry: ${{ env.REGISTRY }}
        username: ${{ secrets.REGISTRY_USER }}
        password: ${{ secrets.REGISTRY_PASS }}
    
    - name: Extract metadata
      id: meta
      uses: docker/metadata-action@v5
      with:
        images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
        tags: |
          type=sha,prefix=
          type=ref,event=branch
    
    - name: Build and push
      uses: docker/build-push-action@v5
      with:
        context: .
        push: true
        tags: ${{ steps.meta.outputs.tags }}
        labels: ${{ steps.meta.outputs.labels }}
        cache-from: type=gha
        cache-to: type=gha,mode=max

  deploy-dev:
    needs: build
    runs-on: ubuntu-latest
    environment: development
    steps:
    - uses: actions/checkout@v4
    - name: Update Helm values
      run: |
        yq -i ".image.tag = \"${{ needs.build.outputs.image_tag }}\"" \
          charts/user-service/values-dev.yaml
        git config user.name "github-actions"
        git commit -am "chore: update dev image tag"
        git push

三、ArgoCD——GitOps持续交付

# 安装ArgoCD
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

# ✅ 验证通过
kubectl get pods -n argocd
# NAME                                  READY   STATUS    RESTARTS   AGE
# argocd-application-controller-0       1/1     Running   0          2m
# argocd-repo-server-xxxxx              1/1     Running   0          2m
# argocd-server-xxxxx                   1/1     Running   0          2m

# 获取初始密码
kubectl -n argocd get secret argocd-initial-admin-secret \
  -o jsonpath="{.data.password}" | base64 -d

# 访问ArgoCD UI
kubectl port-forward svc/argocd-server -n argocd 8080:443
# https://localhost:8080

3.1 ArgoCD Application

# argocd-app.yaml - 声明式Application
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: user-service
  namespace: argocd
  annotations:
    notifications.argoproj.io/subscribe.on-deployed.slack: deploy-notifications
spec:
  project: default
  source:
    repoURL: https://github.com/example/shop-manifests.git
    targetRevision: main
    path: charts/user-service
    helm:
      valueFiles:
      - values.yaml
      - values-prod.yaml
      parameters:
      - name: image.tag
        value: "sha-abc123"         # CI流水线自动更新
      
  destination:
    server: https://kubernetes.default.svc
    namespace: shop-system
  
  syncPolicy:
    automated:
      prune: true                   # 自动删除多余资源
      selfHeal: true                # 自动修复漂移
      allowEmpty: false
    syncOptions:
    - CreateNamespace=true
    - ServerSideApply=true
    retry:
      limit: 3
      backoff:
        duration: 5s
        factor: 2
        maxDuration: 3m

# ✅ 验证通过
kubectl get applications -n argocd
# NAME           SYNC STATUS   HEALTH STATUS
# user-service   Synced        Healthy

3.2 App of Apps模式

# apps-of-apps.yaml - 集中管理所有应用
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: shop-apps
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/example/shop-manifests.git
    targetRevision: main
    path: argocd/apps              # 包含多个Application YAML
  destination:
    server: https://kubernetes.default.svc
    namespace: argocd
  syncPolicy:
    automated:
      prune: true
      selfHeal: true

# argocd/apps/ 目录下:
# ├── user-service.yaml
# ├── product-service.yaml
# ├── order-service.yaml
# ├── payment-service.yaml
# └── frontend.yaml

四、Argo Rollouts——渐进式交付

# 安装Argo Rollouts
kubectl create namespace argo-rollouts
kubectl apply -n argo-rollouts -f https://github.com/argoproj/argo-rollouts/releases/latest/download/install.yaml

# Rollout替代Deployment
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: user-service
  namespace: shop-system
spec:
  replicas: 10
  strategy:
    canary:
      steps:
      - setWeight: 10              # 10%流量到新版本
      - pause: {duration: 5m}     # 观察5分钟
      - setWeight: 30
      - pause: {duration: 5m}
      - setWeight: 50
      - pause: {duration: 10m}
      - setWeight: 80
      - pause: {duration: 5m}
      # 自动完成到100%
      
      canaryService: user-service-canary
      stableService: user-service-stable
      
      analysis:
        templates:
        - templateName: success-rate
        args:
        - name: service-name
          value: user-service-canary

---
# AnalysisTemplate - 自动化验证
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
  name: success-rate
  namespace: shop-system
spec:
  args:
  - name: service-name
  metrics:
  - name: success-rate
    interval: 30s
    count: 10
    successCondition: result[0] >= 0.99
    failureLimit: 3
    provider:
      prometheus:
        address: http://monitoring-kube-prometheus-prometheus.monitoring.svc:9090
        query: |
          sum(rate(http_requests_total{service="{{args.service-name}}",status!~"5.."}[2m]))
          /
          sum(rate(http_requests_total{service="{{args.service-name}}"}[2m]))

# ✅ 验证通过
kubectl argo rollouts get rollout user-service -n shop-system

五、Dockerfile最佳实践

# 多阶段构建 + 安全基础镜像
# Dockerfile
FROM golang:1.22-alpine AS builder

WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download

COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /user-service .

# 最终镜像
FROM gcr.io/distroless/static-debian12:nonroot

COPY --from=builder /user-service /user-service

USER nonroot:nonroot
ENTRYPOINT ["/user-service"]

六、练习

  1. 创建GitHub Actions CI流水线:测试→构建→推送镜像
  2. 安装ArgoCD,创建Application实现GitOps部署
  3. 使用App of Apps模式管理多个微服务
  4. 部署Argo Rollouts,实现金丝雀发布+自动分析
  5. 配置ArgoCD通知:部署成功/失败时发送Slack消息

🏆 第22课成就解锁

下一课预告:第23课深入服务网格Istio——流量管理与可观测性。

📌 补充知识

22-cicd流水线补充要点K8s生产实践扩展

🔹 资源配额(ResourceQuota):限制命名空间总资源
  apiVersion: v1
  kind: ResourceQuota
  metadata:
    name: compute-quota
    namespace: production
  spec:
    hard:
      requests.cpu: "20"
      requests.memory: 40Gi
      limits.cpu: "40"
      limits.memory: 80Gi
      pods: "50"
      services: "10"

🔹 LimitRange:设置默认资源限制
  apiVersion: v1
  kind: LimitRange
  metadata:
    name: default-limits
  spec:
    limits:
    - type: Container
      default:
        cpu: "200m"
        memory: 256Mi
      defaultRequest:
        cpu: "100m"
        memory: 128Mi
      max:
        cpu: "2"
        memory: 4Gi

🔹 Pod优先级与抢占
  apiVersion: scheduling.k8s.io/v1
  kind: PriorityClass
  metadata:
    name: high-priority
  value: 1000000
  globalDefault: false
  ---
  spec:
    preemptionPolicy: PreemptLowerPriority

🔹 优雅处理Pod中断
  • PDB保证最小可用副本
  • preStop钩子处理连接排空
  • terminationGracePeriodSeconds充足
  • 应用必须处理SIGTERM信号

🔹 生产环境Checklist
  ✅ 设置resources requests/limits
  ✅ 配置liveness/readiness探针
  ✅ 使用PDB保护关键服务
  ✅ 实现优雅关闭(SIGTERM)
  ✅ 配置HPA自动伸缩
  ✅ 使用NetworkPolicy隔离
  ✅ 开启RBAC最小权限
  ✅ 日志结构化输出
  ✅ 指标暴露/metrics端点
  ✅ 配置PVC数据备份

📎 扩展阅读与生产实践

22-cicd流水线生产环境进阶要点

🔹 性能优化关键参数
  • kubelet: --max-pods=110 --pods-per-core=10
  • kube-apiserver: --max-requests-inflight=800
  • etcd: --quota-backend-bytes=8589934592
  • kube-scheduler: --percentage-of-nodes-to-score=50

🔹 集群容量规划
  • 控制平面:3节点,8C16G起步
  • Worker节点:按应用类型分组
  • etcd:SSD磁盘,<2ms延迟
  • 网络带宽:10Gbps+集群内互联

🔹 故障自愈最佳实践
  1. Pod: livenessProbe自动重启
  2. Deployment: ReplicaSet保证副本数
  3. Node: kubelet自注册+健康检查
  4. Cluster: Cluster Autoscaler增减节点
  5. Multi-Cluster: Karmada联邦容灾

🔹 K8s版本升级策略
  • 每次只升一个minor版本
  • 先升级控制平面,再升级Worker
  • 使用kubeadm upgrade plan预检
  • 准备回滚方案
  • 在staging环境验证后再升级prod