第十五章 云平台部署与 DevOps 实践

1. 学习目标

本章把第十三-十四章的”质量门禁 + 协作流程”延伸到生产部署:从”PR 合并”到”流量打到新版本”全自动闭环。重点解决 AI 生成 K8s/IaC 配置的三大反模式——资源限制缺失导致节点 OOM、探针配置错误导致流量打到未就绪 Pod、Secrets 明文写在 ConfigMap 中——并把它们沉淀为强制门禁。本章不重复第十二章的微服务治理(Istio/mTLS/SLO),而专注于容器构建 → 镜像安全 → K8s 编排 → GitOps 发布 → IaC 与可观测这条 DevOps 主链路。

1.1 学习路径图

graph TD
    A[前置技能检查] --> B[DevOps 与发布策略理论]
    B --> C[Docker 多阶段 + Trivy 扫描]
    C --> D[Kubernetes 生产清单]
    D --> E[Helm/Kustomize 模板化]
    E --> F[ArgoCD GitOps + Argo Rollouts]
    F --> G[Terraform IaC + External Secrets]
    G --> H[Prom/Grafana/Loki 可观测]
    H --> I[审查闭环与团队 Skill]

    style A fill:#e1f5fe
    style I fill:#c8e6c9

1.2 预期学习成果

本章结束时应形成 6 项交付物:① 多阶段 Dockerfile(生产镜像 < 200 MB,distroless 基础);② 一套生产可上线的 K8s 清单(含 limits / probes / runAsNonRoot / NetworkPolicy / PDB / HPA);③ Helm chart 或 Kustomize overlay(dev/staging/prod 三套环境);④ ArgoCD application 配置(自动同步 + Argo Rollouts 蓝绿/金丝雀);⑤ Terraform 模块管理 EKS/GKE 集群与 IAM;⑥ devops-review Skill 含六类缺陷 + 8 条危险模式 grep。


2. 前置技能检查

维度 必备能力 自检方法
Docker 多阶段构建、Buildx、网络与卷 docker build 出 < 200 MB 镜像并能 docker run 起来
Kubernetes Pod / Deployment / Service / Ingress / ConfigMap / Secret 能在 kind/minikube 上部署一个含 ingress 的 demo 应用
Linux & 网络 shell、文件权限、TLS、负载均衡 能解释 curl https://example.com 的 TLS 握手与 SNI 流程
Ch13/Ch14 CI 流水线 + Branch Protection + Conventional Commits 本地能跑通 Ch14 §5.3 的四 job CI
云平台账号 AWS/GCP/Aliyun 任一,含基础 IAM 权限 能用 CLI 创建 VPC + EKS/GKE 集群(kind 也可代替)

任一项不满足,建议先回到对应章节复习。本章对基础设施知识要求最高。


3. 理论基础:发布策略与陷阱

3.1 发布策略对比

策略 适用场景 切换粒度 资源占用 回滚速度 AI 高频缺陷
Recreate 内部工具、可停服 全量 无 PDB 导致全部一起死
Rolling Update Web 服务通用默认 maxSurge/Unavailable 1.25× maxUnavailable 设为 100%、无 readiness
Blue/Green 数据库迁移、强一致性场景 全量切换 秒级 流量未切回旧环境就被清理
Canary 新功能灰度、用户量大 1% → 100% 1.05-1.5× 秒级 缺指标驱动、靠人工 ramp-up
A/B (Header) 业务实验、按用户切流 任意百分比 1.05-1.5× 秒级 流量染色 header 无审计

决策口诀:“无状态 Web 用 Canary(Argo Rollouts),有状态/Schema 改动用 Blue/Green,业务实验用 A/B header 切流”

3.2 AI 生成 K8s/IaC 配置的六类高频缺陷

类别 典型表现 根因 审查优先级 修正提示词模板(按 Ch2 §4.9
资源限制缺失 resources.limits 不设或仅设 cpu 不设 memory;request = limit 导致 QoS=Guaranteed 浪费 AI 套官方 quickstart 不写 limits P0 保留 Deployment 名,补 resources.requests/limits (cpu+memory) + QoS=Burstable。不要动镜像。验证:kubectl describe pod 显示 limits
探针配置错误 livez/readyz 用同一端点;initialDelay 太短;探针超时 1 s 导致频繁重启 AI 不区分进程存活与依赖就绪 P0 保留容器端口,拆 /livez/readyz + initialDelaySeconds 含启动 buffer + timeoutSeconds=5。不要动 image。验证:DB 抖动 pod 不重启
root 与权限失守 runAsNonRoot=falseallowPrivilegeEscalation=truecapabilities 未 drop ALL AI 套 ubuntu 镜像默认 root P0 保留镜像 base,securityContext: runAsNonRoot:true + readOnlyRootFilesystem + capabilities.drop: [ALL]。不要动 args。验证:kubectl exec id 返 uid≠0
Secrets 明文与漂移 DB 密码写在 ConfigMap;Secret 明文 commit 进 git;无外部 secret manager AI 不会主动用 ESO / Sealed Secrets / Vault P0 保留引用键名,迁 ExternalSecrets + Vault 或 AWS SecretsManager。不要动 env 变量名。验证:git grep -E "password\|token" 返 0 明文
镜像 tag 不可重现 image: app:latest;构建时间戳 tag;Helm values 不锁 digest AI 默认套 latest,违反 GitOps 不可变原则 P1 保留 image repo,tag 改 sha256 digest 锁定 + Helm values 同步锁定。不要动 chart 结构。验证:CI 构建镜像 hash 与运行时 hash 一致
滚动更新与中断保护缺失 PodDisruptionBudgetmaxUnavailable=25% 但只有 2 副本;preStop 缺 sleep AI 套默认值忽略副本数与 graceful shutdown P1 保留 replicas,加 PodDisruptionBudget: minAvailable:70% + preStop: sleep 15s + maxUnavailable:1。不要动 update strategy。验证:drain 节点时 SLO 不破

3.3 传统部署 vs AI 辅助 DevOps

维度 传统手工 AI 辅助(Trae)
Dockerfile 抄基础模板,懂 layer cache 一句话生成多阶段,但常忘 healthcheck/non-root
K8s YAML 凭经验逐字段填 完整骨架但 limits/probes/securityContext 默认错
Helm Chart 抄已有 chart 模板齐全,但 values.yaml 缺 schema、values 过松
Terraform 模块边界清晰 喜欢把所有资源放一个 main.tf,无 state 隔离
监控告警 抄 Prometheus rules 模板 规则齐全但 SLO/Burn rate 通常缺失(见 Ch12)

结论:AI 让基础设施 YAML 接近 0 成本,但让”生产可用性”审查成本翻倍。本章 §7 + §3.2 六类缺陷是审查抓手。


4. 技术栈与项目架构

4.1 技术栈与最低版本

选型 最低版本 选型说明
容器引擎 Docker / containerd 26 / 1.7 Docker 26 默认 BuildKit;containerd 1.7 支持 sandbox v2
镜像构建 Docker Buildx 0.14+ 多平台、缓存导入导出、SBOM/attestation
镜像扫描 Trivy / Grype 0.55+ Trivy 含 misconfig + secret + license 扫描
基础镜像 distroless / chainguard latest distroless 减少攻击面 ≥ 90%
编排 Kubernetes 1.30+ 1.30 GA:Sidecar Containers、ValidatingAdmissionPolicy
模板 Helm / Kustomize 3.14 / 5.4 Helm 3.14 OCI-only;Kustomize 5.4 支持 components
GitOps Argo CD 2.10+ 2.10 起 ApplicationSet + Sync Waves 稳定
渐进发布 Argo Rollouts 1.7+ 支持 metric-driven canary
IaC Terraform / OpenTofu 1.9 / 1.7 OpenTofu 是 1.5 后的开源分叉
配置管理 Ansible 10+ 用于裸金属与 OS 层;K8s 优先 Helm/Kustomize
密钥 External Secrets Operator + Vault 0.10 / 1.15 替代 Sealed Secrets,支持轮转
Ingress Ingress-NGINX / Gateway API 1.10 / v1 Gateway API v1 GA,K8s 1.30 推荐
证书 cert-manager 1.15+ ACME / Let’s Encrypt / 内部 CA 全支持
自动扩缩 HPA + KEDA 1.30 / 2.15 KEDA 支持事件驱动(Kafka/RabbitMQ/SQS)
可观测 Prometheus + Grafana + Loki + Tempo 2.50 / 10.4 / 3.0 / 2.4 完整 LGTM 栈
Runtime 安全 Falco / Tetragon 0.38 / 1.0 eBPF 检测异常容器行为
策略 Kyverno / OPA Gatekeeper 1.12 / 3.16 Kyverno YAML 原生,更易上手

4.2 仓库与环境结构(GitOps 友好)

infra-repo/
├── clusters/
│   ├── prod/                   # 集群级配置(一个 cluster 一个目录)
│   │   ├── argocd/
│   │   └── kustomization.yaml
│   └── staging/
├── platform/                   # 平台级公共组件
│   ├── ingress-nginx/          # Helm chart 引用
│   ├── cert-manager/
│   ├── external-secrets/
│   └── kube-prometheus-stack/
├── apps/                       # 业务应用(一个 app 一个目录)
│   └── task-api/
│       ├── base/               # Kustomize base
│       ├── overlays/
│       │   ├── dev/
│       │   ├── staging/
│       │   └── prod/
│       └── argocd-app.yaml     # Argo CD ApplicationSet 入口
└── terraform/
    ├── modules/                # 复用的 vpc / eks / iam 模块
    └── envs/
        ├── prod/               # 一环境一 backend、一 state
        └── staging/

强约定:业务代码与基础设施代码 separate repo(apps repo + infra repo),通过 Argo CD ApplicationSet 关联,避免应用 commit 触发 infra 漂移。


5. 主框架实战:从 Dockerfile 到 GitOps

5.1 多阶段 Dockerfile(Node.js 示例)

# syntax=docker/dockerfile:1.7
ARG NODE_VERSION=20.15.0

# ---- 1) deps:仅装依赖,最大化缓存 ----
FROM node:${NODE_VERSION}-bookworm-slim AS deps
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN --mount=type=cache,target=/pnpm-store \
    corepack enable && pnpm config set store-dir /pnpm-store \
    && pnpm install --frozen-lockfile --prod=false        # ✅ frozen-lockfile

# ---- 2) build:编译 TS、打包前端 ----
FROM deps AS build
COPY . .
RUN pnpm build && pnpm prune --prod                       # ✅ 仅保留运行时依赖

# ---- 3) runtime:distroless,无 shell,无 root ----
FROM gcr.io/distroless/nodejs20-debian12:nonroot          # ✅ distroless + nonroot
WORKDIR /app
COPY --from=build --chown=nonroot:nonroot /app/dist ./dist
COPY --from=build --chown=nonroot:nonroot /app/node_modules ./node_modules
COPY --from=build --chown=nonroot:nonroot /app/package.json ./
USER nonroot                                               # ✅ 显式声明
EXPOSE 3000
# ⚠️ 反例:CMD ["npm","start"]   distroless 没有 npm
CMD ["dist/server.js"]
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
    CMD ["dist/healthcheck.js"]                           # ✅ 自带 healthcheck,便于 docker
# 配套构建命令(CI 中执行)
docker buildx build \
  --platform linux/amd64,linux/arm64 \
  --provenance=true --sbom=true \
  --tag ghcr.io/org/app:${GIT_SHA} \
  --tag ghcr.io/org/app:$(git describe --tags --always) \
  --cache-to type=gha,mode=max \
  --cache-from type=gha \
  --push .

trivy image --severity HIGH,CRITICAL --exit-code 1 ghcr.io/org/app:${GIT_SHA}  # ✅ 阻断式扫描

关键:① distroless:nonroot + USER nonroot 双保险;② --provenance + --sbom 让镜像可追溯;③ Trivy --exit-code 1 让 HIGH/CRITICAL 漏洞直接阻断 CI。

5.2 生产可上线的 K8s 清单(核心三件套)

# apps/task-api/base/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: task-api
spec:
  replicas: 3
  strategy:
    type: RollingUpdate
    rollingUpdate: { maxUnavailable: 0, maxSurge: 1 } # ✅ 0 停机
  selector: { matchLabels: { app: task-api } }
  template:
    metadata:
      labels: { app: task-api, version: v1 }
      annotations: { prometheus.io/scrape: "true", prometheus.io/port: "9090" }
    spec:
      serviceAccountName: task-api # ✅ 专属 SA,禁默认 SA
      automountServiceAccountToken: false # ✅ 不需要时关闭
      securityContext:
        runAsNonRoot: true # ✅ Pod 级
        runAsUser: 65532
        fsGroup: 65532
        seccompProfile: { type: RuntimeDefault } # ✅ seccomp
      topologySpreadConstraints: # ✅ 跨 zone 打散
        - maxSkew: 1
          topologyKey: topology.kubernetes.io/zone
          whenUnsatisfiable: ScheduleAnyway
          labelSelector: { matchLabels: { app: task-api } }
      containers:
        - name: app
          image: ghcr.io/org/task-api@sha256:... # ✅ 锁 digest,不用 tag
          imagePullPolicy: IfNotPresent
          ports:
            [
              { name: http, containerPort: 3000 },
              { name: metrics, containerPort: 9090 },
            ]
          envFrom: [{ secretRef: { name: task-api-secrets } }]
          resources: # ✅ requests = limits(除 cpu)
            requests: { cpu: "100m", memory: "256Mi", ephemeral-storage: "1Gi" }
            limits: { memory: "256Mi", ephemeral-storage: "2Gi" }
          livenessProbe: # ✅ 进程存活
            httpGet: { path: /livez, port: http }
            initialDelaySeconds: 10
            periodSeconds: 20
            timeoutSeconds: 3
            failureThreshold: 3
          readinessProbe: # ✅ 依赖就绪(与 livez 区分)
            httpGet: { path: /readyz, port: http }
            initialDelaySeconds: 5
            periodSeconds: 5
            timeoutSeconds: 2
            failureThreshold: 2
          startupProbe: # ✅ 慢启动场景必备
            httpGet: { path: /livez, port: http }
            failureThreshold: 30
            periodSeconds: 10
          lifecycle:
            preStop:
              exec: { command: ["/bin/sleep", "15"] } # ✅ 给 Service 摘除时间
          securityContext: # ✅ container 级再加固
            allowPrivilegeEscalation: false
            readOnlyRootFilesystem: true
            capabilities: { drop: ["ALL"] }
          volumeMounts:
            - { name: tmp, mountPath: /tmp } # ✅ readOnlyRootFilesystem 必备
      volumes:
        - { name: tmp, emptyDir: {} }
      terminationGracePeriodSeconds: 60 # ✅ ≥ preStop sleep + 处理时间
---
# pdb.yaml — 防止滚动更新时全部一起死
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata: { name: task-api }
spec:
  minAvailable: 2 # ✅ 3 副本至少留 2
  selector: { matchLabels: { app: task-api } }
---
# hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata: { name: task-api }
spec:
  scaleTargetRef: { apiVersion: apps/v1, kind: Deployment, name: task-api }
  minReplicas: 3
  maxReplicas: 30
  metrics:
    - type: Resource
      resource:
        { name: cpu, target: { type: Utilization, averageUtilization: 60 } }
  behavior:
    scaleDown: # ✅ 防止抖动
      stabilizationWindowSeconds: 300
      policies: [{ type: Percent, value: 10, periodSeconds: 60 }]
---
# networkpolicy.yaml — 默认拒绝
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata: { name: task-api-ingress }
spec:
  podSelector: { matchLabels: { app: task-api } }
  policyTypes: [Ingress, Egress]
  ingress:
    - from:
        [
          {
            namespaceSelector:
              { matchLabels: { kubernetes.io/metadata.name: ingress-nginx } },
          },
        ]
      ports: [{ port: http }]
  egress: # ✅ 显式声明可访问目标
    - to:
        [
          {
            namespaceSelector:
              { matchLabels: { kubernetes.io/metadata.name: kube-system } },
          },
        ]
      ports: [{ port: 53, protocol: UDP }] # DNS
    - to: [{ podSelector: { matchLabels: { app: postgres } } }]
      ports: [{ port: 5432 }]

关键决策:① memory limits = requestscpu limits 留空(避免 throttling);② livez/readyz 必须分离——livez 仅检进程,readyz 检依赖;③ PDB 是 K8s 1.21+ 默认行为前提,必须显式设置。

5.3 Helm + Kustomize 三环境管理

# apps/task-api/overlays/prod/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: prod
resources: [../../base]
patches:
  - target: { kind: Deployment, name: task-api }
    patch: |-
      - op: replace
        path: /spec/replicas
        value: 6                                          # ✅ prod 跑 6 副本
      - op: replace
        path: /spec/template/spec/containers/0/resources/requests/cpu
        value: "500m"
images:
  - name: ghcr.io/org/task-api
    newTag: v1.4.2@sha256:abc... # ✅ Argo Image Updater 会改这一行
configMapGenerator:
  - name: task-api-config
    behavior: merge
    literals: [LOG_LEVEL=info, RATE_LIMIT=1000]

选型建议:应用业务用 Kustomize(轻量、纯 YAML、Argo CD 原生),平台组件用 Helm(社区 chart 多)。混用而不内嵌。

5.4 Argo CD GitOps + Argo Rollouts 渐进发布

# apps/task-api/argocd-app.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata: { name: task-api-prod, namespace: argocd }
spec:
  project: default
  source:
    repoURL: https://github.com/org/infra
    targetRevision: main
    path: apps/task-api/overlays/prod
  destination: { server: https://kubernetes.default.svc, namespace: prod }
  syncPolicy:
    automated: { prune: true, selfHeal: true } # ✅ 自动 self-heal 防漂移
    syncOptions: [ServerSideApply=true, CreateNamespace=true]
    retry: { limit: 3, backoff: { duration: 30s, factor: 2, maxDuration: 5m } }
---
# rollout.yaml — 用 Argo Rollouts 替代原生 Deployment
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata: { name: task-api }
spec:
  replicas: 6
  strategy:
    canary:
      canaryService: task-api-canary
      stableService: task-api-stable
      trafficRouting: { nginx: { stableIngress: task-api } }
      steps:
        - setWeight: 5 # ✅ 5% → 观察
        - pause: { duration: 5m }
        - analysis: # ✅ 指标驱动,非定时
            templates: [{ templateName: success-rate-and-latency }]
            args: [{ name: service-name, value: task-api-canary }]
        - setWeight: 25
        - pause: { duration: 10m }
        - setWeight: 50
        - pause: { duration: 10m }
        - setWeight: 100
---
# AnalysisTemplate — 失败自动回滚
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata: { name: success-rate-and-latency }
spec:
  args: [{ name: service-name }]
  metrics:
    - name: success-rate
      successCondition: result[0] >= 0.99 # ✅ 99% 成功率
      failureLimit: 1
      provider:
        prometheus:
          address: http://prometheus.monitoring:9090
          query: |
            sum(rate(http_requests_total{service="",code!~"5.."}[2m]))
            / sum(rate(http_requests_total{service=""}[2m]))
    - name: p95-latency
      successCondition: result[0] <= 0.300 # ✅ p95 ≤ 300 ms
      failureLimit: 1
      provider:
        prometheus:
          address: http://prometheus.monitoring:9090
          query: |
            histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket{service=""}[2m])) by (le))

强约定:指标驱动 ramp-up,禁止定时无脑加权重。pause 仅用于初次观察,分析失败立即回滚。

5.5 Terraform IaC(EKS 集群示例)

# terraform/envs/prod/main.tf
terraform {
  required_version = ">= 1.9"
  backend "s3" {                                         # ✅ remote state,不本地
    bucket         = "org-tfstate-prod"
    key            = "eks/prod/terraform.tfstate"
    region         = "us-west-2"
    dynamodb_table = "tfstate-lock"                      # ✅ state 锁
    encrypt        = true
  }
  required_providers { aws = { version = "~> 5.60" } }
}

module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "5.13.0"                                     # ✅ 锁版本
  name    = "prod-vpc"
  cidr    = "10.0.0.0/16"
  azs             = ["us-west-2a", "us-west-2b", "us-west-2c"]
  private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
  public_subnets  = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]
  enable_nat_gateway = true
  single_nat_gateway = false                             # ✅ 生产多 AZ NAT
  tags = { Env = "prod", IaC = "terraform" }
}

module "eks" {
  source  = "terraform-aws-modules/eks/aws"
  version = "20.24.0"
  cluster_name    = "prod"
  cluster_version = "1.30"                               # ✅ 锁 K8s 版本
  vpc_id     = module.vpc.vpc_id
  subnet_ids = module.vpc.private_subnets
  cluster_endpoint_public_access  = false                # ✅ 仅私网
  cluster_endpoint_private_access = true
  enable_cluster_creator_admin_permissions = false       # ✅ 不让创建者拿 cluster-admin
  eks_managed_node_groups = {
    default = {
      ami_type       = "BOTTLEROCKET_x86_64"             # ✅ 安全加固 OS
      instance_types = ["m6i.xlarge"]
      min_size = 3; max_size = 20; desired_size = 6
      taints = []
    }
  }
  cluster_addons = {                                     # ✅ 内建 addon
    coredns    = { most_recent = true }
    kube-proxy = { most_recent = true }
    vpc-cni    = { most_recent = true }
  }
}

关键:① S3 backend + DynamoDB 锁(防并发 apply);② provider 与模块版本必须锁;③ enable_cluster_creator_admin_permissions=false 防止 root 用户绑死 cluster-admin。

5.6 External Secrets + Vault(替代 Sealed Secrets)

# secret-store.yaml(一次性配置)
apiVersion: external-secrets.io/v1beta1
kind: ClusterSecretStore
metadata: { name: vault-backend }
spec:
  provider:
    vault:
      server: "https://vault.org.internal"
      path: "kv"
      version: "v2"
      auth:
        kubernetes:
          mountPath: "kubernetes"
          role: "external-secrets" # ✅ 走 Kubernetes auth
---
# external-secret.yaml(每个应用一份)
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata: { name: task-api-secrets, namespace: prod }
spec:
  refreshInterval: 1h # ✅ 自动轮转
  secretStoreRef: { kind: ClusterSecretStore, name: vault-backend }
  target: { name: task-api-secrets, creationPolicy: Owner }
  data:
    - {
        secretKey: DB_PASSWORD,
        remoteRef: { key: prod/task-api, property: db_password },
      }
    - {
        secretKey: JWT_SIGNING_KEY,
        remoteRef: { key: prod/task-api, property: jwt_key },
      }

强约定:git 仓库永不出现明文 secret;ExternalSecret 是唯一与 git 关联的 secret 资源,真正的值在 Vault。


5.7 Vibe Coding 循环实录:livez/readyz 混淆修正

修正语法:「修正提示词」按 Ch2 §4.9 修正提示词语法 模板;3 轮未收敛触发 §4.10。模式选择查 Ch1 §5.4

轮次 AI 输出摘要 发现的缺陷 修正提示词(按 §4.9) 验证信号
R1 livenessProbereadinessProbe 同指 /health(含 DB 连通检查) DB 抖动 → 进程被反复 kill → 雪崩 保留容器与端口配置不变,修复探针端点:拆 /livez(仅返回 200,验证进程存活) + /readyz(含依赖检查)。原因:liveness 失败应重启,readiness 失败应摘流量。不要动镜像与 args。验证:DB 短暂抖动时 pod 不重启但被摘流量 DB 抖动 → pod 不重启
R2 JVM 冷启 30s,readiness 阈值 10s 滚动升级时新 pod 反复被 kill 保留 livez/readyz 拆分,新增 startupProbe: { failureThreshold: 30, periodSeconds: 5 } 给 readyz。原因:startupProbe 期内禁用 liveness。不要动 readyz periodSeconds。验证:冷启 150s 内 pod 不被重启 冷启不重启
R3 滚动升级时所有 pod 同时 NotReady 流量瞬时 503 突增 保留三探针配置,新增 PodDisruptionBudget: { minAvailable: 70% }。原因:滚动期必须保留可服务副本。不要动 replicas 数。验证:kubectl drain 一个节点时 SLO 不破(错误率 < 0.1%) drain 时 SLO 不破

收敛信号:探针拆分 + startup 缓冲 + PDB 三层达标。如未收敛触发 §4.10 信号 3(结构性缺陷:应用本身无优雅关闭),按「换模式」重启——切 Chat 先讨论 SIGTERM handler,再回 Builder 写 K8s 清单。


6. 进阶速查表

6.1 进阶场景索引

场景 关键技术 AI 高频缺陷 建议提示词关键词
多集群管理 Argo CD ApplicationSet + Cluster API 集群凭证泄漏 “ApplicationSet generators + cluster secret”
事件驱动伸缩 KEDA + Kafka/SQS scale-to-zero 时漏消息 “KEDA ScaledObject + cooldown + minReplicas”
多租户隔离 Namespace + Hierarchical NS + Quota quota 过松、网络策略缺失 “ResourceQuota + LimitRange + NetworkPolicy”
批处理/AI 训练 Kueue / Volcano / Job + Gang scheduling OOM 中途失败无重试 “Indexed Job + suspend + checkpoint”
混沌工程 Chaos Mesh / LitmusChaos 不限定爆炸半径 “namespace selector + duration + dry-run”
成本优化 Karpenter + Spot + KEDA Spot 中断未处理 “interruption queue + PDB + topology spread”

6.2 部署性能基线

指标 目标值 测量方法
镜像大小(Node.js) < 200 MB docker image ls
镜像构建时间(缓存命中) < 60 s docker buildx build --progress=plain 计时
Pod 冷启动 → ready < 30 s kubectl get events 查 Ready 时间
滚动更新单 Pod 切换 < 30 s preStop sleep 15 + readiness 5 + 启动 ≤ 10
Argo CD 同步时延 < 1 min App sync wave from git push
Prometheus rule 评估 < 30 s scrape interval + evaluation latency

6.3 配置 Cheatsheet

# 一键 K8s 配置审计(CI 中跑)
kubectl kustomize apps/task-api/overlays/prod | kube-score score -        # ✅ 静态分析
kubectl kustomize apps/task-api/overlays/prod | kubeconform -strict       # ✅ schema 校验
kubectl kustomize apps/task-api/overlays/prod | trivy config -            # ✅ misconfig 扫描
checkov -d terraform/envs/prod                                            # ✅ Terraform 安全扫描

# 镜像 SBOM + 签名 + 验证
syft ghcr.io/org/app:${SHA} -o cyclonedx-json > sbom.json
cosign sign --key cosign.key ghcr.io/org/app:${SHA}                       # ✅ 镜像签名
cosign verify --key cosign.pub ghcr.io/org/app:${SHA}                     # ✅ 部署前验证

7. 审查闭环:把 DevOps 配置变成可强制门禁

7.1 四步审查法(DevOps 配置专用)

步骤 关键检查项
正确性 livez/readyz 是否分离?preStop sleep 是否 ≥ Service 摘除时间?PDB 是否设置?HPA 是否覆盖 maxReplicas?rolling 时是否能保持 N-1 副本可用?
安全性 runAsNonRoot=true?capabilities drop ALL?readOnlyRootFilesystem=true?NetworkPolicy 默认拒绝?Secrets 是否走 ESO/Vault?
性能 request/limits 是否合理(无 cpu limits 防 throttling)?镜像 < 200 MB?distroless?scrape interval ≥ 15 s 防 cardinality 爆炸?
可维护性 镜像锁 digest 而非 tag?Helm/Kustomize 是否分环境?Argo CD self-heal 是否启用?Terraform state 是否 remote + 锁?

7.2 三类生产事故场景测试(AI 最容易遗漏)

# 1) 节点丢失:删除一个 node,验证 Pod 在 60 s 内迁移完成且不超过 PDB 限制
kubectl drain node/<n> --ignore-daemonsets --delete-emptydir-data
kubectl get pods -l app=task-api -w   # ✅ 不应低于 minAvailable

# 2) 配置漂移:手动改 prod 中 Deployment replicas,验证 Argo CD 自动 self-heal 还原
kubectl scale deploy/task-api -n prod --replicas=99
sleep 60
kubectl get deploy task-api -n prod   # ✅ 应被 Argo CD 改回 6

# 3) 镜像不可达:把 Image 改成不存在的 tag,验证滚动更新自动停止 + 回滚
kubectl set image deploy/task-api app=ghcr.io/org/app:nonexistent -n prod
kubectl rollout status deploy/task-api -n prod --timeout=2m  # ✅ 必须失败
kubectl rollout undo deploy/task-api -n prod                  # ✅ 一键回滚

7.3 危险模式 grep 规则(沉淀进 devops-review Skill)

# 1. 镜像 tag 用 latest / 浮动 tag
grep -rEn 'image:\s*[^@]+:(latest|main|master|develop)\b' apps/ platform/

# 2. 资源 limits 缺失
yq '.. | select(has("containers")) | .containers[] | select(.resources.limits == null)' apps/**/*.yaml

# 3. probes 缺失或 livez/readyz 共用同一 path
yq '.. | select(has("livenessProbe")) | select(.livenessProbe.httpGet.path == .readinessProbe.httpGet.path)' apps/**/*.yaml

# 4. runAsNonRoot 未设
grep -rL "runAsNonRoot:\s*true" apps/

# 5. Secrets 明文写在 ConfigMap
grep -rEn 'kind:\s*ConfigMap' apps/ | xargs grep -lEi 'password|secret|token|api[_-]?key'

# 6. PDB 缺失
test -z "$(find apps -name '*.yaml' -exec grep -l 'PodDisruptionBudget' {} \;)" && echo "MISSING PDB!"

# 7. NetworkPolicy 缺失
grep -rL "kind:\s*NetworkPolicy" apps/

# 8. Terraform 资源未 tag(成本归因失败)
grep -rEn 'resource\s+"aws_' terraform/ | xargs grep -L 'tags\s*='

7.4 扫到问题后用什么提示词改?

上面 8 条扫描只识别「DevOps 危信号」;下一步必须按统一语法把意图写回 AI(参照 Ch2 §4.9)。

# 命中后修正提示词模板
1 保留 deployment 名,tag 改 :v1.2.3@sha256:... digest + imagePullPolicy: IfNotPresent。不要动 replicas。验证:grep 返 0;Argo CD diff 无漂移。
2 保留 requests,补 resources.limits(CPU = requests×2、Memory = requests)+ LimitRange。不要动 selector。验证:kubectl describe 显示 limits;OOMKilled 事件 0。
3 保留 livez 路径,readyz 改独立路径(依赖 DB/Redis)+ 补 startupProbe: { initialDelaySeconds:0, periodSeconds:10, failureThreshold:30 }。不要动端口。验证:滑动更新期间 0 5xx;kubectl describe pod 显示三探针独立。
4 保留 image,securityContextrunAsNonRoot: true + runAsUser: 1000 + readOnlyRootFilesystem: true + capabilities.drop: [ALL]。不要动 volume mounts。验证:kubectl exec -- id 显示非 0;kube-bench 红项 -1。
5 保留 key 名称,迁 kind: Secret + ESO/Vault;envFrom: secretRef:。不要动 env name。验证:grep 返 0;Secret 可轮换(kubectl rollout restart 不需改 manifest)。
6 保留 deployment 名,加 PodDisruptionBudget: { minAvailable: 1 };HA 服务设 minAvailable: replicas-1。不要动 replicas。验证:kubectl drain 节点时 ≥ 1 副本可用。
7 保留 namespace,落 default-deny + 按 label 放行。不要动 Service。验证:跨 ns curl 被拒;同 ns 同 label 能通。
8 保留 resource 名,加 tags = local.common_tags(含 owner/env/cost-center/repo);default provider 块加 default_tags。不要动 ARN。验证:成本看板按 tag 聚合 100% 覆盖。

3 轮未收敛触发 §4.10 的「换模式 / 缩范围 / 拆步骤」。


8. 三档实践

8.1 基础实践(必做)

为第十三章的 task-api 项目交付:① 多阶段 distroless Dockerfile,最终镜像 < 200 MB;② kind 本地集群部署 Deployment + Service + Ingress + ConfigMap + Secret,含 limits / probes / runAsNonRoot;③ 用 kube-score + kubeconform + trivy config 三个工具审计,输出”修复前 / 修复后”对比报告。

8.2 进阶实践(推荐)

接入完整 GitOps 链路:① Helm/Kustomize 三环境(dev/staging/prod);② Argo CD 部署 + ApplicationSet;③ Argo Rollouts 金丝雀(5% → 25% → 100%)+ AnalysisTemplate 指标驱动;④ External Secrets Operator + Vault 接入;⑤ Prometheus + Grafana + Loki + Alertmanager(复用 Ch12 SLO + Burn Rate 配置);⑥ 跑通 §7.2 三类生产事故场景演练。

8.3 开放实践(挑战)

为第十二章微服务平台搭建多集群 GitOps:① Terraform 模块化部署 EKS(prod / staging)+ VPC + IAM;② Argo CD Hub-and-Spoke 架构(一个管理集群推送到 N 个工作集群);③ Karpenter + Spot 实现成本下降 ≥ 50%;④ Kyverno 策略强制 §7.3 八条规则在 admission 阶段拦截;⑤ 跑一次 Chaos Mesh 节点丢失实验并写故障报告;⑥ 把所有规约沉淀为 .qoder/skills/devops-review/SKILL.md


9. 小结

9.1 章节交付物清单

编号 交付物 复用去向
D-15-1 多阶段 distroless Dockerfile + Trivy 扫描门禁 Ch16 镜像安全审查
D-15-2 生产可上线 K8s 清单(含 PDB/HPA/NetworkPolicy) Ch16 性能优化基础
D-15-3 Helm/Kustomize 三环境模板 Ch16 资源调优实验环境
D-15-4 Argo CD + Argo Rollouts GitOps 流水线 Ch16 性能回归门禁
D-15-5 Terraform 模块(VPC + EKS + IAM + Backend) 跨章节基础设施基线
D-15-6 devops-review Skill(六类缺陷 + 8 条 grep + 演练剧本) Ch16 安全审查规约

9.2 DevOps 能力自评 Rubric

维度 入门(1-2) 熟练(3-4) 精通(5)
Docker 能写单阶段 Dockerfile 多阶段 + distroless + 镜像 < 200 MB + Trivy 扫描 能设计跨平台 + SBOM + cosign 签名 + 镜像供应链
Kubernetes 能部署 demo 能写带 limits/probes/securityContext 的生产清单 能设计 PDB/HPA/NetworkPolicy/Kyverno 策略一体化的平台
GitOps 知道 Argo CD 概念 能配置 Argo CD + ApplicationSet 自动同步 能用 Argo Rollouts + AnalysisTemplate 指标驱动金丝雀
IaC 能跑通 Terraform demo 能拆分 module + remote state + 锁版本 能设计多环境 + provider + state 隔离 + drift detection
可观测 会看 Grafana 能配 Prometheus rule + Alertmanager + Loki LogQL 能设计 SLO + Burn Rate + 跨服务追踪关联
审查能力 会跑 §7.3 grep 能识别六类缺陷 + 跑三类故障演练 能输出可复用 Skill + 团队规约 + Kyverno admission 规则

9.3 跨章节衔接

  • ⬅️ Ch12:本章 K8s 清单与 GitOps 是 Ch12 微服务治理(Istio/SLO)的运行底座;本章不重复 Istio 配置;
  • ⬅️ Ch13/Ch14:本章 CI 中的 lint/test/build job 直接复用 Ch13/Ch14 配置,CD 链路在其后追加;
  • ➡️ Ch16:本章 §7.3 危险模式 grep 与三类故障演练是 Ch16 安全审查的输入;本章 Prometheus 指标是 Ch16 性能优化的观测基础;
  • ⬅️ Ch5-Ch11:所有业务应用的容器化与发布都走本章流水线。

10. 延伸阅读

10.1 经典必读(建立 DevOps 直觉)

  • 《Kubernetes in Action》(第 2 版,Marko Lukša)— K8s 原理与最佳实践
  • 《Site Reliability Engineering》(Google)+《SRE Workbook》— SLO / 错误预算 / on-call
  • 《The DevOps Handbook》(Gene Kim 等)— 三步工作法与文化
  • 《Infrastructure as Code》(第 2 版,Kief Morris)— IaC 演进与权衡
  • 《Cloud Native Patterns》(Cornelia Davis)— 云原生设计模式

10.2 工程化与官方规范

10.3 前沿研究与实践报告

  • DORA State of DevOps Report(最新版)— DF/LT/CFR/MTTR 跨企业基线
  • Accelerate State of Continuous Delivery(CD Foundation)
  • CNCF Annual Survey(最新版)— 工具采纳与趋势
  • Securing the Software Supply Chain(NIST SP 800-218)
  • The Twelve-Factor App(Heroku)— 云原生应用奠基方法论

完成判定:能在 30 分钟内为新应用产出 ① 多阶段 Dockerfile(< 200 MB);② 含 6 项审查通过的 K8s 生产清单;③ Argo CD application + 金丝雀 rollout;④ §7.3 八条 grep 全部通过。下一章我们将在此基础上深入安全与性能优化。