Kubelet 深度剖析 概述 Kubelet 是 Kubernetes 集群中运行在每个节点上的核心组件,负责管理和维护 Pod 的生命周期。它是节点与 API Server 之间的桥梁,将容器运行时(Container Runtime)的实际状态与 etcd 中期望的状态进行调和(Reconciliation)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 ┌─────────────────────────────────────────────────────────────────────┐ │ Kubelet 架构图 │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────┐ ┌─────────────┐ CRI (Container Runtime) │ │ │ PodWorker │ │ SyncHandler │ ┌─────────────────────┐ │ │ └──────┬──────┘ └──────┬──────┘ │ dockershim │ │ │ │ │ │ containerd │ │ │ └────────┬────────┘ │ cri-o │ │ │ │ └─────────────────────┘ │ │ ┌───────▼────────┐ │ │ │ 状态调和 │ ◄──────────────► 容器运行时 │ │ │ (Reconciler) │ │ │ └───────┬────────┘ │ │ │ │ │ ┌─────────────▼───────────────────────────────────────────┐ │ │ │ Kubelet 核心模块 │ │ │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ │ │ PLEG │ │ VolumeMgr │ │ ImageGC │ │ │ │ │ │ (Pod Lifecycle)│ │ (Volume) │ │ (Image GC) │ │ │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │ │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ │ │ ProbeMgr │ │ SecretMgr │ │ ConfigMapMgr│ │ │ │ │ │ (健康检查) │ │ (Secret) │ │ (ConfigMap) │ │ │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │ │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ │ │ CAdvisor │ │ OOMWatcher │ │ StatusManager│ │ │ │ │ │ (资源监控) │ │ (OOM监控) │ │ (状态同步) │ │ │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │ │ └─────────────────────────────────────────────────────────┘ │ │ │ │ │ ┌───────────────────────────▼───────────────────────────────┐ │ │ │ Pod Lifecycle Generator (PLEG) │ │ │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ │ │ │ Container│ │ PodSync │ │ Sync │ │ Garbage │ │ │ │ │ │ Started │ │ Handler │ │ Period │ │ Collect │ │ │ │ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │ │ └─────────────────────────────────────────────────────────┘ │ │ │ │ └──────────────────────────────│───────────────────────────────────┘ │ ┌──────────▼──────────┐ │ API Server │ │ (Etcd + Watch) │ └─────────────────────┘
1. Kubelet 启动流程 1.1 启动入口 Kubelet 的启动入口位于 cmd/kubelet/app/server.go:
1 2 3 4 5 6 7 8 9 func Run (ctx context.Context, KubeletConfig *config.KubeletConfiguration, ... ) error { }
1.2 核心初始化流程 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 ┌──────────────────────────────────────────────────────────────┐ │ Kubelet 初始化流程 │ ├──────────────────────────────────────────────────────────────┤ │ │ │ 1. NewKubeletConfig() ──► 解析配置,创建 KubeletConfiguration │ │ │ │ │ ▼ │ │ 2. RunKubelet() ──► 创建 kubeletServer │ │ │ │ │ ▼ │ │ 3. NewMainKubelet() ──► 创建 Kubelet 实例 │ │ │ │ │ ┌───────────────┼───────────────┐ │ │ ▼ ▼ ▼ │ │ statusManager containerRuntime PLEG │ │ │ │ │ │ │ └───────────────┼───────────────┘ │ │ ▼ │ │ 4. StartKubelet() ──► 启动各个 manager │ │ │ │ │ ▼ │ │ 5. StartLoop() ──► 启动 sync loop │ │ │ └──────────────────────────────────────────────────────────────┘
1.3 关键配置项 Kubelet 配置文件位于 /var/lib/kubelet/config.yaml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 apiVersion: kubelet.config.k8s.io/v1beta1 kind: KubeletConfiguration address: 0.0 .0 .0 port: 10250 authentication: anonymous: { enabled: false } webhook: { enabled: true , cacheTTL: 2m0s } authorization: { mode: Webhook , webhookCacheAuthorizedTTL: 1m0s }cgroupDriver: systemd cgroupsPerQOS: true clusterDNS: - 10.96 .0 .10 clusterDomain: cluster.local containerRuntimeEndpoint: unix:///var/run/containerd/containerd.sock runtimeRequestTimeout: 2m0s evictionHard: memory.available: "100Mi" nodefs.available: "10%" kubeReserved: cpu: "100m" memory: 256Mi systemReserved: cpu: "100m" memory: 256Mi
2. Pod 状态同步机制 2.1 Pod Sync Handler Kubelet 通过 PodSyncHandler 来同步 Pod 的期望状态与实际状态:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 type PodManager interface { GetPods() []*v1.Pod GetPodByUID(types.UID) (*v1.Pod, bool ) GetPodByName(namespace, name string ) (*v1.Pod, bool ) SetPods(pods []*v1.Pod) AddPod(pod *v1.Pod) UpdatePod(pod *v1.Pod) DeletePod(pod *v1.Pod) } type PodWorkers interface { UpdatePod(options UpdatePodOptions) DeletePod(podUID types.UID) RemoveOrphanedPodImages() ForgetPod(uid types.UID) }
2.2 Sync Loop 流程 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 ┌────────────────────────────────────────────────────────────────┐ │ Sync Loop 主循环 │ ├────────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ 同步循环 (每 1 秒) │ │ │ │ │ │ │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌────────┐ │ │ │ │ │ dispatch│ │ syncPod │ │ prune │ │ housekeeping │ │ │ │ │ Work │ │ │ │ Pods │ │ │ │ │ │ │ └─────────┘ └─────────┘ └─────────┘ └────────┘ │ │ │ │ │ │ │ │ │ │ │ │ └───────────┴───────────┴───────────┘ │ │ │ │ │ │ │ │ │ ▼ │ │ │ │ ┌─────────────────┐ │ │ │ │ │ PodSyncHandler │ │ │ │ │ └─────────────────┘ │ │ │ │ │ │ │ │ │ ▼ │ │ │ │ ┌─────────────────┐ │ │ │ │ │ generatePodSync │ │ │ │ │ │ Task │ │ │ │ │ └─────────────────┘ │ │ │ │ │ │ │ │ └───────────────────────┼───────────────────────────┘ │ │ │ │ └────────────────────────────┼───────────────────────────────────┘ │ ▼ ┌─────────────────────┐ │ containerRuntime │ │ (CRI) │ └─────────────────────┘
2.3 Pod 同步状态定义 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 type syncStatusType int const ( SyncPodCreate syncStatusType = iota SyncPodUpdate SyncPodSync SyncPodKill SyncPodUpdateType ) type UpdatePodOptions struct { UID types.UID Type syncStatusType Pod *v1.Pod MirrorPod *v1.Pod PodStatus *kubecontainer.PodStatus StartTime *metav1.Time Failure kuberuntime.ErrCrashLoopBackoff ErrCh chan <- error }
3. Pod 创建流程 3.1 完整创建流程 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 ┌─────────────────────────────────────────────────────────────────────────┐ │ Pod 创建完整流程 │ ├─────────────────────────────────────────────────────────────────────────┤ │ │ │ API Server Kubelet CRI │ │ │ │ │ │ │ │ Watch: 新建/更新 Pod │ │ │ │ │ ───────────────────────► │ │ │ │ │ │ │ │ │ │ │ 1. ParsePod() │ │ │ │ │ 验证并补充 Pod 信息 │ │ │ │ │ ────────────────────── │ │ │ │ │ │ │ │ │ │ 2. createPodSandbox() │ │ │ │ │ ───────────────────────► │ │ │ │ │ │ │ │ │ │ 3. 拉取 Init Container │ │ │ │ │ 镜像 │ │ │ │ │ ───────────────────────► │ │ │ │ │ │ │ │ │ │ 4. 启动 Init Container │ │ │ │ │ ───────────────────────► │ │ │ │ │ │ │ │ │ │ 5. 拉取业务 Container │ │ │ │ │ 镜像 │ │ │ │ │ ───────────────────────► │ │ │ │ │ │ │ │ │ │ 6. 启动业务 Container │ │ │ │ │ ───────────────────────► │ │ │ │ │ │ │ │ │ │ 7. 挂载 Volume │ │ │ │ │ (EmptyDir/HostPath/ │ │ │ │ │ PVC/ConfigMap/...) │ │ │ │ │ ───────────────────────► │ │ │ │ │ │ │ │ │ │ 8. 启动 Probe Manager │ │ │ │ │ (健康检查) │ │ │ │ │ │ │ │ │ │ 9. 更新状态到 API Server │ │ │ │ ◄ ─────────────────────── │ │ │ │ │ │ │ │ └─────────────────────────────────────────────────────────────────────────┘
3.2 SyncPod 核心代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 func (kl *Kubelet) syncPod(ctx context.Context, pod *v1.Pod, podStatus *kubecontainer.PodStatus) error { if pod.DeletionTimestamp != nil { return kl.killPod(pod, killReasonGracePeriodOverride, nil ) } podSandboxID, err := kl.makePodSandbox(pod, uint (runtimeapi.PodSandboxState_SANDBOX_READY)) if err != nil { message := fmt.Sprintf("Failed to create PodSandbox: %v" , err) kl.recorder.Eventf(pod, v1.EventTypeWarning, events.FailedCreatePodSandBox, message) return err } if err := kl.volumeManager.SetUpAt(pod.Spec.Volumes, pod, podStatus); err != nil { return err } if err := kl.pullImages(pod); err != nil { return err } if err := kl.startContainers(pod, podStatus); err != nil { return err } kl.probeManager.AddPod(pod) return nil }
3.3 Init Container 执行 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 func (m *kubeGenericRuntimeManager) startInitContainers( pod *v1.Pod, podStatus *kubecontainer.PodStatus, ) error { initContainers := pod.Spec.InitContainers if len (initContainers) == 0 { return nil } for _, container := range initContainers { if status, ok := podStatus.ContainerStatus[container.Name]; ok { if status.State == kubecontainer.ContainerStateExited { continue } } if err := m.startContainer(podSandboxID, container, pod, podStatus); err != nil { return err } } return nil }
4. 容器运行时接口 (CRI) 4.1 CRI 架构 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 ┌─────────────────────────────────────────────────────────────────┐ │ CRI 架构图 │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────────┐ │ │ │ Kubelet │ │ │ └────────┬────────┘ │ │ │ │ │ │ gRPC (Unix Socket) │ │ │ │ │ ┌────────▼────────┐ │ │ │ CRI │ │ │ │ (RuntimeService│ │ │ │ ImageService) │ │ │ └────────┬────────┘ │ │ │ │ │ ┌───────────────────┼───────────────────┐ │ │ │ │ │ │ │ ┌──────▼──────┐ ┌───────▼───────┐ ┌──────▼──────┐ │ │ │ dockershim │ │ containerd │ │ cri-o │ │ │ │ (内置) │ │ (cri) │ │ │ │ │ └──────┬──────┘ └───────┬───────┘ └──────┬──────┘ │ │ │ │ │ │ │ ┌──────▼──────┐ ┌───────▼───────┐ ┌──────▼──────┐ │ │ │ Docker │ │ containerd │ │ OCI │ │ │ │ Daemon │ │ daemon │ │ (runc) │ │ │ └────────────┘ └──────────────┘ └─────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────┘
4.2 CRI 核心接口 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 type RuntimeService interface { CreateContainer(ctx context.Context, config *ContainerConfig, sandboxConfig *PodSandboxConfig) (string , error ) StartContainer(ctx context.Context, containerID string ) error StopContainer(ctx context.Context, containerID string , timeout int64 ) error RemoveContainer(ctx context.Context, containerID string ) error ListContainers(ctx context.Context, filter *ContainerFilter) ([]*Container, error ) ContainerStatus(ctx context.Context, containerID string ) (*ContainerStatus, error ) ExecSync(ctx context.Context, containerID string , cmd []string , timeout time.Duration) (*ExecSyncResponse, error ) Exec(ctx context.Context, req *ExecRequest) (*ExecResponse, error ) Attach(ctx context.Context, req *AttachRequest) (*AttachResponse, error ) PortForward(ctx context.Context, req *PortForwardRequest) (*PortForwardResponse, error ) } type ImageService interface { ListImages(ctx context.Context, filter *ImageFilter) ([]*Image, error ) ImageStatus(ctx context.Context, image *ImageSpec) (*Image, error ) PullImage(ctx context.Context, image *ImageSpec, auth *AuthConfig) (string , error ) RemoveImage(ctx context.Context, image *ImageSpec) error }
4.3 Pod Sandbox 创建流程 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 func (m *kubeGenericRuntimeManager) createPodSandbox( ctx context.Context, pod *v1.Pod, attempt uint32 , ) (string , error ) { sandboxConfig, err := m.generatePodSandboxConfig(pod, attempt) if err != nil { return "" , err } sandboxID, err := m.runtimeService.RunPodSandbox(ctx, sandboxConfig) if err != nil { return "" , err } if err := m.waitSandboxReady(ctx, sandboxID); err != nil { return "" , err } if pod.Spec.HostNetwork { return sandboxID, nil } if err := m.networkPlugin.SetUpPod( sandboxID, pod.Namespace, pod.Name, annotations, ); err != nil { return "" , err } return sandboxID, nil }
5. 容器健康检查 5.1 Probe 类型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 ┌─────────────────────────────────────────────────────────────────┐ │ Probe 健康检查机制 │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ Startup │ │ Liveness │ │ Readiness │ │ │ │ Probe │ │ Probe │ │ Probe │ │ │ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │ │ │ │ │ │ │ │ │ │ │ │ ┌──────▼──────┐ ┌──────▼──────┐ ┌──────▼──────┐ │ │ │ 初始化探测 │ │ 存活探测 │ │ 就绪探测 │ │ │ │ (可选) │ │ (必需) │ │ (必需) │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │ │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ Probe 配置 │ │ │ │ │ │ │ │ initialDelaySeconds: 启动后多久开始探测 │ │ │ │ periodSeconds: 探测间隔 (默认 10s) │ │ │ │ timeoutSeconds: 超时时间 (默认 1s) │ │ │ │ failureThreshold: 失败多少次后标记为失败 (默认 3) │ │ │ │ successThreshold: 成功多少次后标记为成功 (默认 1) │ │ │ │ │ │ │ └─────────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────┘
5.2 Probe Manager 实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 type Manager interface { AddPod(pod *v1.Pod) RemovePod(pod *v1.Pod) CleanupPods(pods []*v1.Pod) UpdatePodStatus(pod *v1.Pod, status *v1.PodStatus) } type manager struct { workers map [workerKey]*prober mu sync.Mutex } func (m *manager) AddPod(pod *v1.Pod) { for _, c := range pod.Spec.Containers { if c.StartupProbe != nil { m.addWorker(pod, c, startup) } if c.LivenessProbe != nil { m.addWorker(pod, c, liveness) } if c.ReadinessProbe != nil { m.addWorker(pod, c, readiness) } } } func (p *prober) probe(execProbeType probeType) (probe.Result, string , error ) { switch { case c.Exec != nil : return p.exec.Probe(e.pod, e.container, c.Exec) case c.HTTPGet != nil : return p.http.Probe(e.pod, e.container, c.HTTPGet) case c.TCPSocket != nil : return p.tcp.Probe(e.pod, e.container, c.TCPSocket) } }
5.3 就绪探针与流量控制 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 func (kl *Kubelet) updatePodReady(pod *v1.Pod) { ready := kl.probeManager.IsPodReady(pod) kl.statusManager.SetPodReady(pod.UID, ready) } func (m *manager) SetPodReady(uid types.UID, ready bool ) { m.setPodStatus(uid, func (status *v1.PodStatus) { status.Conditions = updatePodReadyCondition(status.Conditions) v1meta.SetPodCondition(&status.Conditions, v1.PodCondition{ Type: v1.PodReady, Status: v1.ConditionTrue, }) }) }
6. 资源管理 6.1 cAdvisor 集成 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 ┌─────────────────────────────────────────────────────────────────┐ │ cAdvisor 资源监控架构 │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ cAdvisor │ │ │ │ ┌───────────────┐ ┌───────────────┐ ┌─────────────┐ │ │ │ │ │ Container │ │ Node │ │ Stats │ │ │ │ │ │ Metrics │ │ Metrics │ │ Provider │ │ │ │ │ │ (CPU/Mem/Net) │ │ (sys fs) │ │ │ │ │ │ │ └───────────────┘ └───────────────┘ └─────────────┘ │ │ │ └─────────────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ Kubelet │ │ │ │ ┌───────────────┐ ┌───────────────┐ ┌─────────────┐ │ │ │ │ │ Summary │ │ Resource │ │ OOM │ │ │ │ │ │ Provider │ │ Manager │ │ Manager │ │ │ │ │ └───────────────┘ └───────────────┘ └─────────────┘ │ │ │ └─────────────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────┐ │ │ │ Summary API (/stats) │ │ │ └─────────────────────────────┘ │ │ │ │ │ ┌──────────────┼──────────────┐ │ │ ▼ ▼ ▼ │ │ Metrics Server Prometheus Dashboard │ │ │ └─────────────────────────────────────────────────────────────────┘
6.2 资源 QoS 层级 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 qosClass := v1qos.GetPodQOS(pod) func GetPodQOS (pod *v1.Pod) v1.PodQOSClass { if isGuaranteed(pod) { return v1.PodQOSGuaranteed } if isBestEffort(pod) { return v1.PodQOSBestEffort } return v1.PodQOSBurstable } func isGuaranteed (pod *v1.Pod) bool { for _, container := range pod.Spec.Containers { if container.Resources.Requests.Cpu() == nil || container.Resources.Requests.Memory() == nil || container.Resources.Limits.Cpu() == nil || container.Resources.Limits.Memory() == nil { return false } } return true }
7. 卷管理 7.1 Volume Manager 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 ┌─────────────────────────────────────────────────────────────────┐ │ Volume Manager 架构 │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ ┌──────────────────────────────────────────────────────────┐ │ │ │ Volume Manager │ │ │ │ │ │ │ │ ┌────────────────┐ ┌────────────────┐ │ │ │ │ │ VolumeHost │◄──────►│ Reconciler │ │ │ │ │ │ (kubelet) │ │ (状态调和) │ │ │ │ │ └────────────────┘ └────────┬───────┘ │ │ │ │ │ │ │ │ │ ┌────────────────────────────────────┼────────────────┐ │ │ │ │ │ │ │ │ │ │ │ │ ┌─────────────┐ ┌─────────────┐ │ ┌───────────┐ │ │ │ │ │ │ │ desiredState│ │actualState │ │ │operation │ │ │ │ │ │ │ │ OfWorld │ │ OfWorld │ │ │ Queue │ │ │ │ │ │ │ │ (期望状态) │ │ (实际状态) │ │ │ (操作队列) │ │ │ │ │ │ │ └─────────────┘ └─────────────┘ │ └───────────┘ │ │ │ │ │ └────────────────────────────────────┼────────────────┘ │ │ │ └───────────────────────────────────────┼───────────────────┘ │ │ │ │ └──────────────────────────────────────────┼───────────────────────┘ │ ┌──────────────────────┼──────────────────────┐ │ │ │ ┌─────────▼─────────┐ ┌─────────▼─────────┐ ┌──────▼──────┐ │ EmptyDir │ │ PVC (CSI) │ │ ConfigMap │ │ VolumePlugin │ │ VolumePlugin │ │ VolumePlugin │ └───────────────────┘ └───────────────────┘ └─────────────┘
7.2 Volume 挂载流程 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 func (vc *VolumeController) Run(stopCh <-chan struct {}) { go vc.reconciler.Run(stopCh) syncLoopPeriod := 100 * time.Millisecond wait.Until(vc.operationExecutor, syncLoopPeriod, stopCh) } func (rc *reconciler) reconcile() { rc.mountAttach volumesNeedReporting for _, volumeToMount := range rc.desiredStateOfWorld.GetVolumesToMount() { if !rc.actualStateOfWorld.VolumeExistsWithSpecName( volumeToMount.PodName, volumeToMount.VolumeSpecName) { rc.operationExecutor.MountVolume(...) } } for _, volumeToUnmount := range rc.actualStateOfWorld.GetVolumesToUnmount() { if !rc.desiredStateOfWorld.PodExistsInVolume(volumeToUnmount.PodName, ...) { rc.operationExecutor.UnmountVolume(...) } } }
8. Pod 驱逐机制 8.1 驱逐策略 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 type thresholds struct { hard []evictionapi.Threshold soft []evictionapi.Threshold signals map [evictionapi.Signal]float64 }
8.2 驱逐流程 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 ┌─────────────────────────────────────────────────────────────────┐ │ Pod 驱逐流程 │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ 1. 监控资源使用 │ │ ┌─────────────────────────────────────────────────┐ │ │ │ cAdvisor 采集节点资源状态 │ │ │ │ - 内存使用率 │ │ │ │ - 磁盘使用率 │ │ │ │ - Inode 使用率 │ │ │ └─────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ 2. 比较阈值 │ │ ┌─────────────────────────────────────────────────┐ │ │ │ 硬驱逐: 达到阈值立即驱逐 │ │ │ │ 软驱逐: 达到阈值 + gracePeriod 仍未恢复则驱逐 │ │ │ └─────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ 3. 选择要驱逐的 Pod │ │ ┌─────────────────────────────────────────────────┐ │ │ │ 1. QoS 优先级: BestEffort > Burstable > Guaranteed │ │ │ │ 2. 资源使用量: 使用量越大越优先被驱逐 │ │ │ │ 3. Pod Priority: priority 值越小越优先被驱逐 │ │ │ │ 4. 运行时间: 运行时间越短越优先被驱逐 │ │ │ └─────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ 4. 执行驱逐 │ │ ┌─────────────────────────────────────────────────┐ │ │ │ 1. 调用 API Server 删除 Pod │ │ │ │ 2. 停止容器 │ │ │ │ 3. 清理卷挂载 │ │ │ │ 4. 清理网络命名空间 │ │ │ └─────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────┘
8.3 驱逐顺序代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 func (m *manager) rankForEviction(pods []*v1.Pod) { sort.Slice(pods, func (i, j int ) bool { if qosClass[i] != qosClass[j] { return rankQoS(pods[i]) > rankQoS(pods[j]) } if memory[i] != memory[j] { return memory[i] > memory[j] } if podPriority[i] != podPriority[j] { return getPodPriority(pods[i]) < getPodPriority(pods[j]) } return getContainerStartTime(pods[i]).Before(getContainerStartTime(pods[j])) }) }
9. Mirror Pod 与静态 Pod 9.1 Mirror Pod 机制 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ┌─────────────────────────────────────────────────────────────────┐ │ Mirror Pod 机制 │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ API Server Kubelet │ │ │ │ │ │ │ 1. 创建 Mirror Pod 规范 │ │ │ │ ◄──────────────────────── │ │ │ │ │ │ │ │ 2. 同步到节点 kubelet │ │ │ │ ────────────────────────► │ │ │ │ │ │ │ │ 3. 创建实际的 Pod │ │ │ │ │ ───────────────────────► │ │ │ │ │ │ │ 4. 上报状态 │ │ │ │ ◄──────────────────────── │ │ │ │ │ │ └─────────────────────────────────────────────────────────────────┘
9.2 静态 Pod 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 apiVersion: v1 kind: Pod metadata: name: static-web labels: app: static spec: containers: - name: web image: nginx ports: - containerPort: 80
10. 关键源码路径
功能
源码路径
入口函数
cmd/kubelet/app/server.go
Pod Workers
pkg/kubelet/pod_workers.go
Pod Manager
pkg/kubelet/pod/pod_manager.go
Sync Pod
pkg/kubelet/kubelet.go (syncPod)
PLEG
pkg/kubelet/pleg/generic.go
CRI Runtime
pkg/kubelet/kuberuntime/
Probe Manager
pkg/kubelet/probe/
Volume Manager
pkg/kubelet/volumemanager/
Eviction
pkg/kubelet/eviction/
Status Manager
pkg/kubelet/status/status_manager.go
Image GC
pkg/kubelet/images/image_gc_manager.go
cAdvisor
pkg/kubelet/cadvisor/
面试题 基础题 1. Kubelet 的主要职责是什么?
Kubelet 是运行在每个 Kubernetes 节点上的核心组件,主要职责包括:
监听 API Server 上的 Pod 分配任务
创建和管理 Pod 容器
负责容器健康检查(Probe)
监控容器资源使用
上报节点和 Pod 状态到 API Server
与容器运行时(CRI)交互
2. Kubelet 如何与容器运行时通信?
Kubelet 通过 Container Runtime Interface (CRI) 与容器运行时通信。CRI 定义了 gRPC 接口,包括 RuntimeService 和 ImageService 两组接口。Kubelet 通过 Unix Socket 或 TCP 连接向容器运行时发送请求,如创建容器、启动容器、停止容器等操作。
3. 什么是 Mirror Pod?
Mirror Pod 是静态 Pod 在 API Server 上的镜像。Kubelet 读取静态 Pod 配置文件后,会自动在 API Server 上创建一个同名的 Mirror Pod,使得静态 Pod 的状态可以通过 kubectl 查看。实际容器由 Kubelet 直接管理,不经过 API Server。
4. Pod 创建流程中 Init Container 的作用是什么?
Init Container 在 Pod 的业务容器启动之前运行,主要用于:
等待依赖服务就绪(如等待数据库启动)
初始化配置(如从远程拉取配置、设置数据库 schema)
预拉取数据(如预热缓存)
执行一次性任务(如注册服务、生成密钥)
所有 Init Container 必须按顺序执行完成,才能启动业务容器。
5. Probe 健康检查有哪三种类型?
Startup Probe(启动探针) :判断容器是否启动成功,用于慢启动容器,避免在启动期间被 Liveness Probe 杀死
Liveness Probe(存活探针) :判断容器是否存活,如果失败则重启容器
Readiness Probe(就绪探针) :判断容器是否就绪,就绪前不会接收 Service 流量
中级题 6. Kubelet 的 PLEG(Pod Lifecycle Event Generator)是什么?
PLEG 是 Kubelet 中的 Pod 生命周期事件生成器,它定期检查容器运行时的状态变化,生成 Pod 事件供 Kubelet 处理。PLEG 解决了轮询的性能问题,通过间歇性检查而非持续轮询来发现状态变化。主要流程:
PLEG 定期(如 1 秒)调用 ListContainers 获取所有容器状态
与上次状态比较,找出变化的容器
生成 PodLifecycleEvent
Kubelet 的 syncLoop 处理事件并同步 Pod 状态
7. Kubelet 的 Sync Loop 是如何工作的?
Sync Loop 是 Kubelet 的主循环,核心机制:
配置源同步 :从 configZooKeeper 或 API Server 获取期望的 Pod 列表
容器运行时同步 :从 PLEG 获取实际的容器状态
状态调和 :比较期望状态与实际状态,生成同步任务
执行同步 :调用 Pod Workers 执行创建、更新、删除操作
状态上报 :将 Pod 状态上报到 API Server
1 2 3 4 5 6 7 8 9 10 11 12 13 for { desiredPods := kl.podManager.GetPods() actualPods := kl.pleg.GetPodStatuses() for _, pod := range diff(desiredPods, actualPods) { kl.dispatchWork(pod) } time.Sleep(syncFrequency) }
8. Kubelet 如何管理卷(Volume)的挂载和卸载?
Kubelet 的 Volume Manager 负责卷管理:
期望状态 :跟踪 Pod 需要的卷配置
实际状态 :跟踪已挂载的卷
Reconciler :调和期望与实际状态
OperationExecutor :执行挂载/卸载操作
挂载流程:Kubelet 获取 Pod 的 Volume 配置 → 调用相应的 Volume Plugin → 调用容器运行时挂载卷到容器
9. Pod 驱逐的 QoS 优先级是怎样的?
Pod 驱逐的 QoS 优先级(从高到低):
BestEffort - 最高优先级被驱逐
Burstable - 中等优先级
Guaranteed - 最低优先级被驱逐
在同一 QoS 级别内,优先驱逐:
资源使用量大的 Pod
Priority 值小的 Pod
运行时间较短的 Pod
10. Kubelet 的身份认证和授权机制是什么?
Kubelet 的认证和授权采用 Webhook 模式,由 API Server 进行验证:
认证方式 :Kubelet 使用 x509 证书或 Bearer Token 向 API Server 认证
Webhook 模式 :API Server 调用 Kubelet 的 /metrics、/stats 等端点时,Kubelet 会向 API Server 发送 TokenReview 请求验证
RBAC 授权 :API Server 根据 Kubelet 的身份(由认证决定)通过 RBAC 进行授权
配置示例:
1 2 3 4 5 6 7 authentication: webhook: enabled: true cacheTTL: 2m0s authorization: mode: Webhook webhookCacheAuthorizedTTL: 1m0s
简而言之:Kubelet 作为服务端接收 API Server 请求时,API Server 会验证 Kubelet 的证书/Token(认证),并检查其权限(授权)。
高级题 11. 分析 Kubelet 的状态上报机制和 StatusManager 的实现
StatusManager 负责将 Pod 状态同步到 API Server:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 type manager struct { kubeClient clientset.Interface podManager kubeletpod.PodManager podStatusChannel chan podStatusSyncRequest } func (m *manager) SetPodStatus(pod *v1.Pod, status v1.PodStatus) { m.podStatusChannel <- podStatusSyncRequest{pod.UID, status} } func (m *manager) syncPod(uid types.UID) { m.kubeClient.CoreV1().Pods(pod.Namespace).UpdateStatus(ctx, pod) }
关键机制:
批量更新:合并短时间内的多次状态更新
幂等性:只上报变化的字段
错误处理:失败时使用指数退避重试
12. Kubelet 如何处理 Pod 的优雅终止?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 func (m *kubeGenericRuntimeManager) killContainer(...) error { if err := m.runtimeService.StopContainer(containerID, timeout); err != nil { m.killContainerWithSignal(containerID, int (syscall.SIGKILL)) } }
13. Kubelet 的资源 QoS 是如何实现的?
Linux Cgroup 实现 Pod 资源限制:
不同 QoS 级别的 Cgroup 配置:
QoS 级别
CPU 限制
Memory 限制
Guaranteed
cpu.quota/cpu.period = limit
memory.limit_in_bytes = limit
Burstable
cpu.quota/cpu.period = request
memory.soft_limit_in_bytes = request
BestEffort
无限制(可借用其他 Pod)
无限制(可借用其他 Pod)
场景题 14. 如何排查 Pod 一直处于 Pending 状态的问题?
排查步骤:
检查节点资源是否足够:kubectl describe node <node>
检查 Pod 的事件:kubectl describe pod <pod>
常见原因:
资源不足(CPU/Memory/存储)
节点存在污点但 Pod 没有容忍
PVC 未绑定(Pending PV)
镜像拉取失败(配置错误或网络问题)
Init Container 失败
调度失败(亲和性/反亲和性限制)
检查 Kubelet 日志:journalctl -u kubelet
15. 如果一个节点上的 Kubelet 不可用,Pod 会发生什么?
API Server 检测到心跳停止 :节点默认 40 秒无心跳标记为 NotReady
Pod 不会被立即驱逐 :等待 kube-controller-manager 的 nodecontroller 处理
Pod 删除超时 :默认 5 分钟(podEvictionTimeout)后开始驱逐
Pod 重建 :ReplicasetController 在其他健康节点上创建新 Pod
关键时间线:
10 秒:无心跳触发 node status 更新失败
40 秒:节点标记为 Unknown
5 分钟:开始驱逐 Pod
删除后由 Replicaset 创建新 Pod
16. 如何优化 Kubelet 的启动时间?
优化容器镜像预热 :
使用本地镜像仓库
配置 imagePullPolicy 为 IfNotPresent
优化卷挂载 :
使用 CSI 迁移减少转换开销
批量挂载减少串行操作
优化健康检查 :
合理设置 initialDelaySeconds
避免过多探针增加负载
其他优化 :
升级到最新版本(性能改进)
使用 gRPC 而不是 CNI(containerd)
配置适当的 –runtime-request-timeout