云原生基础

2025-11-01T14:11:02+08:00 | 17分钟阅读 | 更新于 2025-11-01T14:11:02+08:00

@

学习目标

学完本章你应该能够:

  1. 讲清软件交付从「瀑布 → 精益 → 敏捷 → DevOps → SRE → AIOps」的演进脉络,以及每一阶段解决的核心矛盾。
  2. 画出一条真实 DevOps 流水线的阶段(Plan/Code/Build/Test/Scan/Deploy/Verify/Monitor/Feedback),并说清 Jenkins、GitLab CI、ArgoCD 的定位差异。
  3. 用自己的话区分 SLI / SLO / 错误预算,并能算出一个具体服务的月度错误预算消耗。
  4. 讲清 AIOps 如何用 LLM 做 NL→PromQL、日志摘要、RAG 知识库与决策 Agent,以及「人在环里」的必要性。
  5. 说清 Terraform 与 Crossplane 的核心工作流与选型取舍,以及 state 漂移、force-unlock 等高频坑。

前置知识:用过 Git 和至少一种 CI 工具;知道 Docker / Kubernetes 的基本概念;对 Prometheus 指标有耳闻即可。

本章你会动手做的事

  • 用 Sloth 的 YAML 生成一份 Prometheus SLO recording rule,并跑通 sloth generate
  • 把你项目的一条 Prometheus 查询改写成「NL 问题 → PromQL」的 prompt 模板。
  • 写一份最小 main.tfterraform plan 预览一个 EKS 集群的变更(不真 apply)。

从精益、敏捷到 DevOps 的发展脉络

软件交付模式的演进,本质上是企业为了更快、更稳地响应市场变化而不断探索的过程。早期瀑布模型强调阶段清晰,但反馈周期长、变更成本高。随后精益(Lean)思想被引入软件开发,核心是消除浪费、持续流动;敏捷(Agile)则进一步强调小步快跑、拥抱变化,通过迭代和增量交付缩短反馈环。

类比:瀑布模型像「盖楼前先画完整图纸、封顶才能入住」,改需求等于拆墙重建;敏捷像「先搭毛坯、每两周住进去体验一轮再改」,反馈快但得接受边住边装修。DevOps 则是把「盖楼的设计师」和「入住后的物业」合并成一个团队——你设计的楼,你自己负责它别塌。

DevOps 在敏捷基础上,将开发(Dev)与运维(Ops)之间的壁垒打通,倡导" you build it, you run it “的文化。它不只是工具链的整合,更是组织流程、度量和协作方式的变革。典型的 DevOps 流水线包含:需求管理、代码提交、持续集成(CI)、持续交付(CD)、部署发布、运行监控、反馈改进。

说实话我第一次看 DevOps 流水线图的时候觉得就那么回事儿,等真上手搭过几次才发现,流水线本身就是公司工程文化的镜子——你团队怎么协作,流水线就长什么样。

flowchart LR
    A[瀑布模型
阶段清晰/反馈慢] --> B[精益
消除浪费/持续流动] B --> C[敏捷
小步快跑/拥抱变化] C --> D[DevOps
打通 Dev 与 Ops] D --> E[SRE
用软件工程做运维] E --> F[AIOps
ML/LLM 智能决策]

一条真实流水线长啥样

下面这条是我自己搭过、踩过坑、能跑起来的典型 Web 服务流水线,每个阶段我都标了对应的工具:

[Plan 需求]      Jira / Linear / 飞书项目        ← 工程师拆卡,写 AC
[Code 编码]      Git + GitHub/GitLab             ← feature 分支,commit message 关联 issue
[Build 构建]     Docker buildx + BuildKit        ← 多阶段镜像构建,推 Harbor
[Test 测试]      pytest / go test + SonarQube    ← 单测+覆盖率+静态扫描
[Scan 安全]      Trivy + Grype                   ← 扫镜像 CVE,扫 IaC 配置
[Deploy 部署]    ArgoCD GitOps                   ← 监听 manifest repo,自动 sync
[Verify 验证]    Prometheus + Blackbox Exporter  ← 部署后 smoke test + SLO 检查
[Monitor 监控]   Grafana + Loki + Tempo          ← 指标/日志/链路三件套
[Feedback 反馈]  告警 → On-call → 复盘 → Jira    ← 失败案例回灌成新的需求
flowchart LR
    P[Plan] --> C[Code] --> B[Build] --> T[Test] --> S[Scan]
    S --> D[Deploy] --> V[Verify] --> M[Monitor] --> F[Feedback]
    F -->|回灌新需求| P

Jenkins vs GitLab CI vs ArgoCD

这三个我都被坑过。简单说下区别,省得你选型时再走一遍:

工具定位优点我踩过的坑
Jenkins老牌 CI/CD 引擎插件多,啥都能干Jenkinsfile 一长就乱,master 节点一挂全员瘫痪
GitLab CIGitLab 内置 CI.gitlab-ci.yml 跟代码一起走shared runner 排队能等到天荒地老,得自己搭 runner
ArgoCDGitOps CD 控制器声明式、UI 直观、K8s 原生不是 CI,只管 CD;manifest repo 与代码 repo 解耦后维护成本上升

我个人觉得小团队 GitLab CI 一把梭就够了,CI 和 CD 都能用。规模上来或者要搞 GitOps 就上 ArgoCD,CI 还保留 GitLab CI / GitHub Actions。Jenkins 我现在基本不主动选了,维护成本太高。

下面给一段 GitLab CI 的最小可用配置,CI 阶段构建并推送镜像,CD 阶段更新 manifest repo 触发 ArgoCD:

# .gitlab-ci.yml —— 应用代码 repo 里的配置
stages:
  - build
  - test
  - publish
  - deploy

variables:
  IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA  # 用 commit 短 SHA 做镜像 tag,可追溯

# 构建阶段:用 BuildKit 跑多阶段构建
build:
  stage: build
  image: docker:24
  services:
    - docker:24-dind
  script:
    - docker buildx build -t $IMAGE --push .
  only:
    - main

# 测试阶段:Go 单测 + 覆盖率
test:
  stage: test
  image: golang:1.22
  script:
    - go test -race -coverprofile=coverage.out ./...
    - go tool cover -func=coverage.out
  only:
    - main

# 部署阶段:更新 manifest repo 里的镜像 tag,ArgoCD 监听到变化自动 sync
deploy:
  stage: deploy
  image: alpine/git
  script:
    - git clone https://gitlab-ci-token:$CI_JOB_TOKEN@gitlab.com/team/manifests.git
    - cd manifests
    - sed -i "s|image:.*|image: $IMAGE|" apps/myapp/deployment.yaml
    - git commit -am "chore(myapp): bump to $CI_COMMIT_SHORT_SHA"
    - git push
  only:
    - main

注意 sed 替换镜像 tag 这种写法很糙,生产里我会用 yq 或者 Kustomize 的 images 字段来改,避免误伤其它行。

SRE 与 AIOps 核心概念

SRE(Site Reliability Engineering) 由 Google 提出,主张用软件工程方法解决运维问题。其关键实践包括:

  • SLO/SLI/SLA:用可量化的服务等级目标(SLO)、指标(SLI)和协议(SLA)来管理可靠性。
  • 错误预算:允许在一定范围内发生故障,从而平衡创新速度与稳定性。
  • Toil 管理:将重复性手工操作自动化,降低运维负担。
  • 混沌工程:通过受控故障注入验证系统韧性。

AIOps(Artificial Intelligence for IT Operations) 则是将人工智能,尤其是机器学习和大模型技术,应用于运维数据的分析、决策与自动化执行。Gartner 将 AIOps 定义为结合大数据与机器学习,支持 IT 运维全过程的平台能力。

SLI / SLO / 错误预算:到底怎么算

说实话这三个词刚看的时候很容易混。我后来用一句话记:SLI 是你量的数据,SLO 是你承诺的目标,错误预算是 1 减 SLO 剩下那点 “允许坏掉” 的额度

flowchart LR
    SLI[SLI
你量的数据
成功率] --> SLO[SLO
你承诺的目标
≥99.9%] SLO --> BUD[错误预算
1 - SLO
=0.1% 允许坏掉] BUD -->|烧光| FREEZE[冻结新功能
全员修稳定性]

举个具体数字例子。一个 HTTP API 服务:

  • SLI:成功率 = 1 - http_requests_total{code=~"5.."} / http_requests_total
  • SLO:30 天内成功率 ≥ 99.9%
  • 错误预算:1 - 99.9% = 0.1%

如果月请求量是 1 亿次,那这个月的错误预算就是 10 万次 5xx。一旦 5xx 超过 10 万次,错误预算烧光,新功能上线就得冻结,全员修稳定性。

错误预算的消耗速度比你想的快。我有一次凌晨 Pod OOM 重启了 5 分钟,429 + 500 加起来烧掉了一个月预算的 30%,第二天 SRE 群就炸了。

Sloth 自动生成 SLO 规则

手写 Prometheus SLO 规则巨痛苦,几百行 recording rule 一不小心就写错。我后来直接上 Sloth,它用一份简洁的 YAML 自动生成符合 Prometheus 最佳实践的 recording rule 和 alert rule。

# sloth.yaml —— Sloth 的 SLO 声明
version: "prometheus/v1"
service: "api-gateway"
labels:
  owner: "team-platform"
slos:
  - name: "requests-availability"
    objective: 99.9                    # 99.9% 成功率
    description: "API 网关 5xx 比例 SLO"
    sli:
      events:
        error_query: sum(rate(http_requests_total{job="api-gateway",code=~"5.."}[{{.window}}]))
        total_query: sum(rate(http_requests_total{job="api-gateway"}[{{.window}}]))
    alerting:
      name: ApiGatewayAvailabilityBurnRate
      labels:
        category: availability
      annotations:
        summary: "API 网关可用性错误预算消耗过快"
      page_alert:
        labels:
          severity: pageteam
      ticket_alert:
        labels:
          severity: slack

然后用一条命令生成最终的 Prometheus rule:

sloth generate -i sloth.yaml -o prometheus-slo-rules.yaml

生成的 YAML 里会自动包含 5m/30m/1h/2h/6h/1d 等多个窗口的 multi-window multi-burn-rate 告警规则,比手写靠谱太多。这里有个坑:Sloth 的 error_querytotal_query 里的 {{.window}} 占位符必须保留,它生成时会替换成各个窗口长度,别手贱去改成固定时间。

如果不想引入新工具,纯 Prometheus recording rule 也能写,长这样:

# prometheus-slo-rules.yaml —— 纯手写版(精简)
groups:
  - name: slo-requests-availability
    rules:
      # 5 分钟窗口的 SLO 完成度
      - record: slo:sli_error:ratio_rate5m
        expr: |
          sum(rate(http_requests_total{job="api-gateway",code=~"5.."}[5m]))
          /
          sum(rate(http_requests_total{job="api-gateway"}[5m]))          
      # 错误预算消耗速率
      - record: slo:error_budget:burn_rate5m
        expr: slo:sli_error:ratio_rate5m / (1 - 0.999)
      # 告警:5 分钟 burn rate > 14.4 倍(约 2% 预算/小时)
      - alert: SLOBurnRateHigh
        expr: slo:error_budget:burn_rate5m > 14.4
        for: 2m
        labels:
          severity: pageteam
        annotations:
          summary: "SLO 错误预算消耗速率过高"

Toil 自动化的真实例子

Toil 这个词很 Google,落到日常其实就是那堆"手动又不创造价值"的事。我列几个我亲手干过、后来全部自动化掉的活儿:

  • 证书续期:Let’s Encrypt 证书 90 天到期,每次手动 acme.sh --issue。后来上 cert-manager,CRD 一声明,自动续期,再也忘不了。
  • 磁盘清理:日志盘 80% 告警,登机器 rm -rf /var/log/*.gz。后来写了个 CronJob 跑 logrotate + 上传 OSS,告警基本消失。
  • 扩容缩容:大促前手动 kubectl scale。HPA + Cluster Autoscaler 配好之后,按 QPS 自动扩,准确率比人手判断高。
  • 值班交接:每次发周报手动整理本周告警。后来 Alertmanager 推到 Alertmanager → n8n → 飞书表格,自动出周报。

下面这段 cert-manager 的 Certificate CR 我贴出来,因为这个是我觉得 ROI 最高的 toil 自动化案例:

# certificate.yaml —— Let's Encrypt 自动签发
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: api-gateway-tls
  namespace: prod
spec:
  secretName: api-gateway-tls        # 证书会写到这个 Secret 里
  duration: 2160h                    # 90 天
  renewBefore: 360h                  # 提前 15 天续期,留足失败重试时间
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer
  dnsNames:
    - api.example.com

踩坑提示:renewBefore 别设太短。我设过 24h,结果续期当天 Let’s Encrypt 限流了,证书没续上,第二天直接过期。15 天才是稳妥值。

大模型与 AIOps 的结合关系

大语言模型(LLM)为 AIOps 带来了新的交互与决策能力:

  1. 自然语言接口:运维人员可以用自然语言查询指标、生成查询语句(如 PromQL、SQL)。
  2. 日志/事件摘要:LLM 可对海量日志进行聚类、摘要和根因解释。
  3. 知识沉淀与推理:将 SOP、故障报告、架构文档作为知识库,LLM 可基于 RAG(检索增强生成)进行推理。
  4. 决策 Agent:通过 Function Calling 调用运维 API,实现自动扩容、重启、回滚等动作。

自然语言查 PromQL 的 Prompt 示例

这是我线上在用的一个 prompt 模板,专门做 NL → PromQL。注意我把指标元数据塞进了 system prompt,不塞的话模型会瞎编指标名,比如把 http_requests_total 写成 http_request_count

你是一名资深 SRE,擅长编写 Prometheus PromQL 查询语句。

# 可用指标清单(严格遵守,禁止臆造指标名)
- http_requests_total{job, method, code, path}
- http_request_duration_seconds_bucket{job, le}
- container_cpu_usage_seconds_total{pod, namespace}
- container_memory_working_set_bytes{pod, namespace}
- kube_pod_status_phase{namespace, phase}
- node_cpu_seconds_total{node, mode}

# 用户问题
{user_question}

# 输出要求
1. 只输出一条 PromQL 语句,不要解释
2. 涉及速率统一用 rate(),区间用 [5m]
3. 直方图分位数用 histogram_quantile(0.95, sum by (le)(rate(...[5m])))
4. 如果用户问题涉及不存在的指标,直接回复 "UNSUPPORTED"

举几个真实的 NL → PromQL 例子:

用户问题期望 PromQL
api-gateway 最近的 5xx 比例sum(rate(http_requests_total{job="api-gateway",code=~"5.."}[5m])) / sum(rate(http_requests_total{job="api-gateway"}[5m]))
prod 命名空间 CPU 使用率 P95histogram_quantile(0.95, sum by (le)(rate(container_cpu_usage_seconds_total{namespace="prod"}[5m])))
哪个节点的 idle CPU 最高topk(1, sum by (node)(rate(node_cpu_seconds_total{mode="idle"}[5m])))

踩坑提示:千万别让 LLM 直接执行生成的 PromQL。我有次让它执行 rate(metric[5m]),它把 [5m] 改成 [5d],结果 Prometheus 直接 OOM 了——30 天的高基数指标一拉直接爆内存。正确做法是 LLM 生成 → 校验白名单 → 人在环里点确认 → 才发到 Prometheus。

RAG 故障知识库架构(文字版)

RAG 这块我画过一版文字架构图,大概长这样:

                    ┌─────────────────────────────┐
   运维同学          │  前端:飞书机器人 / Web UI   │
   "订单服务 500"     └──────────────┬──────────────┘
                                     │ 自然语言问题
                    ┌─────────────────────────────┐
                    │  Query Rewriting            │
                    │  把口语改成检索友好的关键词    │
                    └──────────────┬──────────────┘
                                     │ 改写后的 query
              ┌──────────────────────┼──────────────────────┐
              ▼                      ▼                      ▼
   ┌──────────────────┐  ┌────────────────────┐  ┌─────────────────────┐
   │ Embedding Model  │  │ 向量库 Milvus       │  │ 关键词库 ES          │
   │ bge-large-zh     │  │ Top-K 语义召回       │  │ BM25 召回            │
   └──────────────────┘  └────────────────────┘  └─────────────────────┘
              │                      │                      │
              └──────────────────────┼──────────────────────┘
                       ┌──────────────────────────┐
                       │ Reranker(bge-reranker)│
                       │ 精排,取 Top 3           │
                       └──────────────┬───────────┘
                       ┌──────────────────────────┐
                       │ LLM 生成回答              │
                       │ 注入:召回文档 + 告警上下文 │
                       └──────────────┬───────────┘
                       ┌──────────────────────────┐
                       │ 输出:根因分析 + 处置步骤   │
                       │ + 引用来源链接            │
                       └──────────────────────────┘
flowchart TB
    Q[自然语言问题] --> QR[Query Rewriting 改写]
    QR --> E[Embedding + 向量库 Milvus 语义召回]
    QR --> K[关键词库 ES BM25 召回]
    E --> R[Reranker 精排 Top3]
    K --> R
    R --> L[LLM 生成回答
注入召回文档+告警上下文] L --> O[根因分析 + 处置步骤 + 引用来源]

知识源大概是这几类:历史故障复盘文档(Confluence)、SOP runbook(Git 仓库 markdown)、告警历史(Alertmanager webhook 落库)、代码注释(GitLab API 抓)。文档更新走 Airflow 定时任务,每天增量 reindex。

这里有个坑被同事吐槽过:召回的文档不能太长。一开始我把整篇复盘文档塞 prompt,结果 LLM 抓不到重点,回答巨长还没用。后来改成 chunk + reranker,每个 chunk 800 token 左右,rerank 后只给 Top 3,效果立刻好很多。

DevOps、SRE、AIOps 三者的区别与联系

维度DevOpsSREAIOps
核心目标加速交付、打通协作保障可靠性、量化运营智能分析、自动决策
关注阶段开发到交付全流程生产运行与可靠性数据驱动的运维全链路
主要手段CI/CD、自动化、文化变革SLO、错误预算、自动化ML、LLM、可观测数据
关系基础文化与流程框架可靠性工程实践智能化能力增强

三者并非替代关系。DevOps 提供协作框架,SRE 提供可靠性工程方法,AIOps 提供数据与智能决策能力,三者叠加才能构建现代化的运维体系。

我个人觉得小公司别一上来就想着 AIOps。先把 CI/CD 跑顺、SLO 量化起来,再考虑接 LLM。我们团队就是反过来,AIOps 调了一堆大模型 demo,结果 CI 还在手动跑,被领导一句话打回原形:连部署都不稳定,谈什么智能运维。

基础设施即代码(IaC)概述

IaC 是云原生交付的重要支柱,通过声明式配置管理基础设施,实现版本化、可回滚、可复现。主流工具包括:

  • Terraform:HashiCorp 出品的声明式 IaC 工具,通过 Provider 对接多云资源,Module 实现模板复用。
  • Crossplane:基于 Kubernetes CRD 的 IaC 方案,将云资源抽象为 K8s 资源,实现 GitOps 式的平台工程。

Terraform 的核心工作流为 write -> plan -> apply -> destroy,状态文件(state)是管理依赖与变更的关键。通过 workspace 或 workspace + backend 分离,可以实现多环境(dev/staging/prod)隔离。

Crossplane 则更进一步,将基础设施资源纳入 Kubernetes 控制平面,结合 Composition 和 Claim 机制,允许平台团队封装内部 PaaS,实现自服务能力。

Terraform 完整示例:建一个 EKS

下面这份 main.tf 是我实际在用的最小可用 EKS 模板,AWS 官方那个 eks module 巨方便,省掉了一堆 VPC / 子网 / IAM 的手工拼接。

# main.tf —— AWS EKS 最小可用集群
terraform {
  required_version = ">= 1.5"

  # 远端 backend:state 存到 S3,加 DynamoDB 锁
  # 这里有个坑:bucket 和 table 必须先手动建好,terraform 自己管不了 backend 资源
  backend "s3" {
    bucket         = "my-tf-state-prod"
    key            = "eks/prod/terraform.tfstate"
    region         = "ap-northeast-1"
    dynamodb_table = "tf-locks"
    encrypt        = true
  }

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region = "ap-northeast-1"
}

# VPC:用官方 module,开内网 + 公网子网
module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "~> 5.0"

  name = "prod-vpc"
  cidr = "10.0.0.0/16"

  azs             = ["ap-northeast-1a", "ap-northeast-1c"]
  private_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
  public_subnets  = ["10.0.101.0/24", "10.0.102.0/24"]

  enable_nat_gateway   = true
  single_nat_gateway   = true  # 省钱:只开一个 NAT,生产里要 HA 就别用 single
  enable_dns_hostnames = true  # EKS 必须开,否则 CoreDNS 解析有问题
}

# EKS 集群
module "eks" {
  source  = "terraform-aws-modules/eks/aws"
  version = "~> 20.0"

  cluster_name    = "prod-cluster"
  cluster_version = "1.30"

  vpc_id     = module.vpc.vpc_id
  subnet_ids = module.vpc.private_subnets

  enable_irsa = true  # 启用 IRSA,让 Pod 用 IAM Role 而不是 node IAM

  eks_managed_node_groups = {
    general = {
      instance_types = ["t3.large"]
      desired_size   = 2
      min_size       = 1
      max_size       = 4
      disk_size      = 50
    }
  }

  # 坑:cluster_endpoint_public_access 默认是 false,kubectl 连不上
  cluster_endpoint_public_access = true
}

output "cluster_endpoint" {
  value = module.eks.cluster_endpoint
}

工作流就三步:

terraform init      # 拉 provider + 初始化 backend
terraform plan      # 先 dry-run 看变更,重点 review destroy 那一栏
terraform apply     # 确认无误再 apply

踩坑提示:state 文件绝对不能提交 git。我有一次见实习生把 terraform.tfstate 提交到公开 repo,里面明文存了 DB 密码、access key,当天就触发安全告警,全员轮换密钥。正确做法是 state 放 S3/OSS,git 里加 .gitignore

# .gitignore
*.tfstate
*.tfstate.*
crash.log
.terraform/
.terraform.lock.hcl
*.tfvars      # 含密钥的 tfvars 也不进 git,用 *.tfvars.example 做模板

state 漂移与 force-unlock

state 漂移是 Terraform 最头疼的事。常见来源:同事手动在控制台改了资源、AWS 自动加了默认 tag、其它 IaC 工具交叉管理。漂移后 terraform plan 会爆出一堆"鬼变更”。

# 检测漂移
terraform plan -detailed-exitcode    # exit code 2 = 有漂移

# 同步真实状态(不修改云资源,只改 state)
terraform refresh                    # 老命令,新版已废弃
terraform apply -refresh-only        # 新写法,只刷新 state

# 实在拉不回来,手动改 state
terraform state list                 # 看 state 里有哪些资源
terraform state rm aws_xxx.foo       # 从 state 里移除(资源留在云上)
terraform import aws_xxx.foo id      # 把云上已有资源导入 state

force-unlock 是另一个我踩过的大坑。terraform apply 中途网络断了,DynamoDB 锁没释放,下次 plan 直接报 “Error acquiring the state lock”。这种情况只能 force-unlock:

terraform force-unlock <LOCK_ID>     # 强制释放锁

但 force-unlock 是危险操作,必须确认前一个 apply 真的退出了。我有次没确认就 unlock,结果两个 apply 并行跑,state 被写崩,恢复了一晚上。所以 unlock 之前先去 DynamoDB 看一眼 lock 那条记录的 Info 字段,确认是不是僵尸锁。

Crossplane:把云资源变成 K8s CRD

Crossplane 思路不一样,它把 AWS/Azure/GCP 的资源都包装成 K8s 自定义资源(CRD)。你写个 Bucket CR,Crossplane 控制器就去给你建 S3。好处是基础设施和应用都走 kubectl + GitOps 一套流程。

下面是个完整例子:平台团队用 Composition 封装一个"标准存储桶",业务团队只要 Claim 一下就能拿到。

# composition.yaml —— 平台团队定义:标准 S3 桶
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
  name: standard-bucket
  labels:
    provider: aws
spec:
  compositeTypeRef:
    apiVersion: platform.example.com/v1alpha1
    kind: XBucket
  resources:
    - name: bucket
      base:
        apiVersion: s3.aws.crossplane.io/v1beta1
        kind: Bucket
        spec:
          forProvider:
            region: ap-northeast-1
            acl: private
            versioningConfiguration:
              status: Enabled        # 强制开版本控制,防误删
            lifecycleConfiguration:
              rules:
                - id: expire-logs
                  status: Enabled
                  expirationInDays: 30   # 30 天后自动清理
      patches:
        - fromFieldPath: "spec.bucketName"
          toFieldPath: "metadata.annotations[crossplane.io/external-name]"
        - fromFieldPath: "spec.region"
          toFieldPath: "spec.forProvider.region"

业务团队只要写 Claim(跟写 Pod 一样简单):

# claim.yaml —— 业务团队申请一个桶
apiVersion: platform.example.com/v1alpha1
kind: BucketClaim
metadata:
  name: order-service-logs
  namespace: prod
spec:
  bucketName: order-service-logs-prod-2025
  region: ap-northeast-1
kubectl apply -f claim.yaml
kubectl get bucketclaim order-service-logs -n prod -w

踩坑提示:Crossplane 删资源是异步的,kubectl delete bucketclaim 之后云上资源可能还在,Deletion 卡在 Waiting for external resource to be deleted。S3 桶如果非空就删不掉,得先清空对象或者配 lifecycle 规则。生产里我一定会在 Composition 里强制加 lifecycleConfiguration,防止 bucket 永远删不掉。

Terraform vs Crossplane 怎么选

我自己的判断:

  • 基础设施新建、跨云、一次性大量资源:用 Terraform,速度快、生态成熟、本地校验方便。
  • 持续 reconcile、与应用同生命周期、GitOps 流派:用 Crossplane,跟 ArgoCD 配合体验极佳。
  • 混合用:Terraform 建集群本身(VPC/EKS),Crossplane 跑在集群里管业务用的云资源(DB、桶、队列)。这是我现在生产线上的方案。
flowchart TB
    S{资源类型与诉求}
    S -->|新建/跨云/一次性大量| T[Terraform
write→plan→apply] S -->|持续 reconcile/GitOps| C[Crossplane
kubectl + Composition/Claim] S -->|混合| M[Terraform 建底座
+ Crossplane 管业务资源]

总结

云原生基础不仅是容器和 Kubernetes,更是一套围绕 DevOps、SRE、AIOps 的现代化工程体系。理解这些概念之间的演进关系与互补关系,是后续学习 AIOps 实战、Client-go 开发、Operator 开发以及可观测性技术的必要前提。

说真的这一章全是概念,看着最枯燥,但真到后面写 Operator、调 LLM 的时候,回头再看会发现每一步都对得上。DevOps 给你流水线,SRE 给你 SLO,AIOps 在这俩基础上才能落地——不然你 LLM 生成的 PromQL 连指标都没采集,生成的扩容决策连 SLO 都没算,纯属空中楼阁。


自测题与动手练习

自测题(合上书能答出来,才算懂)

  1. 用一句话区分 SLI、SLO、错误预算;并算:某服务 SLO=99.95%、月请求 2 亿次,月度错误预算是多少次 5xx?
  2. 为什么说「只靠网关验证」在 AIOps 语境下不成立?DevOps、SRE、AIOps 三者是替代关系还是叠加关系?
  3. 为什么说 LLM 生成的 PromQL「绝不能直接执行」?正确的「人在环里」流程是什么?
  4. Terraform 的 state 漂移通常由哪些原因引起?terraform force-unlock 为什么是危险操作、执行前必须确认什么?
  5. Terraform 和 Crossplane 的核心工作流有什么本质区别?什么场景适合「混合用」?

动手练习(建议真做一遍)

  1. 写一份 sloth.yaml 描述你的某个服务的 SLO,跑 sloth generate 看生成的 multi-window burn-rate 规则长啥样。
  2. 把你最常用的一个 Prometheus 查询,套进文中的 NL→PromQL prompt 模板,验证模型能否稳定输出正确指标名(而非臆造)。
  3. 写一份最小 main.tf(哪怕只是建一个 S3 bucket),跑 terraform init && terraform plan,体验「dry-run 看变更」再决定要不要 apply。

本章小结

  • 软件交付从瀑布→精益→敏捷→DevOps→SRE→AIOps 持续演进,后者不是替代前者,而是在协作、可靠性、智能三层叠加能力。
  • DevOps 流水线(Plan→…→Feedback)是工程文化的镜子;Jenkins/GitLab CI/ArgoCD 定位不同,小团队 GitLab CI 一把梭,规模上来上 ArgoCD。
  • SLI 是量到的数据、SLO 是承诺的目标、错误预算=1-SLO 是「允许坏掉」的额度;SLO 烧光要冻结新功能。
  • AIOps 用 LLM 做 NL→PromQL、日志摘要、RAG 知识库、决策 Agent,但生成的动作必须「人在环里」确认,绝不能直接自动执行。
  • IaC 是云原生交付支柱:Terraform 走 write→plan→apply、state 是核心且不能提交 git;Crossplane 把云资源变 K8s CRD,适合 GitOps 流派;二者可混合。
  • 下一章起可以顺着这条脉络进入 AIOps 实战、Client-go / Operator 开发与可观测性技术。
About Me

没什么想介绍的,一个很大众的码农…

喜欢代码,车,马,真的是 🐎

讨厌别人让我给自己的代码写注释 最厌烦别人的程序没有写注释

目标

学AI,加油!加油!