Kubernetes 核心组件详解与实战:从控制平面到应用上线

系统讲解 kube-apiserver、etcd、Scheduler、Controller Manager、kubelet、容器运行时、CNI、Service、Ingress、存储、调度与安全,并提供完整的部署、验收和故障排查实践。

技术文章约 25 分钟122 次阅读

#开篇:一个由声明与调谐驱动的控制系统

Kubernetes 解决的是一类组织性问题:在成百上千台机器上,如何让"用户声明的应用期望状态"被持续、一致、可自动修复地翻译成"节点上真实运行的进程"。它背后最基础的机制,是一套声明式 API 与控制器循环:用户只描述终态(要 3 个副本、镜像是什么、端口如何暴露),系统内的所有组件围绕同一份事实状态各司其职,把现实不断推向期望。

因此,Kubernetes 不只是一个"运行容器的工具",而是一组围绕声明式 API 协作的控制系统。理解组件之间如何协作,比记住大量 kubectl 命令更重要。本文以一个名为 web 的无状态 HTTP 服务为例,先沿因果链拆解每个组件的职责与底层工作机制,再给出可以在测试集群中完整复现的操作、验证方法与常见坑。

#原理层:组件职责与控制回路

#一次发布请求在集群中经过的完整链路

集群可以分成控制平面与工作节点两部分:控制平面保存集群状态并作出调度、编排决策;工作节点负责实际运行 Pod。组件之间主要通过 Kubernetes API Server 交互,而不是彼此随意修改数据库。

一次 kubectl apply -f deployment.yaml 发布大致经过以下链路:

  1. 用户通过 kubectl、CI 或另一个控制器向 API Server 提交 Deployment;
  2. API Server 完成认证、授权、准入检查与对象持久化(写入 etcd);
  3. Deployment Controller 观察到新对象,创建或更新 ReplicaSet;
  4. ReplicaSet Controller 创建 Pod 对象;
  5. Scheduler 为没有节点的 Pod 选择合适节点,并把绑定结果写回 Pod 的 spec.nodeName;
  6. 目标节点的 kubelet 观察到属于自己的 Pod,调用容器运行时创建 Pod sandbox 与容器;
  7. kube-proxy 或 CNI 规则让 Service 流量能够到达 Pod;
  8. kubelet 上报容器状态,Deployment Controller 根据副本数继续调谐。

这个过程体现了三个原则:API 对象是事实来源,控制器是状态转换器,kubelet 是节点侧执行者。手工登录节点修改容器,通常会绕开 Kubernetes 的控制循环,重启后也会丢失。

#声明式 API:期望状态如何以 etcd 为唯一事实源

所有 Kubernetes 对象——Deployment、Pod、Service、Secret、ConfigMap、RBAC、Namespace——都是 API 资源,它们的权威版本存放在 etcd 中(默认键前缀为 /registry)。任何组件都不直接读写 etcd,而是通过 API Server 的 REST 接口完成增删改查;API Server 完成校验后把对象持久化到 etcd。这个设计的收益是:

  • 写入路径唯一:所有变更都经过同一套认证、授权、准入与 schema 校验;
  • 读取路径统一:apiserver 是 etcd 之上的唯一门面,etcd 不暴露给业务组件;
  • 变更可被订阅:apiserver 把对象的写事件以 watch 流推送给所有监听者,控制器据此即时响应,而不必反复全量轮询。

"声明式"的含义是:用户提交的期望状态(replicas: 3、image: nginx:1.27.0)描述的是"最终应该长什么样",而不是"接下来执行哪几条命令"。如何达成由控制器决定。这带来三个直接好处:状态可查询(随时知道期望值)、可对比(期望与现状的差值就是控制器的工作量)、可回滚(历史版本仍在 API 对象中)。命令式操作(例如手工 ssh 到节点启动容器)则不具备这些性质,既不可审计,也无法在故障后自动恢复。

etcd 中的每个对象都带 resourceVersion,写入时可通过该字段做乐观并发控制:如果两个控制器同时基于同一版本修改对象,后写者会因版本不匹配而收到冲突错误,从而避免互相覆盖。这一点是"唯一事实源"在并发环境下依然成立的基石。

#kube-apiserver:唯一入口上的认证、授权与准入

kube-apiserver 是集群的统一入口。kubectl、控制器、调度器、Operator 与外部系统都通过它读取或修改资源;它还负责认证、授权、准入控制、版本转换、审计以及与 etcd 的读写协调。

一个请求进入 API Server 后通常依次经过 5 个关卡:

  1. TLS 与身份认证:客户端证书、ServiceAccount Token、OIDC 或 Webhook Token 认证等,回答"你是谁";
  2. 授权判断:RBAC 等授权模式是否允许该用户在某个命名空间创建 Deployment,回答"你能做什么";
  3. 准入控制:MutatingAdmissionWebhook(允许改写对象)、ValidatingAdmissionWebhook(允许拒绝对象)、Pod Security Admission、ResourceQuota、LimitRange 与自定义准入策略,回答"这个请求能否进入系统";
  4. schema 校验与默认值填充:API 版本转换、字段默认值、OpenAPI 校验;
  5. 写入或读取 etcd:读请求走缓存或 watch,写请求持久化。

看懂这个顺序对排障很有用:TLS 握手失败报证书错误,RBAC 拒绝报 Forbidden,准入拦截报 denied 或 webhook 错误,schema 错误报 invalid——错误发生在哪一步,就说明问题出在哪一层。

常用检查命令:

kubectl cluster-info
kubectl version
kubectl api-resources | head -n 30
kubectl get --raw='/readyz?verbose'
kubectl auth can-i create deployments -n demo

kubectl auth can-i 用于自查授权结果,是定位"为什么创建被拒绝"的首选工具。API Server 访问异常时,先确认 kubeconfig、证书有效期、DNS、负载均衡与控制平面网络;不要直接删除 API Server Pod 作为第一反应,先看控制平面日志、节点状态与 etcd 健康。

#etcd:强一致的集群状态数据库

etcd 是基于 Raft 共识算法的强一致分布式键值存储,保存 Deployment、Pod、Service、Secret、ConfigMap、RBAC 与大量集群元数据。写入需要多数成员确认,因此天然保证"读到的就是最新提交的值"——这正是"唯一事实源"的物理基础。它通过 WAL(预写日志)持久化每次变更,并定期压缩(compaction)历史版本,防止存储无限增长。

etcd 不是普通缓存,磁盘延迟、空间与备份质量会直接影响整个集群:提交延迟过高会拖慢所有写请求,空间耗尽会让集群拒绝写入,备份缺失会造成不可恢复的数据丢失。生产环境要关注:

  • 使用奇数成员数(3、5、7),并把成员分布在故障域中,满足多数派可用;
  • 使用低延迟、可靠的 SSD 与独立磁盘,避免与业务 IO 争抢;
  • 启用 TLS、客户端认证与 peer 认证;
  • 定期做快照,并在隔离环境实际恢复;
  • 监控 leader 变更、提交延迟、数据库大小与磁盘剩余空间。

快照与恢复示例(路径与证书以 kubeadm 或发行版实际配置为准):

ETCDCTL_API=3 etcdctl snapshot save /backup/etcd-$(date +%F).db \
  --endpoints=https://127.0.0.1:2379 \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/healthcheck-client.crt \
  --key=/etc/kubernetes/pki/etcd/healthcheck-client.key
ETCDCTL_API=3 etcdctl snapshot status /backup/etcd-$(date +%F).db -w table

恢复时用 snapshot restore 把快照还原到新的数据目录(多成员集群还需处理 name、initial-cluster 等成员参数,完整步骤以官方备份恢复文档为准):

ETCDCTL_API=3 etcdctl snapshot restore /backup/etcd-$(date +%F).db \
  --data-dir=/var/lib/etcd-restore

不要把 etcd 快照当作唯一备份:备份文件应有访问控制、校验和、异地副本与恢复演练记录。

#控制器:informer/watch 循环如何收敛期望状态

kube-controller-manager 运行多个控制器:Deployment、ReplicaSet、Node、Job、Namespace、ServiceAccount、EndpointSlice 相关控制器等。它们的共同模式是"调谐循环":

  1. 通过 informer 对目标资源执行 List + Watch,并在内存中维护一份本地缓存(indexer);
  2. 收到创建、更新、删除事件后,把对象放入工作队列;
  3. 工作线程取出对象,对比期望状态与集群当前实际状态;
  4. 差异不为零则执行动作(创建或更新 ReplicaSet、创建 Pod、更新 status),并把结果状态写回 API Server;
  5. 事件继续驱动下一轮,直到期望状态满足;定期的 resync 还能兜底纠正漏掉或漂移的状态。

例如 Deployment 的副本数为 3 时,Deployment Controller 会确保存在匹配的 ReplicaSet,ReplicaSet Controller 再确保有 3 个可运行 Pod。Pod 被节点故障删除后,控制器会创建替代 Pod;这不是 kubelet 在做全局决策。informer 的本地缓存显著降低了对 apiserver 的读压力,这也是为什么控制器不"每次全量查表",而是订阅变更。

高可用部署中,controller-manager 与 scheduler 通常以多副本运行,靠 leader election 选出唯一活跃实例,避免多个控制器同时对同一对象调谐造成写冲突。

控制器排障要看对象之间的 ownerReferences、selector 与事件:

kubectl describe deployment web -n demo
kubectl get rs,pod -n demo -l app=web --show-labels
kubectl get events -n demo --sort-by=.lastTimestamp

修改 selector 要格外谨慎。selector 不匹配会造成控制器无法管理原有 Pod,甚至产生重复副本或错误发布。

#kube-scheduler:过滤、打分与节点绑定

Scheduler 只负责为待调度 Pod 选择节点,不负责启动容器。它先过滤不满足条件的节点(predicates),再对可行节点打分(priorities),最后把得分最高的节点写入 Pod 的 spec.nodeName(通过 binding 子资源写回),Pod 随即在 API 对象层面完成"绑定"。

影响调度的常见条件包括:

  • 节点资源请求是否有足够 CPU 与内存(requests 参与,limits 不参与调度);
  • nodeSelector、nodeAffinity 与 taint/toleration;
  • PodAffinity、PodAntiAffinity 与拓扑分布约束;
  • 节点污点、可用区、架构与 GPU 资源;
  • 优先级、抢占与调度器扩展(schedulerName 指定的自定义调度器或调度框架插件)。

打分阶段会综合资源余量、亲和性与分布偏好;例如在同等可用节点中,默认策略倾向于把新 Pod 放到资源最不紧张的节点(如 NodeResourcesFit/LeastRequested 一类目标),以保持节点负载均衡。

排查 Pending Pod:

kubectl get pod -n demo
kubectl describe pod -n demo <pod-name>
kubectl get nodes -o wide
kubectl describe node <node-name>

重点看 Events 中的 Insufficient cpu、Insufficient memory、node(s) had taint、node affinity conflict 与 volume binding 失败。kubectl get pod -o wide 的 NODE 列就是调度结果:一直为空说明 Pod 还停留在调度队列中。不要只给 Pod 增加副本数,先确认资源请求、节点容量与调度约束是否互相矛盾。

#kubelet 与容器运行时:把 PodSpec 执行成真实进程

kubelet 是节点上的执行与上报代理。它监听 API Server 中"分配给自己所在节点"的 Pod(按 spec.nodeName 过滤订阅),在同步循环里把 PodSpec 转换成节点上的实际容器,并向 API Server 上报节点与 Pod 状态。它管理探针、卷挂载、镜像拉取、容器重启、优雅终止与资源回收;节点心跳则通过 Lease 对象定期续约,供控制平面判断节点是否存活。

kubelet 并不会为任意本地容器提供 Kubernetes 管理。只有被 API Server 分配到本节点、静态 Pod 清单(kubeadm 默认目录 /etc/kubernetes/manifests)或节点配置声明的工作,才属于它的控制范围。

kubelet 与容器运行时之间通过 CRI(Container Runtime Interface)交互:kubelet 调用 RunPodSandbox 创建 Pod 沙箱(网络命名空间),再 CreateContainer、StartContainer 启动容器,并持续上报容器状态。常见运行时包括 containerd 与 CRI-O。运行时负责镜像拉取、容器生命周期、sandbox、日志与 cgroup 配置;它不负责 Deployment 的副本调谐——那是控制平面控制器的职责。

节点排查命令:

kubectl get nodes
kubectl describe node <node-name>
kubectl get pods -A -o wide --field-selector spec.nodeName=<node-name>
sudo journalctl -u kubelet -n 200 --no-pager

检查运行时:

kubectl get nodes -o wide
sudo crictl info
sudo crictl ps -a
sudo crictl images

节点 NotReady 时检查 kubelet、容器运行时、CNI、磁盘压力、内存压力、证书、时间同步与到 API Server 的网络。不要先执行 kubectl delete node,这会丢失节点对象和排障上下文。镜像拉取失败要区分认证、仓库 DNS、TLS、架构不匹配、磁盘空间与镜像 tag 不存在;生产环境应固定 digest 或经过验证的版本,不要使用无法审计的 latest。

#kube-proxy、EndpointSlice 与 CNI:Service 流量如何到达 Pod

Service 提供稳定的虚拟 IP、DNS 名称与端口,但"谁来执行转发"由控制器、kube-proxy 与 CNI 分工完成:

  • 控制器把匹配 selector 且 readiness 通过的 Pod 汇总为 EndpointSlice(端点是 Pod IP + targetPort 的列表,端点带 ready 条件标记);
  • kube-proxy 通过 informer 监听 Service 与 EndpointSlice 变化,在节点上生成转发规则。传统实现是 iptables(如 KUBE-SERVICES 链,随机挑选后端);需要更高性能与更多调度算法时用 IPVS(支持 rr、lc 等负载均衡算法与基于 clientIP 的会话保持);现代集群也可能用 eBPF 数据平面(如 Cilium)替代部分 kube-proxy 能力;
  • CNI 插件负责 Pod 网络本身:分配 Pod IP、创建网卡与路由、实现跨节点通信。Calico、Cilium、Flannel 与云厂商网络插件在策略、可观测性与实现细节上不同。

关键机制:kube-proxy 本身不做健康探测,它只依据 EndpointSlice 中的 ready 端点转发。一个 Pod 是否进入 EndpointSlice,取决于它的 readiness 探针是否通过。因此"Service 有 ClusterIP 但没有 EndpointSlice"几乎总是指向 selector、Pod label 或 readiness 问题。如果 Service 没有 selector,EndpointSlice 不会被自动创建,需要手工维护(例如把流量指向外部服务的 Endpoints)。

集群内 DNS 由 CoreDNS 提供:它监听 Service 与 Pod 变化,生成 web.demo.svc.cluster.local 这类 A 记录;kubelet 会把集群 DNS 与搜索域写进容器的 resolv.conf,因此容器内可以直接用 http://web/ 访问同命名空间下的 Service。

检查网络对象:

kubectl get pods -A -o wide
kubectl get svc,endpointslice -n demo
kubectl get networkpolicy -A
kubectl exec -n demo deploy/web -- getent hosts kubernetes.default.svc.cluster.local

服务访问失败时按顺序检查:Pod 是否 Ready、Service selector 是否匹配、EndpointSlice 是否有地址、DNS 是否正常、NetworkPolicy 是否阻断、节点路由与 CNI 日志是否有错误。不要一看到 Service 无法访问就修改 kube-proxy 参数。

#cloud-controller-manager:连接云平台能力

在云环境中,cloud-controller-manager 将 Kubernetes 对象与云厂商 API 对接:节点生命周期、云负载均衡、云路由与持久化磁盘。Service 类型 LoadBalancer、云盘 CSI 与节点地址管理通常都依赖它或云厂商组件。云控制器异常时,应用 Pod 可能正常运行,但 LoadBalancer 一直 Pending、云盘无法挂载或节点状态不完整。排查时同时查看 Kubernetes Events 与云平台审计日志,确认 IAM 权限、配额、子网、安全组与区域是否正确。

#对象层:从声明到可用的核心资源

#Namespace:隔离、作用域与多租户边界

Namespace 是集群内资源的作用域:同名的 Deployment、Service、ConfigMap 可以在不同 Namespace 共存;RBAC 的 Role/RoleBinding、ResourceQuota、LimitRange 与 NetworkPolicy 通常以 Namespace 为粒度生效。它是"逻辑隔离"的手段,而不是"安全隔离"的保证——真正的安全边界由准入控制、RBAC 与 NetworkPolicy 组合构成。

#Pod:最小调度与执行单位

Pod 是一组共享网络命名空间、IP、卷与生命周期的容器。通常一个主容器配合日志代理、代理或指标 sidecar,但不要为了"看起来模块化"把所有进程都放进一个 Pod——它们将共享 IP、网络端口与重启命运,适合放进 Pod 的是"必须同生共死"的进程组合。

Pod 的关键状态包括 Pending、Running、Succeeded、Failed 与 Unknown;容器状态还包括 Waiting、Running、Terminated。CrashLoopBackOff 不是根因,而是 kubelet 对反复崩溃容器采用退避重启的表现;要定位的是容器为什么崩溃(日志、退出码、探针、OOMKilled)。

#Deployment 与 ReplicaSet

Deployment 适合无状态应用。它通过 ReplicaSet 管理 Pod 副本,支持 RollingUpdate 与 Recreate 两种策略,并保留历史版本以便回滚。生产配置至少声明镜像、资源请求与限制、探针、优雅退出与滚动策略:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
  namespace: demo
spec:
  replicas: 3
  revisionHistoryLimit: 5
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 0
      maxSurge: 1
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      terminationGracePeriodSeconds: 30
      containers:
        - name: web
          image: nginx:1.27.0
          ports:
            - name: http
              containerPort: 80
          resources:
            requests:
              cpu: 100m
              memory: 128Mi
            limits:
              cpu: 500m
              memory: 512Mi
          readinessProbe:
            httpGet:
              path: /
              port: http
            periodSeconds: 5
          livenessProbe:
            httpGet:
              path: /
              port: http
            initialDelaySeconds: 20
            periodSeconds: 10

readiness 失败时 Pod 不接收 Service 流量,但容器可以继续运行;liveness 失败会触发重启。启动慢的应用应增加 startupProbe,避免 liveness 在初始化期间误杀进程。maxUnavailable: 0 与 maxSurge: 1 表示滚动更新时先创建新副本、再下线旧副本,保证发布窗口内始终有实例可用。

发布与回滚:

kubectl apply -f deployment.yaml
kubectl rollout status deployment/web -n demo --timeout=180s
kubectl rollout history deployment/web -n demo
kubectl rollout undo deployment/web -n demo

#Service 与 EndpointSlice

Service 提供稳定的虚拟 IP、DNS 名称与端口,将流量转发到匹配 selector 的 Pod。ClusterIP 只在集群内部访问;NodePort 暴露节点端口;LoadBalancer 通常请求云平台创建外部负载均衡。

apiVersion: v1
kind: Service
metadata:
  name: web
  namespace: demo
spec:
  selector:
    app: web
  ports:
    - name: http
      port: 80
      targetPort: http
  type: ClusterIP

示例中 targetPort: http 引用的是容器端口名称(即上面 Deployment 里 ports[].name: http),要保证名称一致。验证 Service:

kubectl get svc web -n demo
kubectl get endpointslice -n demo -l kubernetes.io/service-name=web
kubectl run curl --rm -it --restart=Never -n demo --image=curlimages/curl -- curl -fsS http://web/

Service 有 ClusterIP 但没有 EndpointSlice,通常是 selector、Pod label 或 readiness 状态不匹配。Service 端口的 port、targetPort 与容器端口名称也必须对应。

#Ingress 与 Gateway API

Ingress 描述 HTTP/HTTPS 路由,但它本身不是控制器。必须安装 NGINX Ingress、Traefik、HAProxy 或云厂商控制器,Ingress 对象才会产生实际代理配置。Gateway API 是更结构化的新一代流量 API,适合把基础设施、路由与应用团队职责分开。生产流量入口要明确 TLS 证书来源、重定向、超时、请求体大小、访问日志、健康检查与真实客户端 IP。入口返回 404 时先确认 IngressClass、host、path、Service 与控制器日志,不要只改 DNS。

#ConfigMap 与 Secret

ConfigMap 用于普通配置,Secret 用于密码、令牌与证书。但 Secret 默认可能只是 base64 编码,必须结合 KMS 静态加密、RBAC、审计与外部 Secret 管理系统。禁止把真实 Secret 写入 Git、镜像层、CI 日志或错误页面。

配置变更后要确认应用是否支持热加载。若配置作为环境变量注入,通常需要重启 Pod;若以文件挂载,应用也不一定会自动重新读取。可用 checksum annotation(把 ConfigMap 或 Secret 内容的哈希写进 Pod template annotation)让配置变更自动触发 Deployment 滚动更新。

#PV、PVC、StorageClass 与 CSI

PVC 表达应用需要的容量与访问模式,StorageClass 描述动态供给策略,PV 是实际存储资源,CSI Driver 负责与云盘、NAS 或分布式存储交互。应用不应该直接依赖某个节点上的本地路径。

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: web-data
  namespace: demo
spec:
  accessModes: ["ReadWriteOnce"]
  resources:
    requests:
      storage: 10Gi
  storageClassName: fast

排查 PVC Pending:

kubectl get pvc,pv,storageclass -n demo
kubectl describe pvc web-data -n demo
kubectl get csidrivers
kubectl get volumeattachments

扩容、删除与回收策略都可能涉及真实数据。确认 reclaimPolicy、快照、备份、跨可用区限制与 RPO/RTO 后再操作,不能把删除 PVC 当作普通清理命令。

#requests、limits 与 QoS

requests 参与调度(节点必须有多余容量才会被选中),limits 限制容器实际资源使用上限。Kubernetes 根据配置将 Pod 分类为 Guaranteed、Burstable 或 BestEffort。没有 requests 的应用可能被错误调度到容量不足的节点;过低的 limits 会造成 OOMKilled 或 CPU throttling。容量规划应基于真实指标:CPU 使用、内存工作集、峰值、启动阶段与突发流量。不要把节点总容量全部分给业务 Pod,还要为系统组件、DaemonSet、镜像缓存与故障迁移预留空间。

#节点选择、污点与拓扑分布

nodeSelector 适合简单标签匹配,nodeAffinity 支持更复杂的硬约束与软偏好。taint/toleration 用于阻止普通 Pod 进入专用节点,例如 GPU、存储或控制平面节点。topologySpreadConstraints 可将副本分散到不同节点或可用区。调度策略的目标不是把 Pod 塞满节点,而是在可用性、成本、数据局部性与故障域之间做平衡。高可用服务至少避免所有副本落在同一节点;数据库还要结合存储复制与故障切换能力。

#ServiceAccount、RBAC 与 Pod 身份

ServiceAccount 是 Pod 访问 Kubernetes API 的身份。Role 与 RoleBinding 限制命名空间内权限;ClusterRole 与 ClusterRoleBinding 可作用于集群范围。应用只应获得完成工作所需的最小权限。

kubectl auth can-i get secrets -n demo --as=system:serviceaccount:demo:web
kubectl auth can-i list pods -n demo --as=system:serviceaccount:demo:web
kubectl get role,rolebinding -n demo

--as 参数可以模拟该 ServiceAccount 视角做授权查询,是验证 RBAC 是否过严或过宽的便捷手段。禁止给普通应用绑定 cluster-admin;令牌要有生命周期与轮换策略;云资源访问优先使用云厂商 Workload Identity,而不是把长期密钥写进 Secret。

#Pod Security 与 NetworkPolicy

Pod Security Admission 可以限制特权容器、hostNetwork、hostPath、root 用户与 Linux capabilities。NetworkPolicy 控制 Pod 入站与出站流量,但前提是 CNI 支持并正确执行策略。安全基线至少考虑:

  • 以非 root 用户运行;
  • 只读根文件系统,按需增加 writable volume;
  • 删除不需要的 capabilities;
  • 禁止 privilege escalation;
  • 限制 egress 到数据库、DNS 与必要外部服务;
  • 为命名空间配置 ResourceQuota 与 LimitRange。

安全策略上线前先在测试命名空间验证,避免一条默认拒绝策略切断 DNS、监控或控制器通信。

#操作层:完整可复现的实施步骤

#前置条件与版本约定

  • 集群:在 kind、minikube、k3d 或独立测试集群中执行;
  • 版本:示例使用 Kubernetes 1.28+ 常见 API,具体字段仍应以目标集群版本和发行版文档为准;
  • 工具:kubectl 已配置并指向目标集群,具备创建 Namespace、Deployment、Service 与临时 Pod 的权限;
  • 安全:文中的 namespace、Deployment 与 Service 名称均为示例;生产环境执行破坏性命令前必须核对上下文、命名空间、镜像与数据备份。

#完整示例:Namespace → Deployment → Service

创建命名空间并部署最小应用:

kubectl create namespace demo
kubectl config set-context --current --namespace=demo
kubectl create deployment web --image=nginx:1.27.0 --replicas=3
kubectl expose deployment web --port=80 --target-port=80
kubectl rollout status deployment/web --timeout=120s

这段命令背后的因果链:create deployment 让 Deployment Controller 创建 ReplicaSet,ReplicaSet Controller 创建 3 个 Pod,Scheduler 为每个 Pod 绑定节点,kubelet 拉取镜像并启动容器;expose 创建 ClusterIP Service,EndpointSlice Controller 把 3 个 Ready Pod 的地址写入 EndpointSlice,kube-proxy 据此生成转发规则。

用规范文件复现时(YAML 见上文 Deployment 与 Service 两节):

kubectl apply -f deployment.yaml
kubectl apply -f service.yaml

#观察组件行为的诊断命令

检查对象关系与网络:

kubectl get deploy,rs,pod,svc -o wide
kubectl get endpointslice
kubectl run test-client --rm -it --restart=Never --image=curlimages/curl -- curl -fsS http://web/

观察控制器与调度行为:

kubectl describe deployment web -n demo
kubectl get rs,pod -n demo -l app=web --show-labels
kubectl describe pod -n demo <pod-name>
kubectl get events -n demo --sort-by=.lastTimestamp

kubectl describe pod 的 Events 里能读出 Scheduler 的调度结果与 kubelet 的拉取、启动过程;kubectl get events --sort-by=.lastTimestamp 能还原整条控制链路的时序。

#发布失败演练与回滚

模拟发布失败时,不要直接删除 Deployment。可以发布一个明确错误的镜像 tag,在测试环境观察 rollout:

kubectl set image deployment/web web=nginx:does-not-exist
kubectl rollout status deployment/web --timeout=60s || true
kubectl get pods
kubectl rollout undo deployment/web
kubectl rollout status deployment/web --timeout=120s

|| true 让 rollout 失败时脚本继续执行,便于继续观察;随后 rollout undo 回到上一版本。这个演练可以验证镜像拉取错误、滚动更新保护、事件记录与回滚权限。测试完成后清理资源:

kubectl delete namespace demo
kubectl config set-context --current --namespace=default

删除 Namespace 会连带删除其中全部资源,生产环境执行前必须确认没有未备份的数据。

#验证层:如何确认做对了

#端到端验证

最直接的判据是把三条链路同时打通:副本数(kubectl get deploy 的 READY 列)、调度(全部 Pod Running 且分布在预期节点)、流量(集群内 curl -fsS http://web/ 返回 200)。再叠加一轮故障演练(错误镜像 → rollout 卡住 → undo 恢复),确认控制器、Scheduler、kubelet 与 kube-proxy 都产生了真实的、可观察的动作。

#组件与对象健康检查

  • API Server:kubectl get --raw='/readyz?verbose' 各检查项为 ok;kubectl cluster-info 正常;
  • 认证授权:kubectl auth can-i create deployments -n demo 返回 yes;
  • etcd:快照可保存且 snapshot status 校验通过,leader 稳定;
  • 控制器:Deployment/ReplicaSet 事件无持续报错,kubectl get events 能解释每个状态变化;
  • 节点:kubectl get nodes 全部 Ready,kubectl describe node 无 Pressure;
  • Service:EndpointSlice 中 ready 端点数量与 Ready Pod 数一致;
  • 运行时与网络:crictl ps 能看到容器,getent hosts kubernetes.default.svc.cluster.local 能解析出 ClusterIP。

#按症状排查故障

从底层机制出发,任何症状都可以映射到控制链路的某一环:对象错、控制器未调谐、调度失败、节点未执行、网络或存储不可达、应用未就绪。

#Pod 一直 Pending

先看 kubectl describe pod 的 Events,再检查节点可用资源、污点、亲和性、PVC 与调度约束。资源 request 过大、节点没有匹配标签、存储无法绑定是最常见原因。

#Pod CrashLoopBackOff

查看上一轮容器日志与退出码:

kubectl logs -n demo <pod-name> --previous
kubectl describe pod -n demo <pod-name>
kubectl get pod -n demo <pod-name> -o jsonpath='{.status.containerStatuses[*].lastState}'

重点排查配置缺失、启动参数、权限、依赖不可达、探针过严与 OOMKilled。不要只增加重启次数。

#Service 无法访问

检查 selector、Pod label、readiness、EndpointSlice、Service 端口与 NetworkPolicy。集群内用 DNS 名称测试;节点外访问则继续检查 Ingress、LoadBalancer、安全组与证书。

#发布后流量异常

同时观察 rollout 状态、旧新 ReplicaSet、Pod 事件、应用日志、请求延迟、错误率与连接数。readiness 只应在应用真正能接流量时成功,不能用进程存活替代业务就绪。

#节点 NotReady

查看节点 Conditions、kubelet 日志、容器运行时、CNI、磁盘与内存压力。若需要维护,先 cordon,再在确认工作负载可迁移后 drain:

kubectl cordon <node-name>
kubectl drain <node-name> --ignore-daemonsets --delete-emptydir-data

drain 可能受 PDB、裸 Pod、本地数据与不可驱逐工作负载影响,生产执行前必须确认业务容量与恢复方案。

#边界与常见坑

#经验教训清单

  • 不要手工修改节点上的容器或 etcd 数据:绕开控制循环的改动既不可审计,也会在下次调谐时被覆盖;
  • 不要随意修改 Deployment/Service 的 selector:控制器会丢失对既有 Pod 的管理,可能产生重复副本或错误发布;
  • 不要一看到 Pending 就加副本:先定位是资源不足、污点、亲和性还是存储绑定失败;
  • 不要一看到 Service 不通就调 kube-proxy:先核对 Pod Ready、selector、EndpointSlice、DNS 与 NetworkPolicy;
  • 不要一看到节点 NotReady 就 kubectl delete node:保留节点对象有利于从 Conditions 与日志定位根因;
  • CrashLoopBackOff 是结果不是原因;latest 镜像 tag 无法审计也无法稳定复现,生产应固定 digest;
  • Secret 不等于安全:默认 base64 编码,必须靠 KMS 加密、RBAC、审计与外部密钥管理补足;
  • 容量规划要留余量:把节点全部容量分给业务 Pod,系统组件、DaemonSet 与故障迁移就没有空间;
  • 破坏性操作(删除 Namespace、delete PVC、drain)前必须核对上下文与备份。

#生产上线验收清单

  • 控制平面:API Server readyz 正常,etcd 已做恢复演练,Scheduler 与 Controller Manager 无持续错误,审计日志与证书轮换机制正常;
  • 节点:所有节点 Ready,kubelet 与运行时健康,CNI 连通,磁盘与 inode 有余量,时间同步正常,节点标签、污点与架构符合规划;
  • 应用:Deployment rollout 成功,副本分布符合故障域设计,requests/limits 合理,startup/readiness/liveness 探针经过压测,优雅终止与回滚已经演练;
  • 网络:Service EndpointSlice 正常,集群 DNS 可用,NetworkPolicy 只开放必要流量,Ingress/Gateway 的 TLS、超时、访问日志与真实 IP 配置已验证;
  • 存储:PVC 绑定成功,挂载与卸载正常,快照与备份可以恢复,删除与回收策略符合数据保留要求;
  • 安全:RBAC 遵循最小权限,Pod 不使用不必要的特权,Secret 有加密与轮换方案,镜像来源、漏洞扫描与供应链记录完整;
  • 可观测性:应用日志、事件、指标、追踪与告警可用,能够区分调度、启动、网络、依赖与业务错误。上线记录应包含镜像 digest、配置版本、变更人、开始时间、成功标准与回滚命令。

#收尾

Kubernetes 的核心不是某一个组件,而是 API Server、etcd、控制器、Scheduler、kubelet、运行时与网络存储插件之间形成的控制回路。遇到问题时,沿着"期望对象是否正确 → 控制器是否调谐 → Pod 是否调度 → 节点是否执行 → 网络与存储是否可达 → 应用是否真正就绪"的顺序排查,通常比直接重启更快定位根因。掌握这些边界后,再学习 Operator、Service Mesh、GPU 调度、Serverless 或多集群管理,都会有更清晰的落点:它们本质上是在 Kubernetes API 与控制循环之上扩展新的资源、策略与执行能力。

相关阅读

Related

留言讨论

0 条

还没有留言,来说点什么吧。

Kubernetes 核心组件详解与实战:从控制平面到应用上线 · LXH·BLOG