4. 容器编排入门:Kubernetes 核心架构、Pod、Deployment、Service 等基础对象

当企业从单机 Docker 走向生产级容器化时,最先遇到的瓶颈便是“如何管理成百上千个容器”。容器编排的本质,是将分散的主机资源抽象为一个统一的调度池,并解决容器的自动部署、弹性伸缩、故障自愈与服务发现四大问题。Kubernetes(简称 K8s)凭借其声明式 API 和自愈控制循环,已成为云原生架构的事实标准。本章将深入剖析 Kubernetes 的控制平面与工作节点架构,并围绕 Pod、Deployment、Service 三个最核心的基础对象,讲解其设计原理、操作流程、实战案例与常见误区,帮助读者建立从“会用命令”到“理解设计”的认知跃迁。

Kubernetes 核心架构与基础对象关系图 控制平面 (Control Plane) kube-apiserver etcd kube-scheduler kube-controller-mgr cloud-controller-manager 工作节点 (Worker Node) kubelet kube-proxy 容器运行时 Pod Deployment / Service kubectl / API Pod(最小调度单元) • 1~N 个容器的组合 • 共享网络命名空间/IP • 共享存储卷 Volume • 生命周期短暂,可被重建 • 支持 Readiness/Liveness 探针 • 支持资源 requests/limits • 支持 QoS 等级划分 • 支持 InitContainers 初始化 Deployment(无状态应用) • 声明式更新应用 • ReplicaSet 管理副本数 • 滚动更新 (RollingUpdate) • 回滚到历史版本 • 支持扩缩容 (HPA) • 支持金丝雀发布 • 支持蓝绿部署 • 故障自愈(重启/重建) Service(服务发现与负载均衡) • 稳定虚拟 IP (ClusterIP) • 通过 Label Selector 关联 Pod • 支持 ClusterIP/NodePort/LB • 支持 ExternalName 类型 • 基于 iptables/IPVS 转发 • 支持 SessionAffinity • 支持 Headless Service • 与 Ingress 配合暴露 HTTP

上图展示了 Kubernetes 的整体架构与三个基础对象的关系。控制平面负责全局决策与状态管理,工作节点负责实际运行容器负载。Pod 是最小调度单元,Deployment 管理 Pod 的声明式生命周期,Service 则为 Pod 提供稳定的访问入口。三者层层递进,构成了 Kubernetes 应用编排的基石。

4.1 核心架构:控制平面与工作节点的职责划分

4.1.1 核心原理:一切皆控制器

Kubernetes 架构遵循“控制平面-数据平面”分离的设计哲学。控制平面(Control Plane)由 kube-apiserver、etcd、kube-scheduler、kube-controller-manager 四个核心组件构成。其中,kube-apiserver 是所有请求的唯一入口,提供 RESTful API 并负责认证、授权与准入控制;etcd 作为分布式键值存储,持久化保存集群的全部状态,是集群的“真相来源”(Source of Truth);kube-scheduler 负责为新创建的 Pod 选择最合适的节点,其调度算法综合考虑资源请求、亲和性、污点容忍等约束;kube-controller-manager 运行着数十个控制器(如 ReplicaSet 控制器、Deployment 控制器、Namespace 控制器),它们通过 informer 机制监听 API 对象的变化,并不断将实际状态向期望状态(Spec)收敛。

工作节点(Worker Node)上运行着三个关键组件:kubelet 是节点上的“代理”,负责管理 Pod 的生命周期,包括创建、销毁、健康检查,并与容器运行时(如 containerd、CRI-O)交互;kube-proxy 负责实现 Service 的负载均衡规则,默认基于 iptables 或 IPVS 模式,将发往 Service VIP 的流量转发到后端 Pod;容器运行时 是真正执行容器启停的底层软件,Kubernetes 通过 CRI(Container Runtime Interface)接口屏蔽了不同运行时的差异。

关键理解:Kubernetes 不是直接操作容器的系统,而是操作“期望状态”的系统。用户通过 YAML 声明期望状态,控制器循环(Control Loop)持续对比期望状态与当前状态,并执行差异修正。这种声明式 API 设计,使得系统具备极强的自愈能力——当 Pod 意外崩溃时,ReplicaSet 控制器会立即创建新的 Pod 以维持副本数。

4.1.2 判断方法:如何快速定位组件故障

当集群出现异常时,可按以下路径排查:

  1. API 不可达:检查 kube-apiserver 进程、证书有效期、etcd 健康状态(etcdctl endpoint health)。
  2. Pod 一直 Pending:查看 kubectl describe pod 中的 Events,重点检查调度器是否因资源不足、污点不匹配而无法调度。
  3. Pod 反复重启:查看 kubectl logs 与 kubectl get events,判断是探针失败还是容器启动崩溃。
  4. Service 无法访问:检查 Endpoints 是否有后端地址,确认 kube-proxy 规则是否同步(iptables -L -t nat 或 ipvsadm -Ln)。

4.1.3 案例拆解:一次节点故障的自愈过程

某生产集群中,一个运行着 3 个副本的 Web 应用的节点因硬件故障宕机。初始现象:监控告警显示 NodeNotReady,应用可用性下降。分析过程:kube-controller-manager 中的 NodeLifecycleController 在节点心跳超时(默认 40 秒)后标记节点为 NotReady,再经过 5 分钟(pod-eviction-timeout)后,驱逐该节点上的 Pod。实际操作:系统自动在健康节点上重新创建了 3 个 Pod,整个过程无需人工干预。结果对比:故障恢复时间约 6 分钟,期间服务通过 Service 的负载均衡自动摘除故障节点上的 Pod,用户无感知。复盘经验:生产环境必须配置 PodDisruptionBudget(PDB)以保护关键应用在主动驱逐时不被全部杀死,同时应设置合理的 terminationGracePeriodSeconds 以优雅处理存量请求。

4.1.4 常见误区与总结

  • 误区一:认为 kubectl 直接操作容器。实际上 kubectl 只与 apiserver 通信,apiserver 再将变更写入 etcd,kubelet 监听变化后执行。
  • 误区二:忽略 etcd 的备份。etcd 是集群的命脉,必须定期备份并测试恢复流程。
  • 误区三:所有组件都部署在同一节点。生产环境应将 etcd 与控制平面组件分离部署,避免单点故障。
组件职责故障影响关键监控指标
kube-apiserverAPI 入口、认证授权集群不可写QPS、延迟、错误率
etcd状态存储集群不可用Leader 变更、磁盘 fsync 延迟
kube-schedulerPod 调度新 Pod 无法调度调度失败率、调度延迟
kubelet节点 Pod 管理节点不可调度PLEG 延迟、容器重启次数

4.2 Pod:最小调度单元的设计与多容器模式

4.2.1 核心原理:为什么需要 Pod 这一层抽象

Pod 是 Kubernetes 中可创建和部署的最小单元,它封装了一个或多个紧密相关的容器。Pod 内的容器共享同一个网络命名空间(即共享 IP 和端口空间)、共享存储卷(Volume),并且可以通过 localhost 互相通信。这种设计解决了两个核心问题:一是“超亲密关系”的容器(如主容器与 Sidecar 日志收集容器)必须部署在同一节点并共享生命周期;二是为容器提供了更细粒度的资源调度单位——调度器以 Pod 为单位分配资源,而非单个容器。

Pod 支持两种探针:LivenessProbe(存活探针)用于判断容器是否存活,失败则重启容器;ReadinessProbe(就绪探针)用于判断容器是否准备好接收流量,失败则从 Service Endpoints 中摘除。此外,Pod 还支持 InitContainers(初始化容器),它们按顺序在应用容器启动前运行,适合执行数据库迁移、权限设置等一次性任务。

4.2.2 操作流程:创建与调试 Pod

# 创建 Pod
kubectl run nginx --image=nginx:1.25 --port=80 --dry-run=client -o yaml > pod.yaml
kubectl apply -f pod.yaml

# 查看 Pod 状态与详情
kubectl get pods -o wide
kubectl describe pod nginx

# 进入容器调试
kubectl exec -it nginx -- /bin/sh

# 查看日志(多容器需指定 -c)
kubectl logs nginx -c main-container

# 端口转发(临时调试)
kubectl port-forward pod/nginx 8080:80

4.2.3 实战场景:Sidecar 模式实现日志采集

某微服务应用需要将日志实时采集到 Elasticsearch。初始方案:在应用代码中集成日志 SDK,导致耦合度高且升级困难。优化方案:采用 Sidecar 模式,在同一个 Pod 中运行两个容器——主容器运行 Java 应用,Sidecar 容器运行 Filebeat。关键配置:两个容器共享一个 emptyDir 卷,主容器将日志写入 /var/log/app,Filebeat 监听同一目录并转发。操作步骤:定义 Pod 时声明两个容器,挂载同一 Volume,设置 Filebeat 的配置文件。结果对比:日志采集延迟从原来的 30 秒降低到 3 秒,且应用代码零侵入。风险与代价:每个 Pod 多消耗约 100MB 内存,但换来了运维的标准化。复盘经验:Sidecar 模式适合日志、监控、网络代理等横切关注点,但若资源紧张,可考虑使用 DaemonSet 集中采集。

4.2.4 常见误区与总结

  • 误区一:在一个 Pod 中放入多个无关联的容器。Pod 内的容器应共享生命周期,否则应拆分为多个 Pod。
  • 误区二:忘记设置资源 requests/limits。不设置 requests 会导致调度器无法合理分配资源,不设置 limits 可能导致单容器耗尽节点内存。
  • 误区三:探针配置过于激进。例如 LivenessProbe 的超时时间过短,可能导致容器被频繁重启。
风险提示:Pod 是“有生命”的实体,它可能因节点故障、资源驱逐、手动删除等原因被重建。因此,任何需要持久化的数据都应使用 PersistentVolume(PV),任何需要稳定访问入口的场景都应使用 Service,而不是直接依赖 Pod IP。

4.3 Deployment:声明式应用管理与发布策略

4.3.1 核心原理:从 ReplicaSet 到 Deployment

Deployment 是管理无状态应用的最高层抽象,它通过管理 ReplicaSet(副本集)来间接管理 Pod。ReplicaSet 负责维持指定数量的 Pod 副本,而 Deployment 则在 ReplicaSet 之上增加了版本管理、滚动更新、回滚等能力。当用户更新 Deployment 的 Pod 模板(如镜像版本)时,Deployment 会创建一个新的 ReplicaSet,并逐步缩容旧 ReplicaSet、扩容新 ReplicaSet,从而实现平滑升级。

Deployment 支持两种更新策略:RollingUpdate(滚动更新,默认)和 Recreate(先删后建)。滚动更新通过 maxSurge(最大额外副本数)和 maxUnavailable(最大不可用副本数)两个参数控制更新速率,例如 maxSurge: 25% 表示更新过程中最多允许超出期望副本数 25% 的额外 Pod。

4.3.2 操作流程:发布与回滚

# 创建 Deployment
kubectl create deployment web --image=nginx:1.25 --replicas=3

# 更新镜像版本
kubectl set image deployment/web nginx=nginx:1.26

# 查看滚动更新状态
kubectl rollout status deployment/web

# 查看历史版本
kubectl rollout history deployment/web

# 回滚到上一个版本
kubectl rollout undo deployment/web

# 暂停/恢复更新(用于金丝雀发布)
kubectl rollout pause deployment/web
kubectl rollout resume deployment/web

4.3.3 案例拆解:金丝雀发布实现低风险上线

某电商平台的核心交易系统需要从 v1.0 升级到 v2.0,要求错误率不超过 0.1% 才能全量发布。初始目标:验证新版本在真实流量下的稳定性。关键参数:副本数 10 个,金丝雀比例 10%(即 1 个新版本 Pod)。操作步骤:首先创建 v2.0 的 Deployment,副本数设为 1,同时保持 v1.0 的 Deployment 运行 9 个副本;然后通过 Service 的标签选择器将两个 Deployment 的 Pod 都纳入负载均衡;观察 30 分钟,监控新版本 Pod 的错误率、P99 延迟。结果对比:新版本 P99 延迟从 120ms 上升到 150ms,但错误率仅为 0.05%,符合预期,于是将 v2.0 的副本数扩展到 10,并缩容 v1.0 至 0。风险与代价:金丝雀期间需要人工监控,且 Service 的负载均衡是随机的,无法精确控制流量比例。复盘经验:若需要精确流量比例,应使用服务网格(如 Istio)或 Argo Rollouts 等高级发布工具。

4.3.4 常见误区与总结

  • 误区一:直接修改 Deployment 的标签选择器。选择器是不可变的,修改会导致 ReplicaSet 失控。
  • 误区二:滚动更新时未设置 maxUnavailable: 0 和 maxSurge: 1 来保证不中断服务。对于有状态服务,应使用 StatefulSet 而非 Deployment。
  • 误区三:忽略 revisionHistoryLimit 的配置。默认保留 10 个历史版本,过多会占用 etcd 存储。
发布策略适用场景优点缺点
Recreate开发环境、允许短暂停机简单、资源占用低有停机时间
RollingUpdate生产环境、无状态服务平滑升级、零停机新旧版本共存期需兼容
金丝雀(手动)高风险变更风险可控、流量小需要人工介入
蓝绿部署需要快速回滚切换迅速需要双倍资源

4.4 Service:服务发现与负载均衡的四种类型

4.4.1 核心原理:稳定访问入口的抽象

由于 Pod 的 IP 是动态变化的,Kubernetes 提供了 Service 对象来提供稳定的访问入口。Service 通过 Label Selector 选择一组 Pod,并为其分配一个虚拟 IP(ClusterIP)。当请求到达 Service 时,kube-proxy 根据转发规则(iptables 或 IPVS)将流量负载均衡到后端的 Pod 上。Service 支持四种类型:ClusterIP(默认,集群内访问)、NodePort(通过节点 IP+端口访问)、LoadBalancer(云厂商负载均衡器)、ExternalName(映射到外部域名)。

Service 还支持 Headless Service(设置 clusterIP: None),此时 Service 不提供负载均衡,而是直接返回后端 Pod 的 IP 列表,适用于需要自行实现负载均衡的场景(如数据库主从连接)。此外,Service 的 sessionAffinity 字段可以设置会话保持,默认值为 None,可设置为 ClientIP 以将同一客户端的请求转发到同一 Pod。

4.4.2 操作流程:创建 Service 并验证

# 暴露 Deployment 为 Service
kubectl expose deployment web --port=80 --target-port=8080 --type=ClusterIP

# 查看 Service 与 Endpoints
kubectl get svc web
kubectl get endpoints web

# 测试集群内访问
kubectl run test --image=busybox --rm -it -- wget -O- http://web:80

# 修改为 NodePort 类型
kubectl patch svc web -p '{"spec":{"type":"NodePort"}}'

4.4.3 实战场景:Ingress 与 Service 配合暴露 HTTP 服务

某微服务集群中有 5 个 HTTP 服务,如果每个服务都使用 LoadBalancer 类型,将产生 5 个云负载均衡器,成本高昂。优化方案:使用 Ingress Controller(如 Nginx Ingress)作为统一入口,Ingress 根据域名和路径将请求转发到不同的 Service。关键配置:创建一个 Ingress 资源,定义 host: api.example.com,路径 /users 转发到 user-service,路径 /orders 转发到 order-service。操作步骤:部署 Nginx Ingress Controller,创建 Ingress 规则,配置 DNS 解析到 Ingress Controller 的 LoadBalancer IP。结果对比:云资源成本降低 80%,且实现了统一的 TLS 终止和流量治理。风险与代价:Ingress Controller 成为新的单点,需要部署多个副本并配置健康检查。复盘经验:Ingress 适合 HTTP/HTTPS 流量,对于 TCP/UDP 流量应使用 Service 的 LoadBalancer 类型或 NodePort。

4.4.4 常见误区与总结

  • 误区一:Service 的 selector 写错导致 Endpoints 为空。应使用 kubectl get endpoints 验证。
  • 误区二:混淆 targetPort 与 port。port 是 Service 对外暴露的端口,targetPort 是 Pod 内容器监听的端口。
  • 误区三:认为 Service 可以做应用层路由。Service 只做四层转发,七层路由需要 Ingress 或服务网格。
经验建议:在微服务架构中,建议为每个 Deployment 都创建一个对应的 Service,并遵循“服务名.命名空间.svc.cluster.local”的 DNS 命名规范。这样,服务间调用只需使用服务名即可,无需关心 Pod IP 的变化。

4.5 本章总结与最佳实践

本章从架构、对象、操作三个维度梳理了 Kubernetes 的核心基础。读者应重点掌握以下要点:第一,理解控制平面与工作节点的职责边界,知道故障发生时该查看哪个组件的日志;第二,Pod 是资源调度的最小单位,多容器设计需遵循“共享生命周期”原则;第三,Deployment 是生产环境管理无状态应用的标准方式,务必掌握滚动更新与回滚操作;第四,Service 是服务间通信的桥梁,应根据访问范围选择合适的类型。

在实际项目中,建议遵循以下最佳实践:所有工作负载都应设置资源 requests/limits;为关键应用配置 PDB 与多副本;使用 Namespace 隔离不同环境(dev/staging/prod);定期备份 etcd 并演练恢复流程;将 kubectl 操作封装为 CI/CD 流水线,避免人工误操作。容器编排的入门不是记住命令,而是建立“声明式、自愈、可扩展”的云原生思维模式。