- Authors

- Name
- Youngju Kim
- @fjvbn20031
- 引言
- 1. DevOps 基础:CI/CD 流水线
- 2. GitOps 与 Infrastructure as Code
- 3. Kubernetes 完全精通
- 4. 监控与可观测性
- 5. SRE 原则
- 6. AI/ML 工作流自动化
- 7. 安全:RBAC 与 Secrets 管理
- 8. 事件管理
- 结语
- 测验
引言
在现代软件开发中,DevOps 与 SRE(Site Reliability Engineering)已不再是可选项,而是必需品。Netflix 每天部署数千次,Google 为数十亿用户保证 99.99% 的可用性。这背后,是彻底自动化的流水线与数据驱动的运维哲学。
本指南将从 DevOps/SRE 的核心概念出发,到 Kubernetes 实战运维、AI/ML 工作流自动化,结合实战代码为你完全讲透。
1. DevOps 基础:CI/CD 流水线
什么是 CI/CD
CI(Continuous Integration,持续集成)是开发者频繁集成代码、自动构建/测试的实践。CD(Continuous Delivery/Deployment,持续交付/部署)则是将验证通过的代码自动部署到生产环境。
| 分类 | 目的 | 自动化范围 |
|---|---|---|
| CI | 代码集成验证 | 构建、测试、检查 |
| CD (Delivery) | 部署准备 | 自动化到预发布 |
| CD (Deployment) | 自动部署 | 自动化到生产环境 |
用 GitHub Actions 构建 CI/CD
# .github/workflows/ci-cd.yml
name: CI/CD Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
test:
name: Test & Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
cache: 'pip'
- name: Install dependencies
run: |
pip install -r requirements.txt
pip install pytest pytest-cov flake8
- name: Lint with flake8
run: flake8 src/ --max-line-length=88
- name: Run tests
run: pytest tests/ --cov=src --cov-report=xml
- name: Upload coverage
uses: codecov/codecov-action@v4
with:
file: coverage.xml
build:
name: Build & Push Docker Image
runs-on: ubuntu-latest
needs: test
if: github.ref == 'refs/heads/main'
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- name: Log in to Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=sha,prefix=sha-
type=ref,event=branch
type=semver,pattern={{version}}
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
cache-from: type=gha
cache-to: type=gha,mode=max
deploy:
name: Deploy to Kubernetes
runs-on: ubuntu-latest
needs: build
environment: production
steps:
- uses: actions/checkout@v4
- name: Configure kubectl
uses: azure/k8s-set-context@v3
with:
kubeconfig: ${{ secrets.KUBECONFIG }}
- name: Deploy with Helm
run: |
helm upgrade --install my-app ./helm/my-app \
--namespace production \
--set image.tag=${{ github.sha }} \
--wait --timeout=5m
部署策略对比
Blue-Green 部署:同时维持两套完全相同的生产环境(Blue/Green)。将新版本部署到 Green 之后,一次性切换全部流量。回滚是即时的,但需要双倍资源。
Canary 部署:只把一部分流量(例如 5%)路由到新版本,再逐步扩大比例。用真实用户流量做验证,同时把风险降到最低。
# Argo Rollouts Canary 部署示例
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: my-app
spec:
replicas: 10
strategy:
canary:
steps:
- setWeight: 10
- pause: { duration: 5m }
- setWeight: 30
- pause: { duration: 10m }
- setWeight: 60
- pause: { duration: 10m }
- setWeight: 100
canaryService: my-app-canary
stableService: my-app-stable
2. GitOps 与 Infrastructure as Code
GitOps 原则
GitOps 是把 Git 当作 单一事实来源(Single Source of Truth)来使用的运维模型。
- 声明式(Declarative):把系统状态用代码来声明
- 版本管理:所有变更都被 Git 历史记录追踪
- 自动化:Git 变更 → 自动同步
- 可审计:基于 PR 的变更,记录了谁在什么时候、为什么做了改动
代表性工具是 ArgoCD 与 Flux。
用 Terraform 实现 IaC
# main.tf - AWS EKS 集群配置
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
backend "s3" {
bucket = "my-terraform-state"
key = "prod/eks/terraform.tfstate"
region = "ap-northeast-2"
}
}
module "eks" {
source = "terraform-aws-modules/eks/aws"
version = "~> 20.0"
cluster_name = "prod-cluster"
cluster_version = "1.29"
vpc_id = module.vpc.vpc_id
subnet_ids = module.vpc.private_subnets
eks_managed_node_groups = {
general = {
instance_types = ["m5.xlarge"]
min_size = 2
max_size = 10
desired_size = 3
}
gpu = {
instance_types = ["g4dn.xlarge"]
min_size = 0
max_size = 5
desired_size = 1
taints = [{
key = "nvidia.com/gpu"
value = "true"
effect = "NO_SCHEDULE"
}]
}
}
}
3. Kubernetes 完全精通
理解核心资源
Kubernetes 的核心对象整理如下。
| 资源 | 角色 |
|---|---|
| Pod | 执行单元,由一个或多个容器组成 |
| Deployment | 管理 Pod 副本,支持滚动更新 |
| Service | 为一组 Pod 提供网络端点 |
| HPA | 基于 CPU/内存的自动水平扩缩容 |
| ConfigMap | 分离环境变量/配置文件 |
| Secret | 管理敏感信息(密码、令牌) |
| Ingress | 外部 HTTP 流量路由 |
实战 Deployment + HPA 清单
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: ml-inference-api
namespace: production
labels:
app: ml-inference-api
version: v1
spec:
replicas: 3
selector:
matchLabels:
app: ml-inference-api
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
labels:
app: ml-inference-api
version: v1
annotations:
prometheus.io/scrape: 'true'
prometheus.io/port: '8080'
prometheus.io/path: '/metrics'
spec:
containers:
- name: api
image: ghcr.io/myorg/ml-inference-api:sha-abc123
ports:
- containerPort: 8080
env:
- name: MODEL_NAME
valueFrom:
configMapKeyRef:
name: ml-config
key: model_name
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: password
resources:
requests:
cpu: '500m'
memory: '512Mi'
limits:
cpu: '2000m'
memory: '2Gi'
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
---
# hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: ml-inference-api-hpa
namespace: production
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: ml-inference-api
minReplicas: 3
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
- type: Pods
pods:
metric:
name: http_requests_per_second
target:
type: AverageValue
averageValue: '100'
behavior:
scaleUp:
stabilizationWindowSeconds: 60
policies:
- type: Pods
value: 4
periodSeconds: 60
scaleDown:
stabilizationWindowSeconds: 300
用 Helm Chart 管理包
Helm 是 Kubernetes 的包管理器。它把复杂应用的部署过程模板化管理。
# helm/my-app/values.yaml
replicaCount: 3
image:
repository: ghcr.io/myorg/my-app
pullPolicy: IfNotPresent
tag: 'latest'
service:
type: ClusterIP
port: 80
targetPort: 8080
ingress:
enabled: true
className: nginx
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
hosts:
- host: api.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: api-tls
hosts:
- api.example.com
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: 2000m
memory: 2Gi
autoscaling:
enabled: true
minReplicas: 3
maxReplicas: 20
targetCPUUtilizationPercentage: 70
postgresql:
enabled: true
auth:
database: myapp
existingSecret: db-credentials
redis:
enabled: true
architecture: replication
4. 监控与可观测性
可观测性的三大支柱
| 支柱 | 工具 | 用途 |
|---|---|---|
| 指标(Metrics) | Prometheus, Grafana | 数值数据,仪表盘 |
| 日志(Logs) | Loki, Elasticsearch | 事件记录,调试 |
| 追踪(Traces) | Jaeger, Tempo | 分布式请求追踪 |
Prometheus 告警规则
# prometheus-rules.yaml
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: ml-service-alerts
namespace: monitoring
spec:
groups:
- name: ml-service.rules
interval: 30s
rules:
- alert: HighErrorRate
expr: |
sum(rate(http_requests_total{status=~"5.."}[5m]))
/
sum(rate(http_requests_total[5m])) > 0.05
for: 2m
labels:
severity: critical
annotations:
summary: 'High error rate detected'
description: 'Error rate is {{ $value | humanizePercentage }} for the last 5 minutes'
- alert: SlowResponseTime
expr: |
histogram_quantile(0.99,
sum(rate(http_request_duration_seconds_bucket[5m])) by (le, service)
) > 1.0
for: 5m
labels:
severity: warning
annotations:
summary: 'Slow p99 latency'
description: 'p99 latency is {{ $value }}s for {{ $labels.service }}'
- alert: PodCrashLooping
expr: |
increase(kube_pod_container_status_restarts_total[15m]) > 3
for: 0m
labels:
severity: critical
annotations:
summary: 'Pod crash looping'
description: 'Pod {{ $labels.namespace }}/{{ $labels.pod }} is crash looping'
- alert: HighMemoryUsage
expr: |
container_memory_usage_bytes
/
container_spec_memory_limit_bytes > 0.85
for: 5m
labels:
severity: warning
annotations:
summary: 'High memory usage'
OpenTelemetry 埋点
# instrumentation.py
from opentelemetry import trace, metrics
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.metrics import MeterProvider
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
from opentelemetry.instrumentation.requests import RequestsInstrumentor
def setup_telemetry(service_name: str, otlp_endpoint: str):
"""OpenTelemetry 配置"""
# 追踪器设置
tracer_provider = TracerProvider()
otlp_exporter = OTLPSpanExporter(endpoint=otlp_endpoint)
tracer_provider.add_span_processor(BatchSpanProcessor(otlp_exporter))
trace.set_tracer_provider(tracer_provider)
# 指标设置
meter_provider = MeterProvider()
metrics.set_meter_provider(meter_provider)
return trace.get_tracer(service_name)
# 应用到 FastAPI
from fastapi import FastAPI
app = FastAPI()
tracer = setup_telemetry("ml-inference-api", "http://otel-collector:4317")
# 自动埋点
FastAPIInstrumentor.instrument_app(app)
RequestsInstrumentor().instrument()
@app.post("/predict")
async def predict(payload: dict):
with tracer.start_as_current_span("model-inference") as span:
span.set_attribute("model.name", "bert-base")
span.set_attribute("input.length", len(str(payload)))
# 模型推理逻辑
result = run_inference(payload)
span.set_attribute("prediction.confidence", result["confidence"])
return result
5. SRE 原则
SLI / SLO / SLA 层级结构
- SLI(Service Level Indicator):实际测量到的服务性能指标(例如请求成功率、延迟)
- SLO(Service Level Objective):SLI 的目标值(例如 99.9% 可用性)
- SLA(Service Level Agreement):与客户约定的合同水平(通常比 SLO 更宽松)
Error Budget 计算
如果 SLO 是 99.9%,按一个月(30 天)计算,允许的停机时间如下。
Error Budget = 100% - SLO = 0.1%
月度允许停机时间 = 30天 × 24小时 × 60分钟 × 0.1% ≈ 43.2分钟
Error Budget 一旦耗尽,就要停止发布新功能,转而集中精力做稳定性工作。这是 SRE 的核心机制。
| SLO 水平 | 月度允许停机时间 |
|---|---|
| 99% | 7 小时 18 分钟 |
| 99.9% | 43 分 48 秒 |
| 99.99% | 4 分 22 秒 |
| 99.999% | 26 秒 |
降低 Toil 的策略
Toil 指的是手动、重复、可自动化的运维工作。Google SRE 建议把 Toil 控制在总工作时间的 50% 以下。
降低 Toil 的方法:
- 把重复性工作脚本化/自动化
- 把 Runbook(运行手册)转化为自动化代码
- 提升告警质量,降低噪声
- 构建自愈(Self-Healing)系统
6. AI/ML 工作流自动化
用 MLflow 追踪实验
# train.py
import mlflow
import mlflow.sklearn
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score, f1_score
mlflow.set_tracking_uri("http://mlflow-server:5000")
mlflow.set_experiment("fraud-detection-v2")
with mlflow.start_run(run_name="rf-baseline"):
# 记录超参数
params = {"n_estimators": 100, "max_depth": 10, "random_state": 42}
mlflow.log_params(params)
# 训练模型
model = RandomForestClassifier(**params)
model.fit(X_train, y_train)
# 记录指标
y_pred = model.predict(X_test)
mlflow.log_metric("accuracy", accuracy_score(y_test, y_pred))
mlflow.log_metric("f1_score", f1_score(y_test, y_pred))
# 保存模型
mlflow.sklearn.log_model(model, "model",
registered_model_name="fraud-detector")
用 Argo Workflows 构建 ML 流水线
# ml-pipeline.yaml
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
name: ml-training-pipeline
spec:
entrypoint: ml-pipeline
templates:
- name: ml-pipeline
dag:
tasks:
- name: data-prep
template: prepare-data
- name: train
template: train-model
dependencies: [data-prep]
- name: evaluate
template: evaluate-model
dependencies: [train]
- name: deploy
template: deploy-model
dependencies: [evaluate]
- name: prepare-data
container:
image: ghcr.io/myorg/data-prep:latest
command: [python, prepare_data.py]
resources:
requests:
memory: 4Gi
cpu: '2'
- name: train-model
container:
image: ghcr.io/myorg/ml-trainer:latest
command: [python, train.py]
resources:
requests:
memory: 16Gi
cpu: '8'
nvidia.com/gpu: '1'
- name: evaluate-model
container:
image: ghcr.io/myorg/ml-evaluator:latest
command: [python, evaluate.py]
- name: deploy-model
container:
image: ghcr.io/myorg/model-deployer:latest
command: [python, deploy.py]
Python ML 服务的 Dockerfile
# 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 groupadd -r appuser && useradd -r -g appuser appuser
WORKDIR /app
# 从构建阶段复制包
COPY /root/.local /home/appuser/.local
COPY src/ ./src/
COPY models/ ./models/
USER appuser
ENV PATH=/home/appuser/.local/bin:$PATH
ENV PYTHONUNBUFFERED=1
ENV PYTHONDONTWRITEBYTECODE=1
EXPOSE 8080
HEALTHCHECK \
CMD python -c "import requests; requests.get('http://localhost:8080/health').raise_for_status()"
CMD ["uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "8080", "--workers", "4"]
7. 安全:RBAC 与 Secrets 管理
Kubernetes RBAC
# rbac.yaml
# 创建 ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
name: ml-service-account
namespace: production
---
# 最小权限 Role
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: ml-service-role
namespace: production
rules:
- apiGroups: ['']
resources: ['pods', 'services']
verbs: ['get', 'list', 'watch']
- apiGroups: ['']
resources: ['secrets']
resourceNames: ['ml-model-secrets']
verbs: ['get']
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: ml-service-rolebinding
namespace: production
subjects:
- kind: ServiceAccount
name: ml-service-account
namespace: production
roleRef:
kind: Role
apiGroup: rbac.authorization.k8s.io
name: ml-service-role
用 HashiCorp Vault 管理 Secret
# vault_client.py
import hvac
import os
def get_secret(secret_path: str) -> dict:
"""从 Vault 安全地读取密钥"""
client = hvac.Client(
url=os.environ["VAULT_ADDR"],
token=os.environ["VAULT_TOKEN"]
)
if not client.is_authenticated():
raise RuntimeError("Vault 认证失败")
secret = client.secrets.kv.v2.read_secret_version(
path=secret_path,
mount_point="secret"
)
return secret["data"]["data"]
# 在 Kubernetes 中使用 Vault Agent Injector
# 通过 Pod 注解自动注入密钥
用 Network Policy 控制流量
# network-policy.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: ml-service-netpol
namespace: production
spec:
podSelector:
matchLabels:
app: ml-inference-api
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: ingress-nginx
ports:
- protocol: TCP
port: 8080
egress:
- to:
- namespaceSelector:
matchLabels:
name: database
ports:
- protocol: TCP
port: 5432
- to:
- namespaceSelector:
matchLabels:
name: monitoring
ports:
- protocol: TCP
port: 4317 # OTLP gRPC
8. 事件管理
事件响应流程
- 检测(Detection):Prometheus 告警或用户上报
- 分类(Triage):判断严重程度(P1/P2/P3)
- 沟通(Communication):更新状态页面,通知相关方
- 缓解(Mitigation):流量切换、回滚、扩容
- 解决(Resolution):解决根本原因
- 事后复盘(Post-Mortem):撰写 Blameless post-mortem(无责复盘)
写出有效的 Post-Mortem
好的 Post-Mortem 不是聚焦个人责任,而是聚焦 系统改进。
- 详细记录时间线
- 区分根本原因(Root Cause)与触发因素(Trigger)
- 使用 5 Whys 分析法
- 给出具体的行动项(负责人 + 截止日期)
结语
DevOps/SRE 不只是一套工具集合,而是一种 文化与哲学。用自动化减少人为失误,用数据做决策,并通过持续改进来提升系统可靠性。
核心原则总结如下:
- 自动化优先:所有重复性工作都用代码完成
- 可衡量性:用 SLI/SLO 让目标变得清晰
- 快速失败:用 Canary 部署把风险降到最低
- Blameless 文化:改进系统,而不是指责个人
测验
Q1. 在 CI/CD 流水线中,Blue-Green 部署与 Canary 部署有什么区别?
答案:Blue-Green 是同时维持两套完全相同的生产环境、一次性切换全部流量的方式;Canary 是只把一部分流量逐步切换到新版本的方式。
说明:Blue-Green 部署的回滚是即时的(只需切换流量)且没有停机时间,但需要双倍资源。Canary 部署可以用真实用户流量验证新版本、把风险降到最低,但监控更复杂。像 Argo Rollouts 这样的工具两种方式都支持。
Q2. Kubernetes HPA 用来扩缩容的基准指标是什么?
答案:默认基于 CPU 使用率和内存使用率,通过 Custom Metrics API 还可以使用 RPS(每秒请求数)、队列深度等自定义指标。
说明:HPA(HorizontalPodAutoscaler)在 v2 API 中支持 resource、pods、object、external 四种指标类型。设定 CPU 70% 目标后,当前平均 CPU 一旦超过该值就会增加 Pod 数量。安装 Prometheus Adapter 之后,就能把 Prometheus 指标接入 HPA。
Q3. Error Budget 在 SRE 中扮演什么角色?
答案:Error Budget 是 SLO 中定义的可容忍失败量,是在稳定性与功能开发速度之间取得平衡的机制。
说明:如果 SLO 是 99.9%,Error Budget 就是 0.1%。这份预算充足时,可以发布新功能、做实验性变更。预算耗尽后,就要冻结新的发布,集中精力做稳定性改进。借此,开发团队和运维团队能够基于数据协商发布节奏。
Q4. Prometheus 采用 pull 方式采集指标有什么优点?
答案:pull 方式让 Prometheus 能够集中管理抓取目标,配置更简单;目标服务宕机时可以立即察觉;在安全层面也不需要开放防火墙入站规则。
说明:push 方式(如 StatsD、InfluxDB 等)要求每个服务都知道指标服务器的地址,网络出问题时数据可能会丢失。pull 方式下,Prometheus 通过配置文件或服务发现来管理目标,服务的增删因此更灵活。不过,对于生命周期极短的批处理任务,需要借助 Pushgateway。
Q5. GitOps 与传统 CI/CD 有什么区别?
答案:GitOps 把 Git 当作单一事实来源,持续同步声明式状态;而传统 CI/CD 是由流水线直接以命令式方式执行部署。
说明:传统 CI/CD(Jenkins、GitHub Actions)由流水线直接执行 kubectl apply 或 helm upgrade。GitOps(ArgoCD、Flux)持续比较 Git 中的声明式状态与集群的实际状态,并自动同步。GitOps 能够做到漂移检测、自动回滚、完整的审计追踪,而且不需要把集群访问权限交给 CI/CD 系统,从而增强了安全性。