vault backup: 2026-08-08 19:01:04
This commit is contained in:
@@ -0,0 +1,258 @@
|
||||
---
|
||||
tags: [arch/cicd, kubernetes, rolling-update, canary-deployment, hpa, vpa, prometheus, grafana]
|
||||
create time: 2026-08-08 18:00
|
||||
update time: 2026-08-08 18:00
|
||||
---
|
||||
|
||||
# K8s 发布与可观测性体系
|
||||
|
||||
## 概述
|
||||
|
||||
Kubernetes 是现代 CI/CD 体系的编排核心,提供从滚动发布、灰度策略到自动扩缩容的完整能力链。配合 Prometheus + Grafana + 日志采集组件,构成生产级别的可观测性基础设施。本文系统梳理这些组件的设计原理与协作方式。
|
||||
|
||||
## 核心原理
|
||||
|
||||
### 整体架构概览
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
subgraph UserTraffic["用户流量"]
|
||||
U[用户请求] --> INGRESS[Nginx Ingress Controller]
|
||||
end
|
||||
|
||||
subgraph K8sCluster["K8s 集群"]
|
||||
SUBNAME["Service Name: user-service"] --> EP[Endpoint: pod IPs]
|
||||
EP --> P1[Pod A: v2.3.1]
|
||||
EP --> P2[Pod B: v2.3.1]
|
||||
EP --> P3[Pod C: v2.4.0-new]
|
||||
|
||||
DEPLOY[Deployment] -->|管理| P1
|
||||
DEPLOY -->|管理| P2
|
||||
DEPLOY -->|管理| P3
|
||||
|
||||
HPA[Horizontal Pod Autoscaler] -->|扩缩容指令| DEPLOY
|
||||
|
||||
sub kubeSystem["kube-system 组件"]
|
||||
APISERVER[API Server]
|
||||
ETCD[(etcd)]
|
||||
CONTROLLER[M-controller Manager]
|
||||
SCHEDULER[Scheduler]
|
||||
end
|
||||
|
||||
P1 -->|心跳 / metrics| PROMETHEUS[Prometheus TSDB]
|
||||
P2 -->|心跳 / metrics| PROMETHEUS
|
||||
P3 -->|心跳 / metrics| PROMETHEUS
|
||||
P1 -.->Fluentd --> ES[ES / Loki]
|
||||
P2 -.->Fluentd --> ES
|
||||
P3 -.->Fluentd --> ES
|
||||
end
|
||||
|
||||
sub GrafanaUI["可视化层"]
|
||||
GRAFANA[Grafana Dashboard] -->|查询| PROMETHEUS
|
||||
GRAFANA -->|告警规则| ALERTMANAGER[Alertmanager]
|
||||
end
|
||||
|
||||
INGRESS --> SUBNAME
|
||||
```
|
||||
|
||||
### RollingUpdate 策略详解
|
||||
|
||||
K8s Deployment 默认使用 `RollingUpdate` 策略,通过两个参数控制滚动速度:
|
||||
|
||||
| 参数 | 默认值 | 含义 | 影响 |
|
||||
|------|-------|------|------|
|
||||
| maxSurge | 25% | 更新过程中允许超出目标副本数的最大数量 | 控制新 Pod 先启动的数量 |
|
||||
| maxUnavailable | 25% | 更新过程中允许不可用的最大副本数 | 控制旧 Pod 被终止的速度 |
|
||||
|
||||
**两种典型配置对比:**
|
||||
|
||||
| 配置 | 行为 | 适用场景 |
|
||||
|------|-----|---------|
|
||||
| maxSurge=1, maxUnavailable=0 | 逐台升级,零停机 | 对可用性要求极高的生产环境 |
|
||||
| maxSurge=25%, maxUnavailable=25% | 批量快速滚动 | 测试环境或无需保持全量的场景 |
|
||||
|
||||
以 3 副本升级为 4 副本为例(maxSurge=1, maxUnavailable=0):
|
||||
|
||||
```mermaid
|
||||
gantt
|
||||
title RollingUpdate 过程 (3 -> 4 pods, surge=1)
|
||||
dateFormat YYYY-MM-DD
|
||||
axisFormat %H:%M
|
||||
|
||||
section Pod Group
|
||||
old-1 :done, 1, 2026-08-08T00:00, 2026-08-08T00:05
|
||||
old-2 :done, 1, 2026-08-08T00:00, 2026-08-08T00:05
|
||||
old-3 :done, 1, 2026-08-08T00:00, 2026-08-08T00:05
|
||||
new-1 (surge +1) :active, 2026-08-08T00:01, 2026-08-08T00:05
|
||||
old-3 terminate :crit, 2026-08-08T00:06, 2026-08-08T00:07
|
||||
new-2 (surge +1) :active, 2026-08-08T00:07, 2026-08-08T00:11
|
||||
old-2 terminate :crit, 2026-08-08T00:12, 2026-08-08T00:13
|
||||
new-3 (surge +1) :active, 2026-08-08T00:13, 2026-08-08T00:17
|
||||
old-1 terminate :crit, 2026-08-08T00:18, 2026-08-08T00:19
|
||||
new-4 :active, 2026-08-08T00:19, 2026-08-08T00:23
|
||||
```
|
||||
|
||||
**关键约束:就绪探针(Readiness Probe)**
|
||||
- 新 Pod 必须通过 Readiness Probe 才会被加入 Service 的 Endpoint 列表。
|
||||
- 如果 Readiness 失败,即使新 Pod 已运行也不会接收流量。
|
||||
- livenessProbe 用于检测进程是否存活并可能触发重启;readinessProbe 用于决定"这个 Pod 是否可以接受流量"。
|
||||
|
||||
### 蓝绿部署 vs Canary 发布
|
||||
|
||||
| 维度 | RollingUpdate | 蓝绿部署 | Canary 发布 |
|
||||
|------|-------------|---------|------------|
|
||||
| 资源消耗 | 低(增量替换) | 高(需要双倍实例) | 中(少量 Canary 实例) |
|
||||
| 回滚速度 | 慢(需要滚动回去) | 秒级(切换流量即可) | 快(减少 Canary 流量比例) |
|
||||
| 风险 | 低(渐进式) | 中高(全部切到新版本后才发现问题) | 最低(小部分用户先体验) |
|
||||
| 复杂度 | 低(K8s 原生支持) | 中(需要外部 LB 管理) | 高(需要 Istio 或 Nginx 权重配置) |
|
||||
| 适用团队 | 所有规模 | 大团队,有独立预发环境 | 有成熟 DevOps 能力的团队 |
|
||||
|
||||
Canary 发布的流量权重示例(基于 Istio VirtualService):
|
||||
|
||||
```yaml
|
||||
apiVersion: networking.istio.io/v1beta1
|
||||
kind: VirtualService
|
||||
metadata:
|
||||
name: user-service-canary
|
||||
spec:
|
||||
hosts: ["user-service.default.svc.cluster.local"]
|
||||
http:
|
||||
- route:
|
||||
- destination:
|
||||
host: user-service
|
||||
subset: v1
|
||||
weight: 90 # 90% 流量走稳定版
|
||||
- destination:
|
||||
host: user-service
|
||||
subset: v2
|
||||
weight: 10 # 10% 流量进 Canary
|
||||
```
|
||||
|
||||
### HPA — 水平自动扩缩容
|
||||
|
||||
HPA 基于指标监控动态调整 Pod 副本数:
|
||||
|
||||
```go
|
||||
// HPA 核心指标类型
|
||||
type MetricSourceType string
|
||||
|
||||
const (
|
||||
// CPU 利用率(容器内统计)
|
||||
ContainerCPU MetricSourceType = "ContainerResource"
|
||||
// 内存利用率
|
||||
ContainerMemory MetricSourceType = "ContainerResource"
|
||||
// Prometheus 自定义指标(外部指标)
|
||||
External MetricSourceType = "External"
|
||||
// Pods 级别指标(如并发连接数)
|
||||
Pods MetricSourceType = "Pods"
|
||||
)
|
||||
```
|
||||
|
||||
HPA 的计算公式:`targetReplicas = ceil(currentReplicas * (currentMetricValue / desiredMetricValue))`
|
||||
|
||||
例如 CPU 目标 70%,当前平均 CPU 使用率 91%,当前 5 个副本:
|
||||
`ceil(5 * 91 / 70) = ceil(6.5) = 7` → 扩容到 7 个副本。
|
||||
|
||||
> [!WARNING]
|
||||
> HPA 不是实时的——它依赖 metrics-server 每 15~60 秒的采集间隔,扩容动作有分钟级延迟。对于需要即时响应的秒杀场景,应该提前设置 minReplicas >= 预期峰值的 80%。
|
||||
|
||||
### VPA — 垂直自动扩缩容
|
||||
|
||||
VPA 自动调整单个 Pod 的 CPU/Memory requests 和 limits:
|
||||
|
||||
| 模式 | 行为 | 说明 |
|
||||
|------|-----|------|
|
||||
| Offline | 只推荐不应用 | 人工审核后手动调整 |
|
||||
| Initial | 在 Pod 创建时设置建议值 | 对新 Pod 生效 |
|
||||
| Auto | 直接在运行时修改 Pod Spec | 会导致 Pod 被杀掉重建 |
|
||||
| Recreate | 类似 Auto 但先删除旧的再创建 | 保证平滑过渡 |
|
||||
|
||||
VPA 的典型场景:微服务刚上线阶段,运维难以精确预估资源需求,可以让 VPA 学习实际使用模式后给出最优建议。
|
||||
|
||||
### Prometheus 指标采集链路
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
CLIENT_LIB["Client Library<br/>Go SDK / Java SDK / Python SDK"] -->|暴露 /metrics HTTP endpoint| APP_POD["App Pod"]
|
||||
APP_POD -->|HTTP GET /metrics| SCRAPE["Prometheus Scrape"]
|
||||
SCRAPE -->|写入| TSDB["TSDB: Thanos / VictoriaMetrics"]
|
||||
TSDB --> QUERY["PromQL Query Engine"]
|
||||
QUERY --> ALERT["Alert Rule Evaluation"]
|
||||
ALERT -->|告警触发| AM["Alertmanager"]
|
||||
AM -->|Webhook / 邮件 / 钉钉| NOTIFICATION["通知通道"]
|
||||
```
|
||||
|
||||
**核心概念:**
|
||||
- **Counter**:单调递增计数器(如总请求数),适合画 Rate 曲线。
|
||||
- **Gauge**:可上可下的仪表值(如活跃连接数)。
|
||||
- **Histogram**:分桶统计(如请求延迟分布),自动生成 count + sum + bucket。
|
||||
- **Summary**:客户端计算分位数(P50/P99),服务器端不做计算但有额外开销。
|
||||
|
||||
> [!TIP]
|
||||
> 面试常考点:为什么 Prometheus 用 Pull 而不是 Push?因为 Prometheus 作为中心化的采集器天然知道所有 target 的地址,Pull 模式下失联的 service 会自动被忽略(不再收到数据即标记为 down)。如果是 Push 模式(如 StatsD),挂了的服务会停止发送数据但采集器不知道它们已经不存在了。
|
||||
|
||||
### Grafana Dashboard 模板来源
|
||||
|
||||
Grafana 本身不提供指标,它只是可视化层。主要数据来源:
|
||||
|
||||
| 数据源 | 采集内容 | 典型用途 |
|
||||
|--------|---------|---------|
|
||||
| cAdvisor | 容器级别的 CPU/内存/网络/Disk I/O | 容器资源监控 |
|
||||
| kube-state-metrics | Pod/Node/Deployment/RS 的状态元数据 | K8s 资源健康度 |
|
||||
| node-exporter | 宿主机硬件指标(CPU、内存、磁盘、网络) | 节点层面性能分析 |
|
||||
| cadvisor+prometheus | 组合 cAdvisor 和 Prometheus 的指标导出 | 综合容器监控面板 |
|
||||
|
||||
### 日志收集方案
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
PODS["所有 Pod 的 stdout/stderr"] --> FLUENTD["Fluentd / Filebeat DaemonSet"]
|
||||
FLUENTD -->|"Filesystem tail"| LOG_FILES["文件日志"]
|
||||
FLUENTD --> ES_ELB["Elasticsearch Cluster"]
|
||||
FLUENTD --> LOKI["Loki"]
|
||||
ES_ELB --> KIBANA["Kibana"]
|
||||
LOKI --> GRAFANA["Grafana Log Panel"]
|
||||
```
|
||||
|
||||
- **ELK 栈(Elasticsearch + Logstash/Filebeat + Kibana)**:功能最强大,支持全文搜索、聚合分析,但存储成本高(JSON 结构化索引非常占空间)。
|
||||
- **Loki(Grafana 生态)**:不建立全文索引,只索引 Labels。查询时用 label 过滤后再检索日志内容,存储成本极低。适合与 Grafana 深度集成的场景。
|
||||
|
||||
> [!NOTE]
|
||||
> 最佳实践:日志采集应该在 Pod 层面做 sidecar 注入(而非直接写文件),这样即使 Pod 崩溃也能收集到最后一段输出。
|
||||
|
||||
## 代码示例
|
||||
|
||||
Go 中使用 Prometheus Client Library 暴露自定义指标:
|
||||
|
||||
```go
|
||||
import "github.com/prometheus/client_golang/prometheus"
|
||||
|
||||
var requestDuration = prometheus.NewHistogramVec(
|
||||
prometheus.HistogramOpts{
|
||||
Name: "http_request_duration_seconds",
|
||||
Help: "HTTP request duration in seconds",
|
||||
Buckets: prometheus.DefBuckets,
|
||||
},
|
||||
[]string{"method", "path"},
|
||||
)
|
||||
|
||||
func init() {
|
||||
prometheus.MustRegister(requestDuration)
|
||||
}
|
||||
```
|
||||
|
||||
## 实践场景
|
||||
|
||||
**秋招高频问题:**
|
||||
|
||||
- "HPA 能基于自定义业务指标扩缩容吗?" — 可以。通过 Custom Metrics API + adapter(如 prometheus-adapter),HPA 可以从 Prometheus 读取任意业务指标。例如根据 QPS、错误率、或者 Kafka 消费 lag 来触发扩缩容。
|
||||
- "为什么蓝绿部署要双倍资源?" — 蓝绿的本质是同时保留新旧两套完整环境,用负载均衡器切换流量。这保证了随时可以秒级回滚,代价就是付费双倍的生产实例。
|
||||
- "Prometheus 在什么场景下不适合?" — 海量短生命周期任务(如 Serverless 函数,每分钟创销毁成千上万 Pod)。Prometheus 的拉取模型无法跟得上如此动态的变化。此时更适合用 Pushgateway 或改为 push-based 的方案。
|
||||
|
||||
> [!WARNING]
|
||||
> K8s 的 Ready/NotReady 状态切换不会自动通知 HPA——只有当 Pod 处于 Running + Ready 时才计入副本基数。所以在 deployment.yaml 里一定要配好 readiness probe,否则 HPA 会误判当前副本数从而做出错误的扩缩容决策。
|
||||
|
||||
## 关联笔记
|
||||
|
||||
- [[负载均衡算法]]
|
||||
- [[限流熔断降级]]
|
||||
Reference in New Issue
Block a user