Kubernetes核心机制原理
一、Kubelet内部机制
1.1 Kubelet架构总览
┌─────────────────────────────────────────────────────────────────────┐
│ Kubelet 架构 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ Kubelet Core │ │
│ │ │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ PodManager │ │ StatusMngr │ │ VolumeMngr │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ │ │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │PLEG(生命周期)│ │ EvictionMngr│ │ Prober │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ │ │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ SyncLoop │ │ CAdvisor │ │ CertMngr │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌────────────────────────────┼────────────────────────────────┐ │
│ │ CRI Interface │ │
│ │ RuntimeService │ ImageService │ │
│ └────────────────────────────┼────────────────────────────────┘ │
│ │ │
│ ┌──────────┼──────────┐ │
│ ▼ ▼ ▼ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │containerd│ │ CRI-O │ │ Docker │ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
Kubelet核心组件详解
| 组件 | 职责 | 关键源码位置 |
|---|---|---|
| PodManager | Pod生命周期管理,维护期望Pod与实际Pod映射 | pkg/kubelet/pod/pod_manager.go |
| StatusManager | 猪象状态同步至API Server,状态缓存与重试机制 | pkg/kubelet/status/status_manager.go |
| VolumeManager | 卷挂载/卸载,支持多种存储后端 | pkg/kubelet/volumemanager/ |
| PLEG | Pod生命周期事件生成,容器状态变更检测 | pkg/kubelet/pleg/ |
| EvictionManager | 资源压力检测与Pod驱逐决策 | pkg/kubelet/eviction/ |
| Prober | 健康检查执行,Liveness/Readiness/Startup探针 | pkg/kubelet/prober/ |
| SyncLoop | 核心调谐循环,事件驱动的Pod状态收敛 | pkg/kubelet/kubelet.go |
1.2 PLEG(Pod生命周期事件生成器)
┌─────────────────────────────────────────────────────────────────┐
│ PLEG工作流程 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 1. Relist周期(默认1s) │
│ │ │
│ ▼ │
│ 2. 调用CRI获取所有容器状态 │
│ │ │
│ ▼ │
│ 3. 对比当前缓存状态 │
│ │ │
│ ├── 容器新增 → PodStarted事件 │
│ ├── 容器退出 → PodDied事件 │
│ ├── 状态变化 → PodChanged事件 │
│ └── 无变化 → 无事件 │
│ │ │
│ ▼ │
│ 4. 发送事件到SyncLoop │
│ │ │
│ ▼ │
│ 5. SyncLoop处理事件,调谐Pod状态 │
│ │
│ 关键指标: │
│ - kubelet_pleg_relist_duration_seconds │
│ - kubelet_pleg_relist_interval_seconds │
│ - kubelet_pod_start_duration_seconds │
│ │
└─────────────────────────────────────────────────────────────────┘
PLEG性能调优深度解析
问题诊断:PLEG健康检查失败
PLEG is not healthy: pleg was last seen active 3m42.794904855s ago;
threshold is 1m0s
根因分析:
PLEG超时通常由以下原因导致:
| 问题类型 | 症状 | 诊断方法 |
|---|---|---|
| CRI调用阻塞 | relist_duration 异常高 | 检查容器运行时日志、资源使用 |
| 容器数量过多 | 单次relist耗时长 | kubectl get pods --all-namespaces -o wide |
| 磁盘IO瓶颈 | CRI状态查询慢 | iostat -x 1 检查磁盘延迟 |
| 网络存储问题 | Volume挂载/卸载阻塞 | 检查NFS/iSCSI连接状态 |
PLEG源码级工作流程(pkg/kubelet/pleg/generic.go):
// GenericPLEG核心结构
type GenericPLEG struct {
relistPeriod time.Duration // 默认1s
runtime container.Runtime // CRI接口
eventChannel chan *PodLifecycleEvent // 事件通道
podCache cache.Cache // Pod状态缓存
runningPodCache *runningPodCache // 运行中Pod缓存
}
// relist主循环
func (g *GenericPLEG) relist() {
// 1. 获取所有Pod的容器状态(耗时操作)
podList, err := g.runtime.GetPods(true) // 调用CRI ListPodSandbox
// 2. 构建新旧状态对比
newState := getPodsStatus(podList)
oldState := g.podCache.Get()
// 3. 状态差异计算
events := g.generateEvents(oldState, newState)
// 4. 发送事件到SyncLoop
for _, event := range events {
g.eventChannel <- event
}
}
PLEG调优参数(Kubelet启动参数):
# 调整relist周期(默认1s,高密度节点可适当增加)
--pleg-relist-period=2s
# 设置PLEG健康检查阈值(默认1m,生产环境建议不超过3m)
--pleg-relist-duration-threshold=2m
# 并发容器操作数
--container-runtime-threads=4
PLEG性能监控指标详解:
# Prometheus监控规则
groups:
- name: pleg.rules
rules:
- alert: PLEGRelistDurationHigh
expr: histogram_quantile(0.99, rate(kubelet_pleg_relist_duration_seconds_bucket[5m])) > 10
for: 5m
labels:
severity: warning
annotations:
summary: "PLEG relist duration exceeds 10s"
- alert: PLEGNotHealthy
expr: rate(kubelet_pleg_relist_interval_seconds_sum[1m]) == 0
for: 3m
labels:
severity: critical
annotations:
summary: "PLEG has stopped responding"
1.3 SyncLoop核心循环
┌─────────────────────────────────────────────────────────────────┐
│ SyncLoop 调谐循环 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 事件源(Channels): │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Pod更新 │ │ Config更新│ │ 定时同步 │ │ PLEG事件 │ │
│ │ Channel │ │ Channel │ │ Channel │ │ Channel │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │ │ │
│ └─────────────┼─────────────┼─────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌──────────────────────────┐ │
│ │ SyncLoop │ │
│ │ (事件驱动调谐) │ │
│ └────────────┬─────────────┘ │
│ │ │
│ ┌────────────▼─────────────┐ │
│ │ SyncPod │ │
│ │ (单Pod调谐逻辑) │ │
│ └────────────┬─────────────┘ │
│ │ │
│ ┌─────────────────┼─────────────────┐ │
│ ▼ ▼ ▼ │
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
│ │ 计算Pod操作 │ │ 挂载Volume │ │ 启动容器 │ │
│ │ (Kill/Create│ │ │ │ (Init→Main)│ │
│ │ /Update) │ │ │ │ │ │
│ └────────────┘ └────────────┘ └────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
SyncLoop事件处理流程源码级分析
SyncLoop核心数据结构(pkg/kubelet/kubelet.go):
// SyncLoop主循环 - 事件驱动的核心
func (kl *Kubelet) syncLoop(ctx context.Context, updates chan kubetypes.PodUpdate,
handler SyncHandler) {
// 初始化各事件源Channel
syncTicker := time.NewTicker(kl.resyncInterval) // 定期同步
housekeepingTicker := time.NewTicker(kl.housekeepingInterval) // 清理周期
plegCh := kl.pleg.Watch() // PLEG事件
for {
select {
case u, ok := <-updates: // Pod配置更新
kl.syncLoopHandlePodUpdate(u)
case e := <-plegCh: // PLEG事件
kl.syncLoopHandlePLEG(e)
case <-syncTicker.C: // 定期全量同步
kl.syncLoopIteration()
case <-housekeepingTicker.C: // 清理周期
kl.handleHousekeeping()
case <-kl.livenessManager.Updates(): // 存活探针更新
kl.syncLoopHandleLiveness()
}
}
}
// SyncPod操作类型
const (
SyncPodSync SyncPodType = iota // 同步Pod状态
SyncPodCreate // 创建新Pod
SyncPodUpdate // 更新Pod
SyncPodKill // 终止Pod
)
SyncPod完整流程(pkg/kubelet/kubelet_pods.go):
func (kl *Kubelet) syncPod(ctx context.Context, pod *v1.Pod,
mirrorPod *v1.Pod, podStatus *kubecontainer.PodStatus) (result SyncPodResult) {
// 1. 计算Pod操作类型
changeType := kl.computePodAction(pod, podStatus)
// 2. 如果是Kill操作
if changeType == SyncPodKill {
kl.killPod(pod, podStatus)
return
}
// 3. 检查Pod是否可以运行(资源、端口冲突等)
if err := kl.canRunPod(pod); err != nil {
kl.rejectPod(pod, err.Error())
return
}
// 4. 创建/更新Pod沙箱(Pause容器)
sandboxID, err := kl.runtimeService.CreatePodSandbox(ctx, podSandboxConfig)
// 5. 挂载Volume
kl.volumeManager.WaitForAttachAndMount(pod)
// 6. 拉取镜像
for _, container := range pod.Spec.InitContainers {
kl.imageManager.EnsureImageExists(container.Image)
}
// 7. 按顺序启动Init容器
for _, container := range pod.Spec.InitContainers {
kl.runtimeService.CreateContainer(ctx, sandboxID, containerConfig)
kl.runtimeService.StartContainer(ctx, containerID)
kl.waitForContainer(containerID) // 等待Init容器完成
}
// 8. 启动主容器
for _, container := range pod.Spec.Containers {
kl.runtimeService.CreateContainer(ctx, sandboxID, containerConfig)
kl.runtimeService.StartContainer(ctx, containerID)
// 8a. 执行PostStart Hook(阻塞)
if container.Lifecycle != nil && container.Lifecycle.PostStart != nil {
kl.runner.Run(container.Lifecycle.PostStart)
}
}
// 9. 启动探针监控
kl.probeManager.AddPod(pod)
// 10. 更新Pod状态到API Server
kl.statusManager.SetPodStatus(pod, newStatus)
}
SyncLoop事件优先级与并发控制:
┌─────────────────────────────────────────────────────────────────┐
│ SyncLoop事件优先级机制 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 优先级队列 (pkg/kubelet/priorityqueue): │
│ │
│ Priority 1 (最高): PLEG事件 - 容器状态变更 │
│ Priority 2: 存活探针失败事件 │
│ Priority 3: Pod配置更新 │
│ Priority 4: 定期同步 │
│ Priority 5 (最低): 清理任务 │
│ │
│ 并发控制: │
│ --sync-worker-count=1 (默认单worker) │
│ --serialize-image-pulls=true (镜像拉取串行) │
│ --registry-pull-qps=5 (镜像拉取QPS限制) │
│ │
│ 工作流保证: │
│ 1. 同一Pod的事件串行处理 │
│ 2. 不同Pod之间可并行(当worker>1) │
│ 3. Kill操作立即执行 │
│ │
└─────────────────────────────────────────────────────────────────┘
1.4 Kubelet启动Pod完整流程
1. API Server通知Pod分配到本节点
│
2. Kubelet从API Server获取Pod定义
│
3. PodManager注册Pod
│
4. VolumeManager挂载卷
│
5. 计算Pod操作类型(SyncPodKill/SyncPodCreate/SyncPodUpdate)
│
6. 如果是Create:
├── a. 创建CRI沙箱(Pause容器)
├── b. 挂载Volume到沙箱
├── c. 启动Init容器(按顺序)
├── d. 启动主容器
├── e. 执行PostStart Hook
└── f. 启动Liveness/Readiness探针
│
7. 状态上报至API Server
│
8. Prober持续监控容器健康状态
1.5 Kubelet资源预留与QoS管理
系统资源预留配置
# Kubelet Configuration (v1beta1)
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
# 系统守护进程资源预留
systemReserved:
cpu: "500m"
memory: "1Gi"
ephemeral-storage: "10Gi"
# Kubernetes组件资源预留
kubeReserved:
cpu: "500m"
memory: "2Gi"
ephemeral-storage: "10Gi"
# 驱逐阈值
evictionHard:
memory.available: "500Mi"
nodefs.available: "10%"
nodefs.inodesFree: "5%"
imagefs.available: "10%"
evictionSoft:
memory.available: "1Gi"
nodefs.available: "15%"
evictionSoftGracePeriod:
memory.available: "1m30s"
nodefs.available: "2m"
evictionMaxPodGracePeriodSeconds: 60
evictionMinimumReclaim:
memory.available: "200Mi"
nodefs.available: "500Mi"
资源预留计算公式:
Node Allocatable = Node Capacity - System Reserved - Kube Reserved - Eviction Threshold
示例 (32Gi内存节点):
Node Capacity: 32Gi
- System Reserved: 1Gi
- Kube Reserved: 2Gi
- Eviction Hard: 500Mi
────────────────────────────
Node Allocatable: 28.5Gi
QoS服务质量等级详解
┌─────────────────────────────────────────────────────────────────┐
│ Pod QoS等级分类 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Guaranteed (最高优先级): │
│ ├── 条件: 所有容器都设置了CPU/Memory的requests和limits │
│ │ 且 requests == limits │
│ ├── 特点: │
│ │ - 内存不足时最后被驱逐 │
│ │ - CPU资源保证(CFS配额) │
│ │ - 内存不会超过limits(OOM时被kill) │
│ └── cgroup: cpu.cfs_quota_us/cpu.cfs_period_us │
│ memory.limit_in_bytes == memory.soft_limit_in_bytes │
│ │
│ Burstable (中等优先级): │
│ ├── 条件: 至少一个容器设置了requests或limits │
│ │ 但不满足Guaranteed条件 │
│ ├── 特点: │
│ │ - 内存不足时中等优先级驱逐 │
│ │ - CPU可突发使用(requests到limits之间) │
│ │ - 内存可超用但会被OOM Kill │
│ └── cgroup: memory.limit_in_bytes > memory.soft_limit_in_bytes │
│ │
│ BestEffort (最低优先级): │
│ ├── 条件: 所有容器都没有设置requests和limits │
│ ├── 特点: │
│ │ - 内存不足时最先被驱逐 │
│ │ - 无资源保证 │
│ │ - 可使用节点空闲资源 │
│ └── cgroup: 无限制 │
│ │
│ 驱逐顺序 (OOM Score): │
│ BestEffort (-1000) > Burstable (0~999) > Guaranteed (-998) │
│ │
└─────────────────────────────────────────────────────────────────┘
QoS与OOM Score计算(源码分析):
// pkg/kubelet/qos/policy.go
func GetPodOOMScoreAdjust(pod *v1.Pod, machineMemory int64) int {
switch GetPodQOS(pod) {
case Guaranteed:
// OOM Score: -998 (最低优先级被OOM)
return -998
case BestEffort:
// OOM Score: 1000 (最高优先级被OOM)
return 1000
case Burstable:
// 动态计算: 基于内存使用比例
// score = 1000 - (1000 * memoryRequest) / machineMemory
// 范围: 2~999
return int(1000 - (1000*memoryRequest)/machineMemory)
}
}
内存驱逐优先级排序
// pkg/kubelet/eviction/helpers.go
func RankMemoryPressureOrders(pods []*v1.Pod) [][]*v1.Pod {
orders := make([][]*v1.Pod, 3)
// Tier 1: BestEffort Pod
orders[0] = filterPodsByQOS(pods, qos.BestEffort)
// Tier 2: Burstable Pod (按内存使用超用比例排序)
orders[1] = sortBurstableByMemoryOveruse(pods)
// Tier 3: Guaranteed Pod (按内存使用绝对值排序)
orders[2] = sortGuaranteedByMemoryUsage(pods)
return orders
}
二、Watch机制深度解析
2.1 Watch机制原理
┌─────────────────────────────────────────────────────────────────┐
│ Watch机制原理 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ etcd │
│ │ │
│ │ Watch API (基于revision) │
│ ▼ │
│ API Server │
│ │ │
│ │ HTTP Long Polling / Chunked Transfer │
│ │ (Content-Type: application/json) │
│ ▼ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Watch事件流 │ │
│ │ │ │
│ │ {"type":"ADDED","object":{...}} │ │
│ │ {"type":"MODIFIED","object":{...}} │ │
│ │ {"type":"DELETED","object":{...}} │ │
│ │ {"type":"BOOKMARK","object":{...}} │ │
│ │ │ │
│ └──────────────────────────────────────────────────┘ │
│ │ │
│ ├──► Controller Manager (Watch Deployments, Pods等) │
│ ├──► Kubelet (Watch Pods绑定到本节点) │
│ ├──► Scheduler (Watch未调度的Pods) │
│ └──► kubectl get -w (Watch输出) │
│ │
└─────────────────────────────────────────────────────────────────┘
2.2 Watch与List的协同
┌─────────────────────────────────────────────────────────────────┐
│ Informer: List + Watch 机制 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 1. List: 全量获取当前状态 │
│ GET /api/v1/namespaces/default/pods?resourceVersion=0 │
│ → 获取所有Pod及最新resourceVersion │
│ │
│ 2. Watch: 增量监听变化 │
│ GET /api/v1/namespaces/default/pods? │
│ watch=true&resourceVersion=<最新> │
│ → 从resourceVersion开始监听变化 │
│ │
│ 3. Watch断开重连: │
│ → 使用最后收到的resourceVersion重新List+Watch │
│ → 如果resourceVersion过期,重新全量List │
│ │
│ 4. Resync: 周期性(默认30min)重新处理全量对象 │
│ → 确保Informer缓存与etcd一致 │
│ → 不重新List,只是重新触发处理逻辑 │
│ │
└─────────────────────────────────────────────────────────────────┘
2.3 Informer架构
┌─────────────────────────────────────────────────────────────────┐
│ Informer架构 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ API Server │
│ │ │
│ │ List + Watch │
│ ▼ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Reflector │ │
│ │ (负责List/Watch,将对象写入Delta Queue) │ │
│ └──────────────────────┬───────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Delta Queue │ │
│ │ [<obj1, Added>, <obj1, Updated>, <obj2, Deleted>] │ │
│ └──────────────────────┬───────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ SharedInformer │ │
│ │ ┌────────────────┐ ┌────────────────┐ │ │
│ │ │ Indexer(缓存) │ │ Event Handlers│ │ │
│ │ │ (ThreadSafeStore)│ │ OnAdd/OnUpdate│ │ │
│ │ └────────────────┘ │ /OnDelete │ │ │
│ │ └────────────────┘ │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ 多个Controller共享同一Informer(减少API Server压力) │
│ │
└─────────────────────────────────────────────────────────────────┘
Informer性能优化深度解析
Reflector性能优化参数:
// client-go/tools/cache/config.go
type Config struct {
// List-Watch相关参数
ListWatchPageSize int64 // List分页大小,减少单次内存峰值
RelistResyncPeriod time.Duration // 强制重新List周期(0表示禁用)
MinWatchTimeout time.Duration // Watch最小超时时间
// 队列相关参数
QueueInitialSize int // Delta队列初始大小
QueueWithExtraSize int // 额外预留大小
// 重试相关参数
RetryOnWatchErrorFunc func(error) bool // Watch错误重试判断
}
Informer内存优化策略:
// 1. 使用分页List减少内存峰值
func (r *Reflector) List(stopCh <-chan struct{}) error {
listOpts := metav1.ListOptions{
Limit: int64(r.pageSize), // 分页大小,建议500-1000
Continue: "",
}
for {
list, err := r.listerWatcher.List(listOpts)
// 处理当前页...
if list.Continue == "" {
break // 所有页面已处理
}
listOpts.Continue = list.Continue
}
}
// 2. 使用WatchList替代List+Watch(Kubernetes 1.27+)
// 减少List期间的资源版本不一致问题
func (r *Reflector) WatchList(stopCh <-chan struct{}) error {
// 直接从指定版本开始Watch,逐步构建完整列表
// 适用于etcd v3的ProgressNotify特性
}
SharedInformer工厂配置:
// 生产环境推荐配置
informerFactory := informers.NewSharedInformerFactoryWithOptions(
client,
time.Hour, // Resync周期,根据业务稳定性调整
informers.WithNamespace(metav1.NamespaceAll), // 监控所有命名空间
informers.WithTweakListOptions(func(opts *metav1.ListOptions) {
opts.ResourceVersion = "0" // 从缓存读取List
opts.Limit = 500 // 分页大小
}),
)
// 单独配置每个Informer
podInformer := informerFactory.Core().V1().Pods().Informer()
podInformer.SetWatchErrorHandler(func(r *cache.Reflector, err error) {
// 自定义错误处理,监控告警
klog.Errorf("Watch error: %v", err)
})
Resync机制详解
Resync核心原理(源码分析):
// client-go/tools/cache/controller.go
type controller struct {
config Config
reflector *Reflector
resyncPeriod time.Duration
resyncPeriodHandlers []ResyncPeriodHandler
}
// Resync工作流程
func (c *controller) Run(stopCh <-chan struct{}) {
// 启动定期Resync协程
go c.resyncWorker(stopCh)
}
func (c *controller) resyncWorker(stopCh <-chan struct{}) {
ticker := time.NewTicker(c.resyncPeriod)
defer ticker.Stop()
for {
select {
case <-ticker.C:
// 触发全量Resync
c.resync()
case <-stopCh:
return
}
}
}
func (c *controller) resync() {
// 遍历Indexer中所有对象
for _, key := range c.config.Queue.ListKeys() {
obj, exists, err := c.config.Queue.GetByKey(key)
if exists {
// 将对象重新放入Delta队列,类型为Sync
c.config.Queue.Add(Delta{
Type: Sync, // 注意是Sync,不是Added
Object: obj,
})
}
}
}
Resync设计目的与影响:
┌─────────────────────────────────────────────────────────────────┐
│ Resync机制深度分析 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 设计目的: │
│ 1. 解决Handler处理失败后状态不一致问题 │
│ - 某次OnAdd/OnUpdate处理失败 │
│ - Resync会重新触发,提供修复机会 │
│ 2. 处理外部直接修改资源后Informer未感知的情况 │
│ - 绕过API Server直接操作etcd │
│ - 非标准客户端修改 │
│ 3. 周期性状态校验 │
│ │
│ 性能影响: │
│ ┌────────────────────────────────────────────┐ │
│ │ Resync周期 │ 集群对象数 │ Delta队列压力 │ CPU │ │
│ ├────────────────────────────────────────────┤ │
│ │ 10分钟 │ 10000 │ 中等 │ 中 │ │
│ │ 30分钟 │ 10000 │ 低 │ 低 │ │
│ │ 10分钟 │ 100000 │ 高 │ 高 │ │
│ │ 1小时 │ 100000 │ 中等 │ 中 │ │
│ └────────────────────────────────────────────┘ │
│ │
│ 最佳实践: │
│ - 稳定集群: 设置较长周期(1-12小时)或禁用 │
│ - 高可靠性场景: 设置较短周期(10-30分钟) │
│ - 大规模集群: 使用分页List + 适当延长周期 │
│ │
│ 关键代码示例: │
│ // 禁用Resync(某些Controller不需要) │
│ informer, _ := cache.NewSharedInformer( │
│ lw, │
│ &corev1.Pod{}, │
│ 0, // 0表示禁用Resync │
│ ) │
│ │
└─────────────────────────────────────────────────────────────────┘
Watch Bookmarks原理
Bookmarks解决的问题:
问题场景:
Client 1: List at RV=1000, Watch from RV=1000
Client 1 断开连接...
etcd继续写入... RV=2000
Client 1 重连, 请求Watch from RV=1000
但etcd已压缩,RV=1000的数据已不存在
→ 需要重新全量List
Bookmark事件结构:
{
"type": "BOOKMARK",
"object": {
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"resourceVersion": "1500", // 当前最新RV
"name": "", // 空对象
"namespace": ""
}
}
}
Bookmarks启用与工作原理:
// client-go/tools/cache/reflector.go
func (r *Reflector) startWatch(w watch.Interface, rv string) {
// 启用Bookmarks
opts := metav1.ListOptions{
ResourceVersion: rv,
Watch: true,
AllowWatchBookmarks: true, // 启用Bookmarks
}
for {
event, ok := <-w.ResultChan()
switch event.Type {
case watch.Added:
r.store.Add(event.Object)
case watch.Modified:
r.store.Update(event.Object)
case watch.Deleted:
r.store.Delete(event.Object)
case watch.Bookmark:
// 更新本地resourceVersion
// 无需重新List,可继续Watch
rv = event.Object.(*metav1.Object).GetResourceVersion()
}
}
}
Bookmarks配置与效果:
# etcd配置启用Bookmarks
# etcd会定期发送ProgressNotify
etcd:
auto-compaction-retention: 1h
snapshot-count: 10000
┌─────────────────────────────────────────────────────────────────┐
│ Bookmarks优化效果对比 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 未启用Bookmarks: │
│ Watch断开 → resourceVersion过期 → 全量List → 内存峰值 │
│ 集群10000 Pod, List耗时约2-5秒, 内存峰值约500MB │
│ │
│ 启用Bookmarks: │
│ Watch断开 → 使用Bookmark RV → 继续Watch → 无内存峰值 │
│ 重连延迟约100ms, 无内存峰值 │
│ │
│ API Server参数: │
│ --watch-cache-sizes=100#100 # Pod缓存100MB │
│ --default-watch-cache-size=100 # 默认缓存大小 │
│ │
└─────────────────────────────────────────────────────────────────┘
2.4 Indexer高级索引机制
// 自定义索引函数
func indexPodByNodeName(obj interface{}) ([]string, error) {
pod, ok := obj.(*corev1.Pod)
if !ok {
return nil, nil
}
return []string{pod.Spec.NodeName}, nil
}
// 注册索引
indexer.AddIndexers(cache.Indexers{
"node": indexPodByNodeName,
})
// 使用索引查询
podsOnNode1, _ := indexer.ByIndex("node", "node-1")
三、HPA/VPA/CA自动伸缩
3.1 HPA(水平Pod自动伸缩)
HPA工作原理
┌─────────────────────────────────────────────────────────────────┐
│ HPA工作原理 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Metrics Server / Prometheus Adapter │
│ │ │
│ │ 指标查询 │
│ ▼ │
│ ┌──────────────────────────────────────────┐ │
│ │ HPA Controller │ │
│ │ │ │
│ │ 1. 读取当前指标值 │ │
│ │ 2. 计算期望副本数 │ │
│ │ 3. 与当前副本数对比 │ │
│ │ 4. 决定是否扩缩容 │ │
│ └──────────────────────┬───────────────────┘ │
│ │ │
│ ▼ │
│ 更新Deployment副本数 │
│ │
│ 扩缩容算法: │
│ desiredReplicas = ceil[currentReplicas × (currentMetric / targetMetric)]│
│ │
└─────────────────────────────────────────────────────────────────┘
HPA配置示例
# 基于CPU使用率
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: web-app-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: web-app
minReplicas: 2
maxReplicas: 10
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: "1000"
behavior:
scaleUp:
stabilizationWindowSeconds: 60
policies:
- type: Percent
value: 100
periodSeconds: 60
- type: Pods
value: 4
periodSeconds: 60
selectPolicy: Max
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 10
periodSeconds: 60
selectPolicy: Min
HPA扩缩容行为参数
┌─────────────────────────────────────────────────────────────────┐
│ HPA Behavior参数详解 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ scaleUp: │
│ stabilizationWindowSeconds: 60 ← 扩容冷却期 │
│ policies: │
│ - type: Percent ← 按百分比扩容 │
│ value: 100 ← 每分钟最多翻倍 │
│ periodSeconds: 60 │
│ - type: Pods ← 按Pod数扩容 │
│ value: 4 ← 每分钟最多加4个 │
│ periodSeconds: 60 │
│ selectPolicy: Max ← 取最大值 │
│ │
│ scaleDown: │
│ stabilizationWindowSeconds: 300 ← 缩容冷却期(默认5分钟) │
│ policies: │
│ - type: Percent ← 按百分比缩容 │
│ value: 10 ← 每分钟最多减10% │
│ periodSeconds: 60 │
│ selectPolicy: Min ← 取最小值(保守缩容) │
│ │
└─────────────────────────────────────────────────────────────────┘
自定义指标HPA深度解析
Prometheus Adapter部署架构:
┌─────────────────────────────────────────────────────────────────┐
│ 自定义指标HPA架构 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────────┐ │
│ │ Prometheus │────►│ Prometheus │ │
│ │ Server │ │ Adapter │ │
│ └──────────────┘ └────────┬─────────┘ │
│ │ │
│ │ 注册custom.metrics.k8s.io API │
│ ▼ │
│ ┌──────────────────┐ │
│ │ API Aggregation │ │
│ │ Layer │ │
│ └────────┬─────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────┐ │
│ │ HPA Controller │ │
│ └──────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
Prometheus Adapter配置:
# prometheus-adapter-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: prometheus-adapter
data:
config.yaml: |
rules:
# Pod级别指标
- seriesQuery: 'http_requests_total{namespace!="",pod!=""}'
resources:
overrides:
namespace: {resource: "namespace"}
pod: {resource: "pod"}
name:
matches: "^(.*)_total"
as: "${1}_per_second"
metricsQuery: 'sum(rate(<<.Series>>{<<.LabelMatchers>>}[2m])) by (<<.GroupBy>>)'
# 容器级别指标
- seriesQuery: 'container_memory_working_set_bytes{namespace!="",pod!="",container!=""}'
resources:
overrides:
namespace: {resource: "namespace"}
pod: {resource: "pod"}
container: {resource: "container"}
metricsQuery: '<<.Series>>'
# Service级别指标
- seriesQuery: 'nginx_ingress_controller_requests{namespace!="",service!=""}'
resources:
overrides:
namespace: {resource: "namespace"}
service: {resource: "service"}
metricsQuery: 'sum(rate(<<.Series>>{<<.LabelMatchers>>}[1m])) by (<<.GroupBy>>)'
自定义指标HPA完整示例:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: web-app-custom-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: web-app
minReplicas: 3
maxReplicas: 20
metrics:
# 自定义Pod指标 - QPS
- type: Pods
pods:
metric:
name: http_requests_per_second
target:
type: AverageValue
averageValue: "500" # 每Pod 500 QPS
# 自定义对象指标 - 队列长度
- type: Object
object:
metric:
name: queue_length
describedObject:
apiVersion: v1
kind: Service
name: rabbitmq
target:
type: Value
value: "10000" # 队列长度超过10000时扩容
# 外部指标 - 云服务指标
- type: External
external:
metric:
name: aws_sqs_queue_messages_visible
selector:
matchLabels:
queue_name: "my-queue"
target:
type: AverageValue
averageValue: "100"
behavior:
scaleUp:
stabilizationWindowSeconds: 30
policies:
- type: Percent
value: 200
periodSeconds: 30
- type: Pods
value: 10
periodSeconds: 30
selectPolicy: Max
scaleDown:
stabilizationWindowSeconds: 600
policies:
- type: Percent
value: 25
periodSeconds: 120
selectPolicy: Max
多指标聚合策略:
// HPA Controller多指标计算逻辑
func calculateDesiredReplicas(metrics []MetricSpec, currentReplicas int32) int32 {
var maxDesiredReplicas int32 = currentReplicas
for _, metric := range metrics {
desired := calculateForMetric(metric, currentReplicas)
if desired > maxDesiredReplicas {
maxDesiredReplicas = desired
}
}
return maxDesiredReplicas
}
// 多个指标中取最大值,确保任一指标超标都会触发扩容
3.2 VPA(垂直Pod自动伸缩)
VPA架构
┌─────────────────────────────────────────────────────────────────┐
│ VPA架构 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │VPA Recommender│ │VPA Updater │ │VPA Admission │ │
│ │(推荐器) │ │(更新器) │ │(准入控制器) │ │
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │
│ │ │ │ │
│ │ 读取指标 │ 驱逐Pod │ 修改请求 │
│ ▼ ▼ ▼ │
│ Metrics Server 驱逐不符合推荐的Pod 新Pod创建时注入资源 │
│ │
│ 更新模式: │
│ - Off: 仅推荐,不执行 │
│ - Auto: 驱逐+准入(默认) │
│ - Recreate: 立即重建Pod │
│ - Initial: 仅在新Pod创建时应用 │
│ │
└─────────────────────────────────────────────────────────────────┘
VPA配置示例
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: my-app-vpa
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
updatePolicy:
updateMode: Auto
resourcePolicy:
containerPolicies:
- containerName: '*'
minAllowed:
cpu: 100m
memory: 128Mi
maxAllowed:
cpu: "4"
memory: 4Gi
controlledResources: ["cpu", "memory"]
VPA推荐算法详解
┌─────────────────────────────────────────────────────────────────┐
│ VPA Recommender算法原理 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 核心概念: OOM处理安全边界 │
│ │
│ 内存推荐计算: │
│ recommendedMemory = max( │
│ P99(过去8天内存使用峰值), │
│ 历史OOM事件前的内存使用 * 1.5 │
│ ) * safetyMargin │
│ │
│ CPU推荐计算: │
│ recommendedCPU = P95(过去8天CPU使用) * safetyMargin │
│ │
│ 安全边界系数: │
│ - memory: 1.15 (15%安全余量) │
│ - cpu: 1.0 (CPU可压缩,无需额外余量) │
│ │
│ 历史数据来源: │
│ 1. Prometheus长期存储 │
│ 2. VPA内置历史数据(8天窗口) │
│ 3. 实时Metrics Server数据 │
│ │
│ 推荐值输出格式: │
│ ┌────────────────────────────────────────┐ │
│ │ Target: 推荐值(理想值) │ │
│ │ LowerBound: 下限(低于此值不推荐) │ │
│ │ UpperBound: 上限(高于此值不推荐) │ │
│ │ UncappedTarget: 无限制推荐值 │ │
│ └────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
VPA推荐值获取:
# 查看VPA推荐值
kubectl get vpa my-app-vpa -o yaml
# 输出示例
status:
recommendation:
containerRecommendations:
- containerName: app
target:
cpu: "500m"
memory: "512Mi"
lowerBound:
cpu: "250m"
memory: "256Mi"
upperBound:
cpu: "2"
memory: "2Gi"
uncappedTarget:
cpu: "450m"
memory: "480Mi"
3.3 CA(集群自动伸缩)
CA工作原理
┌─────────────────────────────────────────────────────────────────┐
│ Cluster Autoscaler工作原理 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 扩容触发: │
│ ┌──────────────────────────────────────────────┐ │
│ │ Pod处于Pending状态 │ │
│ │ → 调度失败(资源不足) │ │
│ │ → CA评估是否可以扩容 │ │
│ │ → 调用云Provider API创建新Node │ │
│ └──────────────────────────────────────────────┘ │
│ │
│ 缩容触发: │
│ ┌──────────────────────────────────────────────┐ │
│ │ Node资源利用率低(默认<50%) │ │
│ │ → CA评估Node上Pod是否可以迁移 │ │
│ │ → 排除受保护的Pod( PDB/annotation) │ │
│ │ → 驱逐Pod,删除Node │ │
│ └──────────────────────────────────────────────┘ │
│ │
│ 缩容安全机制: │
│ - Pod Disruption Budget (PDB) │
│ - cluster-autoscaler.kubernetes.io/safe-to-evict: "false" │
│ - kube-system命名空间的Pod │
│ - 非ReplicaSet管理的Pod │
│ - 本地存储Pod │
│ │
└─────────────────────────────────────────────────────────────────┘
CA多云扩展策略
多云CA架构:
┌─────────────────────────────────────────────────────────────────┐
│ Cluster Autoscaler多云架构 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────┐ │
│ │ Cluster API │ │
│ │ Management │ │
│ └────────┬─────────┘ │
│ │ │
│ ┌──────────────────┼──────────────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
│ │ AWS ASG │ │ GCP MIG │ │ Azure VMSS │ │
│ │ Provider │ │ Provider │ │ Provider │ │
│ └─────┬──────┘ └─────┬──────┘ └─────┬──────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
│ │ Node Group │ │ Node Group │ │ Node Group │ │
│ │ (us-east) │ │ (europe) │ │ (asia) │ │
│ └────────────┘ └────────────┘ └────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
AWS Auto Scaling Group配置:
# Cluster Autoscaler多云部署 - AWS
apiVersion: apps/v1
kind: Deployment
metadata:
name: cluster-autoscaler
namespace: kube-system
spec:
template:
spec:
containers:
- image: k8s.gcr.io/autoscaling/cluster-autoscaler:v1.27.0
name: cluster-autoscaler
command:
- ./cluster-autoscaler
- --cloud-provider=aws
- --node-groups-auto-discovery=asg:tag=k8s.io/cluster-autoscaler/enabled
- --scale-down-unneeded-time=10m
- --scale-down-delay-after-add=10m
- --scale-down-delay-after-failure=3m
- --scale-down-delay-after-delete=10s
- --balance-similar-node-groups
- --expander=priority # 多节点组优先级策略
env:
- name: AWS_REGION
value: us-east-1
CA Expander策略详解:
# 扩展策略选项
--expander=random # 随机选择可扩展的节点组(默认)
--expander=most-pods # 选择能调度最多Pod的节点组
--expander=least-waste # 选择扩容后资源浪费最少的节点组
--expander=priority # 按优先级选择(需要Priority配置)
--expander=price # 选择成本最低的节点组
节点组优先级配置:
apiVersion: v1
kind: ConfigMap
metadata:
name: cluster-autoscaler-priority-expander
namespace: kube-system
data:
priorities: |-
10:
- .*-spot-.*
20:
- .*-on-demand-.*
30:
- .*-gpu-.*
# 优先扩容Spot实例,其次是On-Demand,最后是GPU节点
多云场景CA配置:
# 多云扩展配置示例
# 支持多Node Group的CA配置
apiVersion: apps/v1
kind: Deployment
metadata:
name: cluster-autoscaler
namespace: kube-system
spec:
template:
spec:
containers:
- name: cluster-autoscaler
command:
- ./cluster-autoscaler
- --cloud-provider=clusterapi
- --node-group-auto-discovery=clusterapi:selector=k8s.io/cluster-autoscaler/node-group
# 多云扩展参数
- --balance-similar-node-groups=true
- --ignore-taint=true
- --max-node-provision-time=15m
- --nodes=1:10:cluster-api-group-worker-us-east
- --nodes=1:10:cluster-api-group-worker-europe
- --nodes=1:10:cluster-api-group-worker-asia
3.4 HPA/VPA/CA协同策略
| 维度 | HPA | VPA | CA |
|---|---|---|---|
| 伸缩方向 | 水平(副本数) | 垂直(资源) | 节点数 |
| 触发条件 | 指标超阈值 | 资源不匹配 | Pod Pending/Node空闲 |
| 业务影响 | 无(新增Pod) | 有(需重启) | 有(Pod迁移) |
| 响应速度 | 秒级 | 分钟级 | 分钟级 |
| 适用场景 | 无状态应用 | 资源不确定 | 集群容量 |
VPA与HPA协同最佳实践
协同原则:避免资源维度冲突
# 方案1: HPA使用自定义指标,VPA管理CPU/Memory
# HPA配置
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: app-hpa
spec:
metrics:
- type: Pods
pods:
metric:
name: http_requests_per_second # 自定义指标
target:
type: AverageValue
averageValue: "1000"
# 不配置CPU/Memory指标
---
# VPA配置
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: app-vpa
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: app
updatePolicy:
updateMode: Auto
resourcePolicy:
containerPolicies:
- containerName: app
controlledResources: ["cpu", "memory"] # VPA管理资源
方案2: VPA仅推荐模式 + HPA管理CPU
# VPA配置 - 仅推荐模式
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: app-vpa-recommend
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: app
updatePolicy:
updateMode: Off # 仅推荐,不自动更新
resourcePolicy:
containerPolicies:
- containerName: app
controlledResources: ["memory"] # 仅推荐内存
---
# HPA配置 - 管理CPU
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: app-hpa
spec:
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
协同冲突检测与解决:
┌─────────────────────────────────────────────────────────────────┐
│ HPA/VPA协同冲突检测机制 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 冲突场景: │
│ 1. HPA基于CPU扩容,VPA同时调整CPU → 无限循环 │
│ HPA扩容 → CPU使用下降 → VPA降配 → CPU使用上升 → HPA扩容... │
│ │
│ 2. HPA基于Memory扩容,VPA调整Memory → 同样循环 │
│ │
│ 解决方案: │
│ ┌───────────────────────────────────────────────────┐ │
│ │ 方案 │ HPA指标 │ VPA管理资源 │ │
│ ├───────────────────────────────────────────────────┤ │
│ │ 推荐配置 │ 自定义指标 │ CPU + Memory │ │
│ │ 替代配置 │ CPU │ Memory Only │ │
│ │ 混合配置 │ Memory │ CPU Only │ │
│ └───────────────────────────────────────────────────┘ │
│ │
│ VPA推荐值作为HPA资源请求参考: │
│ - 定期查看VPA推荐值 │
│ - 手动/自动更新Deployment资源请求 │
│ - HPA基于新资源请求计算副本数 │
│ │
└─────────────────────────────────────────────────────────────────┘
自动化协同脚本示例:
#!/bin/bash
# vpa-recommender-to-hpa.sh
# 将VPA推荐值应用到Deployment,避免与HPA冲突
DEPLOYMENT="my-app"
NAMESPACE="default"
# 获取VPA推荐值
CPU_REC=$(kubectl get vpa ${DEPLOYMENT}-vpa -n ${NAMESPACE} -o jsonpath='{.status.recommendation.containerRecommendations[0].target.cpu}')
MEM_REC=$(kubectl get vpa ${DEPLOYMENT}-vpa -n ${NAMESPACE} -o jsonpath='{.status.recommendation.containerRecommendations[0].target.memory}')
# 更新Deployment资源请求
kubectl set resources deployment/${DEPLOYMENT} -n ${NAMESPACE} \
--requests=cpu=${CPU_REC},memory=${MEM_REC} \
--limits=cpu=${CPU_REC},memory=${MEM_REC}
四、CRD/Operator模式
4.1 CRD(自定义资源定义)
CRD定义结构
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: applications.app.example.com
spec:
group: app.example.com
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
replicas:
type: integer
minimum: 1
maximum: 100
image:
type: string
config:
type: object
x-kubernetes-preserve-unknown-fields: true
status:
type: object
properties:
phase:
type: string
enum: [Pending, Running, Failed]
conditions:
type: array
items:
type: object
properties:
type:
type: string
status:
type: string
lastTransitionTime:
type: string
subresources:
status: {}
scale:
specReplicasPath: .spec.replicas
statusReplicasPath: .status.replicas
additionalPrinterColumns:
- name: Replicas
type: integer
jsonPath: .spec.replicas
- name: Phase
type: string
jsonPath: .status.phase
scope: Namespaced
names:
plural: applications
singular: application
kind: Application
shortNames: [app]
CRD Validation深度解析
OpenAPI v3 Schema验证详解:
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: databases.db.example.com
spec:
group: db.example.com
versions:
- name: v1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: ["spec"] # 必填字段
properties:
spec:
type: object
required: ["version", "storage"]
properties:
# 字符串验证
version:
type: string
pattern: "^v[0-9]+\\.[0-9]+\\.[0-9]+$" # 正则验证
enum: ["v1.0.0", "v1.1.0", "v2.0.0"] # 枚举值
# 数值验证
storage:
type: string
pattern: "^[0-9]+(Gi|Mi)$"
# 自定义验证在validationRules中实现
# 嵌套对象验证
backup:
type: object
properties:
enabled:
type: boolean
schedule:
type: string
pattern: "^(@(annually|yearly|monthly|weekly|daily|hourly)|((([0-9]{1,2}|\\*)\\s){4}([0-9]{1,2}|\\*)))$"
retention:
type: integer
minimum: 1
maximum: 365
# 数组验证
users:
type: array
minItems: 1
maxItems: 100
items:
type: object
required: ["name", "databases"]
properties:
name:
type: string
minLength: 1
maxLength: 63
databases:
type: array
items:
type: string
permissions:
type: array
items:
type: string
enum: ["SELECT", "INSERT", "UPDATE", "DELETE", "ALL"]
# 资源引用验证
secretRef:
type: object
required: ["name"]
properties:
name:
type: string
namespace:
type: string
# 保留未知字段(用于灵活配置)
extraConfig:
type: object
x-kubernetes-preserve-unknown-fields: true
x-kubernetes-validations:
- rule: "self.size() <= 100" # CEL验证
message: "extraConfig cannot have more than 100 keys"
status:
type: object
properties:
phase:
type: string
enum: ["Creating", "Running", "Updating", "Failed"]
conditions:
type: array
items:
type: object
required: ["type", "status"]
properties:
type:
type: string
status:
type: string
enum: ["True", "False", "Unknown"]
reason:
type: string
message:
type: string
maxLength: 32768 # 最大消息长度
# CEL验证规则(Kubernetes 1.29+)
validations:
- expression: "self.spec.storage.endsWith('Gi') ? int(self.spec.storage.replace('Gi', '')) >= 10 : true"
message: "Storage must be at least 10Gi when using Gi suffix"
CEL验证表达式详解:
# Kubernetes 1.25+ 支持CEL表达式验证
x-kubernetes-validations:
# 跨字段验证
- rule: "self.spec.minReplicas <= self.spec.maxReplicas"
message: "minReplicas must be less than or equal to maxReplicas"
# 条件验证
- rule: "self.spec.highAvailability.enabled == true ? has(self.spec.highAvailability.replicas) : true"
message: "replicas must be specified when highAvailability is enabled"
# 数组元素验证
- rule: "self.spec.ports.all(port, port.containerPort > 0 && port.containerPort < 65536)"
message: "containerPort must be between 1 and 65535"
# 字符串操作
- rule: "self.metadata.name.startsWith('prod-') || self.metadata.namespace == 'dev'"
message: "Production resources must have names starting with 'prod-'"
# 复杂业务逻辑
- rule: |
self.spec.tls.enabled == true ?
(has(self.spec.tls.certSecret) && has(self.spec.tls.keySecret)) :
true
message: "Both certSecret and keySecret must be specified when TLS is enabled"
CRD Webhook验证
// Custom Resource Validation Webhook
package main
import (
"encoding/json"
"net/http"
admissionv1 "k8s.io/api/admission/v1"
)
type ValidationWebhook struct{}
func (v *ValidationWebhook) ServeHTTP(w http.ResponseWriter, r *http.Request) {
var admissionReview admissionv1.AdmissionReview
json.NewDecoder(r.Body).Decode(&admissionReview)
// 解析CR对象
var cr CustomResource
json.Unmarshal(admissionReview.Request.Object.Raw, &cr)
// 执行验证逻辑
var warnings []string
allowed := true
reason := ""
// 示例:验证跨命名空间引用
if cr.Spec.SecretRef.Namespace != "" && cr.Spec.SecretRef.Namespace != admissionReview.Request.Namespace {
allowed = false
reason = "Cross-namespace secret references are not allowed"
}
// 示例:验证资源配额
if cr.Spec.CPU > "4" && cr.Spec.Replicas > 10 {
warnings = append(warnings, "High CPU and replica count may exceed namespace quota")
}
// 构建响应
response := admissionv1.AdmissionReview{
TypeMeta: admissionReview.TypeMeta,
Response: &admissionv1.AdmissionResponse{
UID: admissionReview.Request.UID,
Allowed: allowed,
Result: &metav1.Status{Reason: metav1.StatusReason(reason)},
Warnings: warnings,
},
}
json.NewEncoder(w).Encode(response)
}
4.2 Operator设计模式
Operator核心组件
┌─────────────────────────────────────────────────────────────────┐
│ Operator架构模式 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Operator Controller │ │
│ │ │ │
│ │ ┌────────────┐ ┌────────────┐ ┌────────────┐ │ │
│ │ │ Informer │ │ Reconcile │ │ Action │ │ │
│ │ │ (Watch CR) │─►│ (调谐逻辑) │─►│ (执行操作) │ │ │
│ │ └────────────┘ └────────────┘ └────────────┘ │ │
│ │ │ │ │ │ │
│ │ ▼ ▼ ▼ │ │
│ │ 事件驱动 期望vs实际 CRUD子资源 │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ 框架选择: │
│ ├── Kubebuilder (官方推荐,脚手架) │
│ ├── Operator SDK (Red Hat,含OLM支持) │
│ ├── Kopf (Python) │
│ └── Metacontroller (无代码Operator) │
│ │
└─────────────────────────────────────────────────────────────────┘
Reconcile循环伪代码
func (r *ApplicationReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
// 1. 获取CR实例
var app appv1alpha1.Application
if err := r.Get(ctx, req.NamespacedName, &app); err != nil {
return ctrl.Result{}, client.IgnoreNotFound(err)
}
// 2. 计算期望状态
desiredDeployment := r.constructDeployment(&app)
desiredService := r.constructService(&app)
// 3. 获取实际状态并调谐
// 3a. 调谐Deployment
var existingDeploy appsv1.Deployment
err := r.Get(ctx, req.NamespacedName, &existingDeploy)
if err != nil && errors.IsNotFound(err) {
// 创建
if err := r.Create(ctx, desiredDeployment); err != nil {
return ctrl.Result{}, err
}
} else if err == nil {
// 更新
if !reflect.DeepEqual(existingDeploy.Spec, desiredDeployment.Spec) {
existingDeploy.Spec = desiredDeployment.Spec
if err := r.Update(ctx, &existingDeploy); err != nil {
return ctrl.Result{}, err
}
}
}
// 3b. 调谐Service (同上)
// 4. 更新CR状态
app.Status.Phase = "Running"
if err := r.Status().Update(ctx, &app); err != nil {
return ctrl.Result{}, err
}
// 5. 决定是否Requeue
return ctrl.Result{RequeueAfter: 30 * time.Second}, nil
}
Operator SDK深度对比
┌─────────────────────────────────────────────────────────────────┐
│ Operator SDK框架对比分析 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────┐│
│ │ Kubebuilder (官方推荐) ││
│ ├─────────────────────────────────────────────────────────────┤│
│ │ 优点: ││
│ │ - 原生Controller Runtime,性能最优 ││
│ │ - 完善的CRD生成与安装支持 ││
│ │ - 内置Webhook支持 ││
│ │ - 活跃社区,Kubernetes官方维护 ││
│ │ 缺点: ││
│ │ - 学习曲线陡峭 ││
│ │ - 无OLM集成(需手动配置) ││
│ │ 适用场景: 核心基础设施Operator,高性能需求 ││
│ └─────────────────────────────────────────────────────────────┘│
│ │
│ ┌─────────────────────────────────────────────────────────────┐│
│ │ Operator SDK (Red Hat) ││
│ ├─────────────────────────────────────────────────────────────┤│
│ │ 优点: ││
│ │ - 内置OLM支持,易于打包发布 ││
│ │ - 支持Ansible/Helm/Go三种模式 ││
│ │ - 完善的测试框架(EnvTest/Scorecard) ││
│ │ - Red Hat企业支持 ││
│ │ 缺点: ││
│ │ - 相对重量级 ││
│ │ - 依赖OLM生态 ││
│ │ 适用场景: 企业级Operator,需要OLM分发的场景 ││
│ └─────────────────────────────────────────────────────────────┘│
│ │
│ ┌─────────────────────────────────────────────────────────────┐│
│ │ Kopf (Python) ││
│ ├─────────────────────────────────────────────────────────────┤│
│ │ 优点: ││
│ │ - Python生态友好,开发效率高 ││
│ │ - 轻量级,无需编译 ││
│ │ - 异步框架,性能良好 ││
│ │ 缺点: ││
│ │ - 非官方,社区较小 ││
│ │ - 不支持Webhook ││
│ │ 适用场景: 快速原型开发,数据处理类Operator ││
│ └─────────────────────────────────────────────────────────────┘│
│ │
│ ┌─────────────────────────────────────────────────────────────┐│
│ │ Metacontroller ││
│ ├─────────────────────────────────────────────────────────────┤│
│ │ 优点: ││
│ │ - 无需编写Controller代码 ││
│ │ - JSON配置即可定义Operator ││
│ │ - 学习成本最低 ││
│ │ 缺点: ││
│ │ - 灵活性有限 ││
│ │ - 性能不如原生实现 ││
│ │ 适用场景: 简单CRD,快速验证概念 ││
│ └─────────────────────────────────────────────────────────────┘│
│ │
└─────────────────────────────────────────────────────────────────┘
Controller Runtime原理深度解析
Controller Runtime核心架构:
// sigs.k8s.io/controller-runtime/pkg/controller/controller.go
type Controller struct {
Name string
MaxConcurrentReconciles int // 并发Reconcile数量
Reconcile reconcile.Reconciler
Cache cache.Cache
Client client.Client
Scheme *runtime.Scheme
// 事件过滤与处理
source source.Source
handler handler.EventHandler
}
// Manager - 管理多个Controller的生命周期
type Manager interface {
Add(Runnable) error
GetClient() client.Client
GetCache() cache.Cache
GetScheme() *runtime.Scheme
GetEventRecorderFor(name string) record.EventRecorder
Start(ctx context.Context) error
}
Controller Runtime工作流程:
┌─────────────────────────────────────────────────────────────────┐
│ Controller Runtime工作流程 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 1. 初始化阶段 │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ mgr, _ := ctrl.NewManager(cfg, ctrl.Options{ │ │
│ │ Scheme: scheme, │ │
│ │ MetricsBindAddress: ":8080", │ │
│ │ Port: 9443, // Webhook端口 │ │
│ │ }) │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ 2. Controller注册 │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ err := ctrl.NewControllerManagedBy(mgr). │ │
│ │ For(&appsv1.Deployment{}). │ │
│ │ Owns(&corev1.Pod{}). │ │
│ │ Complete(&DeploymentReconciler{Client: mgr.GetClient()})│
│ └──────────────────────────────────────────────────────┘ │
│ │
│ 3. 事件处理链 │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Source (Kind/Predicate) │ │
│ │ ↓ │ │
│ │ EventHandler (EnqueueRequestForObject) │ │
│ │ ↓ │ │
│ │ WorkQueue (rateLimitingInterface) │ │
│ │ ↓ │ │
│ │ Reconcile Loop (并发处理) │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ 4. Reconcile结果处理 │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Result{Requeue: true} → 立即重新入队 │ │
│ │ Result{RequeueAfter: 1min} → 延迟重新入队 │ │
│ │ Result{} → 完成,不重新入队 │ │
│ │ error → 指数退避重试 │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
事件过滤器与谓词:
// 自定义事件过滤谓词
type ResourcePredicate struct {
predicate.Funcs
}
func (p *ResourcePredicate) Create(e event.CreateEvent) bool {
// 只处理带有特定标签的资源
return e.Object.GetLabels()["app.kubernetes.io/managed-by"] == "my-operator"
}
func (p *ResourcePredicate) Update(e event.UpdateEvent) bool {
// 只在Generation变化时触发(忽略Status更新)
return e.ObjectOld.GetGeneration() != e.ObjectNew.GetGeneration()
}
func (p *ResourcePredicate) Delete(e event.DeleteEvent) bool {
// 确认删除事件处理
return !e.DeleteStateUnknown
}
// 注册Controller时使用
ctrl.NewControllerManagedBy(mgr).
For(&appsv1.Deployment{}, builder.WithPredicates(&ResourcePredicate{})).
Complete(&DeploymentReconciler{})
并发与限流配置:
// 生产级Controller配置
ctrl.NewControllerManagedBy(mgr).
For(&appsv1.Deployment{}).
Owns(&corev1.Pod{}).
WithOptions(controller.Options{
MaxConcurrentReconciles: 10, // 并发数
RateLimiter: workqueue.NewTypedMaxOfRateLimiter(
workqueue.NewTypedItemExponentialFailureRateLimiter[reconcile.Request](5*time.Second, 1000*time.Second),
&workqueue.TypedBucketRateLimiter[reconcile.Request]{Limiter: goproxy.Limit(10, time.Second)},
),
CacheSyncTimeout: 2 * time.Minute,
RecoverPanic: true,
}).
Complete(&DeploymentReconciler{})
4.3 Operator成熟度模型
┌─────────────────────────────────────────────────────────────────┐
│ Operator成熟度模型 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Level 5: Auto Pilot │
│ ├── 自愈+自动伸缩+自动调优 │
│ └── AI驱动的运维决策 │
│ ▲ │
│ Level 4: Deep Insights │
│ ├── 告警+异常检测+容量规划 │
│ └── 基于指标的自动调优 │
│ ▲ │
│ Level 3: Seamless Upgrades │
│ ├── 滚动升级+回滚+数据迁移 │
│ └── 多版本共存 │
│ ▲ │
│ Level 2: Seamless Cluster Lifecycle │
│ ├── 备份恢复+故障转移 │
│ └── 集群扩缩容 │
│ ▲ │
│ Level 1: Basic Install │
│ ├── 安装+配置+基本CRD │
│ └── 手动运维 │
│ │
└─────────────────────────────────────────────────────────────────┘
五、滚动更新机制
5.1 Deployment滚动更新原理
┌─────────────────────────────────────────────────────────────────┐
│ Deployment滚动更新流程 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 初始状态: │
│ ReplicaSet-v1: [Pod1] [Pod2] [Pod3] [Pod4] [Pod5] │
│ │
│ 更新镜像版本 v1→v2: │
│ │
│ Step 1: 创建ReplicaSet-v2 (0 replicas) │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ RS-v1: [Pod1] [Pod2] [Pod3] [Pod4] [Pod5] │ │
│ │ RS-v2: │ │
│ └────────────────────────────────────────────────────────┘ │
│ │
│ Step 2: maxSurge=1, maxUnavailable=0 │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ RS-v1: [Pod1] [Pod2] [Pod3] [Pod4] [Pod5] │ │
│ │ RS-v2: [Pod6] │ │
│ └────────────────────────────────────────────────────────┘ │
│ │
│ Step 3: v2 Pod6 Ready, 缩减v1 │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ RS-v1: [Pod1] [Pod2] [Pod3] [Pod4] │ │
│ │ RS-v2: [Pod6] [Pod7] │ │
│ └────────────────────────────────────────────────────────┘ │
│ │
│ Step 4: 持续滚动... │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ RS-v1: [Pod1] [Pod2] [Pod3] │ │
│ │ RS-v2: [Pod6] [Pod7] [Pod8] │ │
│ └────────────────────────────────────────────────────────┘ │
│ │
│ 最终状态: │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ RS-v1: │ │
│ │ RS-v2: [Pod6] [Pod7] [Pod8] [Pod9] [Pod10] │ │
│ └────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
5.2 滚动更新策略配置
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
spec:
replicas: 5
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # 可以超出期望副本数的最大值(数字或百分比)
maxUnavailable: 0 # 更新期间允许不可用的最大值(数字或百分比)
selector:
matchLabels:
app: web-app
template:
metadata:
labels:
app: web-app
spec:
containers:
- name: web-app
image: web-app:v2
readinessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 5
periodSeconds: 3
5.3 更新策略对比
| 参数 | maxSurge | maxUnavailable | 行为 |
|---|---|---|---|
| 保守 | 1 | 0 | 先扩后缩,零停机 |
| 激进 | 25% | 25% | 快速更新,短暂不可用 |
| 极端 | 0 | 1 | 先缩后扩,资源节省 |
| Recreate | N/A | N/A | 先删后建,有停机 |
5.4 Progress Deadline机制详解
Progress Deadline工作原理:
┌─────────────────────────────────────────────────────────────────┐
│ Progress Deadline机制 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 配置参数: │
│ spec.progressDeadlineSeconds: 600 (默认600秒) │
│ │
│ 触发条件: │
│ - ReplicaSet创建后,Pod长时间未Ready │
│ - 滚动更新过程中,新Pod无法达到Ready状态 │
│ - 连续超时未完成更新 │
│ │
│ 状态变化流程: │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ 时间T=0: 创建新ReplicaSet │ │
│ │ 时间T=60s: Pod未Ready, Progressing=True │ │
│ │ 时间T=600s: Pod仍未Ready │ │
│ │ → ProgressDeadlineExceeded=True │ │
│ │ → Deployment.status.conditions更新 │ │
│ │ → 滚动更新暂停 │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ Deployment Condition: │
│ Type: Progressing │
│ Status: False │
│ Reason: ProgressDeadlineExceeded │
│ Message: ReplicaSet "web-app-xxx" has timed out progressing. │
│ │
└─────────────────────────────────────────────────────────────────┘
Progress Deadline配置示例:
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
spec:
replicas: 5
progressDeadlineSeconds: 300 # 5分钟内必须完成更新
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
spec:
containers:
- name: web-app
image: web-app:v2
readinessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
failureThreshold: 3
successThreshold: 1
Progress Deadline超时排查:
# 查看Deployment状态
kubectl describe deployment web-app
# 输出示例
Conditions:
Type Status Reason
Available True MinimumReplicasAvailable
Progressing False ProgressDeadlineExceeded
# 查看Pod状态
kubectl get pods -l app=web-app -o wide
# 查看Pod事件
kubectl describe pod web-app-xxx-yyy
# 常见原因排查:
# 1. ReadinessProbe配置错误
# 2. 镜像拉取失败
# 3. 资源不足(CPU/Memory)
# 4. Init容器阻塞
# 5. PVC挂载失败
5.5 就绪门控(ReadinessGate)与滚动更新安全
apiVersion: v1
kind: Pod
metadata:
name: with-readiness-gate
spec:
readinessGates:
- conditionType: "www.example.com/feature-1"
containers:
- name: app
image: nginx
readinessProbe:
httpGet:
path: /healthz
port: 8080
---
# Pod Condition状态:
# Type Status
# Ready True ←内置探针
# www.example.com/feature-1 True ←自定义门控
# 两者都为True, Pod才被视为Ready
ReadinessGate深度详解
ReadinessGate完整配置示例:
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
spec:
replicas: 3
selector:
matchLabels:
app: web-app
template:
metadata:
labels:
app: web-app
annotations:
# 自定义ReadinessGate配置
readiness.gates.io/conditions: '["example.com/feature-ready", "example.com/dependency-ready"]'
spec:
readinessGates:
- conditionType: "example.com/feature-ready"
- conditionType: "example.com/dependency-ready"
containers:
- name: web-app
image: web-app:v1
readinessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 5
periodSeconds: 3
---
# 外部控制器更新Pod Condition
apiVersion: v1
kind: Pod
metadata:
name: web-app-xxx-yyy
status:
conditions:
- type: Ready
status: "True"
lastProbeTime: null
- type: example.com/feature-ready
status: "True"
lastProbeTime: null
reason: "FeatureEnabled"
message: "Feature toggle has been enabled"
- type: example.com/dependency-ready
status: "True"
lastProbeTime: null
reason: "DependencyAvailable"
message: "All dependencies are ready"
ReadinessGate典型应用场景:
┌─────────────────────────────────────────────────────────────────┐
│ ReadinessGate应用场景 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 场景1: 等待外部依赖就绪 │
│ ├── 等待数据库连接池初始化完成 │
│ ├── 等待外部API服务可用 │
│ └── 由Sidecar或外部Controller更新Condition │
│ │
│ 场景2: 金丝雀发布流量控制 │
│ ├── 新Pod启动后先不接收流量 │
│ ├── 等待监控系统确认无异常 │
│ └── 由流量管理组件更新Condition │
│ │
│ 场景3: 多阶段预热 │
│ ├── 容器启动 → 内置Probe通过 │
│ ├── 缓存预热 → 自定义Gate通过 │
│ ├── 建立连接 → 自定义Gate通过 │
│ └── 全部通过 → Pod Ready │
│ │
│ 实现方式: │
│ 1. 自定义Controller监听Pod,更新Condition │
│ 2. Sidecar容器检测依赖,更新Pod Status │
│ 3. 外部服务通过API更新Pod Condition │
│ │
└─────────────────────────────────────────────────────────────────┘
ReadinessGate Controller实现示例:
// 自定义ReadinessGate Controller
func (r *PodReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
var pod corev1.Pod
if err := r.Get(ctx, req.NamespacedName, &pod); err != nil {
return ctrl.Result{}, client.IgnoreNotFound(err)
}
// 检查是否需要更新ReadinessGate
for _, gate := range pod.Spec.ReadinessGates {
// 检查外部依赖状态
ready, err := r.checkDependency(gate.ConditionType, &pod)
if err != nil {
return ctrl.Result{RequeueAfter: 5 * time.Second}, nil
}
// 更新Pod Condition
condition := corev1.PodCondition{
Type: gate.ConditionType,
Status: corev1.ConditionTrue,
Reason: "DependencyReady",
}
if !ready {
condition.Status = corev1.ConditionFalse
condition.Reason = "DependencyNotReady"
}
// 更新Pod Status
found := false
for i, c := range pod.Status.Conditions {
if c.Type == gate.ConditionType {
pod.Status.Conditions[i] = condition
found = true
break
}
}
if !found {
pod.Status.Conditions = append(pod.Status.Conditions, condition)
}
}
return ctrl.Result{RequeueAfter: 10 * time.Second}, r.Status().Update(ctx, &pod)
}
5.6 金丝雀发布与蓝绿部署
金丝雀发布(Armo Rollouts)
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: canary-demo
spec:
replicas: 10
strategy:
canary:
steps:
- setWeight: 10 # 10%流量到新版本
- pause: {duration: 5m} # 暂停5分钟观察
- setWeight: 30 # 30%流量
- pause: {} # 手动确认
- setWeight: 60
- pause: {duration: 5m}
- setWeight: 100 # 全量发布
canaryService: canary-svc
stableService: stable-svc
蓝绿部署
# 蓝绿部署通过Service selector切换实现
# 蓝(当前版本)
apiVersion: v1
kind: Service
metadata:
name: web-app
spec:
selector:
app: web-app
version: blue # 切换为green即完成切换
ports:
- port: 80
targetPort: 8080
5.7 Argo Rollouts高级发布策略
Argo Rollouts完整架构
┌─────────────────────────────────────────────────────────────────┐
│ Argo Rollouts架构 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Rollout Controller │ │
│ │ │ │
│ │ ┌────────────┐ ┌────────────┐ ┌────────────┐ │ │
│ │ │ Rollout │ │ Analysis │ │ Experiment │ │ │
│ │ │ Reconciler │ │ Engine │ │ Manager │ │ │
│ │ └────────────┘ └────────────┘ └────────────┘ │ │
│ └──────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Traffic Management │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐│ │
│ │ │ Istio │ │ Nginx │ │ AWS ALB │ │ SMI ││ │
│ │ │ Virtual │ │ Ingress │ │ Ingress │ │ Traffic ││ │
│ │ │ Service │ │ Controller│ │ Controller│ │ Split ││ │
│ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘│ │
│ └──────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
高级金丝雀发布配置
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: web-app-rollout
spec:
replicas: 10
revisionHistoryLimit: 3
selector:
matchLabels:
app: web-app
template:
metadata:
labels:
app: web-app
spec:
containers:
- name: web-app
image: web-app:v2
ports:
- containerPort: 8080
resources:
requests:
cpu: 100m
memory: 128Mi
strategy:
canary:
# Istio流量管理
trafficRouting:
istio:
virtualService:
name: web-app-vsvc
destinationRule:
name: web-app-destrule
canarySubsetName: canary
stableSubsetName: stable
# 金丝雀步骤
steps:
# 阶段1: 初始金丝雀
- setWeight: 5
- pause: {duration: 2m}
# 阶段2: 自动分析
- setWeight: 10
- analysis:
templates:
- templateName: success-rate
startingStep: 3
args:
- name: service-name
value: web-app-canary
# 阶段3: 渐进增加
- setWeight: 25
- pause: {duration: 5m}
- setWeight: 50
- pause: {duration: 5m}
# 阶段4: 最终分析
- setWeight: 80
- analysis:
templates:
- templateName: error-rate
args:
- name: service-name
value: web-app-canary
# 阶段5: 全量发布
- setWeight: 100
- pause: {}
# 反转配置(自动回滚)
maxSurge: 25%
maxUnavailable: 0
# 缩容配置
scaleDownDelayRevisionLimit: 2
scaleDownDelaySeconds: 300
---
# AnalysisTemplate定义
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
name: success-rate
spec:
args:
- name: service-name
metrics:
- name: success-rate
interval: 1m
count: 5
successCondition: result[0] >= 0.99
failureLimit: 3
provider:
prometheus:
address: http://prometheus.monitoring:9090
query: |
sum(rate(http_requests_total{service="{{args.service-name}}",status!~"5.."}[1m])) /
sum(rate(http_requests_total{service="{{args.service-name}}"}[1m]))
---
# Error Rate分析模板
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
name: error-rate
spec:
args:
- name: service-name
metrics:
- name: error-rate
interval: 30s
count: 10
successCondition: result[0] < 0.01
failureLimit: 2
inconclusiveLimit: 3
provider:
prometheus:
address: http://prometheus.monitoring:9090
query: |
sum(rate(http_requests_total{service="{{args.service-name}}",status=~"5.."}[1m])) /
sum(rate(http_requests_total{service="{{args.service-name}}"}[1m]))
蓝绿发布高级配置
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: web-app-bluegreen
spec:
replicas: 3
selector:
matchLabels:
app: web-app
template:
metadata:
labels:
app: web-app
spec:
containers:
- name: web-app
image: web-app:v2
ports:
- containerPort: 8080
strategy:
blueGreen:
# 激活Service(指向当前活跃版本)
activeService: web-app-active
# 预览Service(指向新版本,用于测试)
previewService: web-app-preview
# 自动切换前的等待时间
autoPromotionEnabled: true
autoPromotionSeconds: 30
# 缩容旧版本前的等待时间
scaleDownDelaySeconds: 60
# 预览副本数
previewReplicaCount: 1
# 切换后保留旧版本
antiAffinity:
required: false
---
# Active Service
apiVersion: v1
kind: Service
metadata:
name: web-app-active
spec:
selector:
app: web-app
ports:
- port: 80
targetPort: 8080
---
# Preview Service (用于测试新版本)
apiVersion: v1
kind: Service
metadata:
name: web-app-preview
spec:
selector:
app: web-app
ports:
- port: 80
targetPort: 8080
渐进式交付(Progressive Delivery)
# 结合Analysis的渐进式交付
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: progressive-delivery
spec:
replicas: 10
strategy:
canary:
steps:
# 1. 部署1个金丝雀Pod
- setCanaryScale:
replicas: 1
- pause: {duration: 1m}
# 2. 运行后台分析任务
- analysis:
templates:
- templateName: baseline-comparison
args:
- name: baseline-service
value: web-app-stable
- name: canary-service
value: web-app-canary
# 3. 分析通过后增加流量
- setWeight: 20
- pause: {duration: 2m}
# 4. 持续监控
- analysis:
templates:
- templateName: latency-check
startingStep: 4
# 5. 完成发布
- setWeight: 100
---
# 基线对比分析
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
name: baseline-comparison
spec:
args:
- name: baseline-service
- name: canary-service
metrics:
- name: latency-comparison
interval: 1m
count: 5
successCondition: result[0] < result[1] * 1.1 # 金丝雀延迟不超过基线10%
provider:
prometheus:
address: http://prometheus.monitoring:9090
query: |
histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket{service="{{args.canary-service}}"}[1m])) by (le))
# 对比结果需要在另一个查询中计算
Argo Rollouts与Istio集成
# Istio VirtualService配置
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: web-app
spec:
hosts:
- web-app
http:
- route:
- destination:
host: web-app-stable
subset: stable
weight: 100
- destination:
host: web-app-canary
subset: canary
weight: 0
---
# Istio DestinationRule
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: web-app
spec:
host: web-app
subsets:
- name: stable
labels:
app: web-app
version: stable
- name: canary
labels:
app: web-app
version: canary
---
# Rollout自动更新VirtualService权重
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: web-app
spec:
strategy:
canary:
trafficRouting:
istio:
virtualService:
name: web-app-vsvc
routes:
- primary # 指定路由名称
destinationRule:
name: web-app-destrule
canarySubsetName: canary
stableSubsetName: stable
参考资料:
-
Kubernetes Kubelet
-
HPA Design
-
VPA
-
Cluster Autoscaler
-
Operator Pattern
-
Kubebuilder
-
Rolling Update
-
Controller Runtime
-
Argo Rollouts
-
Custom Resource Validation
更多推荐
所有评论(0)