7AA7 Blog

Kubernetes 核心概念:Pod、Deployment 与 Service

Pipeline 郑 UID:131
2026-09-08 19:12
35 3 0

理解 Kubernetes 的关键不在于记住命令,而在于看清声明式 API 与控制器循环。用户提交的是期望状态,例如“始终运行三个副本”,控制器持续观察实际状态,计算差异并执行创建、更新或删除,直到两者收敛。某个 Pod 被节点故障带走后,系统不会修复原 Pod,而是创建符合模板的新 Pod。

声明式 API 与控制器循环

资源对象通常包含 metadata、spec 和 status。spec 由用户表达期望,status 由控制面和控制器回写实际情况。控制器的工作逻辑可以抽象为:

循环:
  actual = observe()
  desired = read(spec)
  diff = compare(desired, actual)
  reconcile(diff)

这个循环必须允许重复执行。网络超时、控制器重启或并发修改都可能让一次操作只完成一半,幂等的调谐过程会在下一轮继续收敛。kubectl apply 返回成功只表示 API 对象已被接收,不表示工作负载已经可用;应继续观察条件、事件与副本状态。

kubectl get deployment web -o wide
kubectl rollout status deployment/web --timeout=120s
kubectl describe deployment web

Pod 是最小调度单元

Pod 不是容器的别名,而是 Kubernetes 能够调度的最小单元。一个 Pod 可以包含一个主容器,也可以包含紧密协作的 Sidecar。Pod 内容器共享网络命名空间,因此使用同一 IP,可通过 localhost 通信;还可以挂载同一卷交换文件。它们总被调度到同一节点,也会共同经历 Pod 的创建和删除。

只有确实需要共享生命周期、网络或存储的进程才应放进同一个 Pod。把互不相关的服务塞在一起,会让扩缩容粒度、故障隔离和资源核算都变差。Pod 本身是临时对象,重建后名称与 IP 可能变化,不应把 Pod IP 写进配置,也不应把业务状态只留在可写层。

Deployment、ReplicaSet 与 Pod 的层级

Deployment 面向无状态工作负载,负责声明副本数、Pod 模板和更新策略。它不会直接逐个维护 Pod,而是创建 ReplicaSet;ReplicaSet 再依据标签选择器确保指定数量的 Pod 存活。发布新模板时,Deployment 建立新的 ReplicaSet,逐步扩容新版本并缩容旧版本。

Deployment
├── ReplicaSet(web-7c8d6f) ── Pod × 3   当前版本
└── ReplicaSet(web-65b94d) ── Pod × 0   历史版本

历史 ReplicaSet 保留了旧模板,为回滚提供依据。直接修改 ReplicaSet 或其 Pod 会与上层控制器冲突:Deployment 下一轮调谐可能覆盖修改,被删掉的 Pod 也会重新创建。应修改 Deployment 的 Pod 模板,让层级中的控制器按职责收敛。

标签选择器贯穿资源关联

Deployment、ReplicaSet、Pod 与 Service 并不是通过名称自动绑定,而是依赖 label 和 selector。Deployment 的 spec.selector 必须匹配 Pod 模板标签;Service 再用自己的 selector 选择后端 Pod。标签拼写不一致时,Pod 可能正常运行,但 Service 没有任何端点。

kubectl get pods -l app=web,track=stable --show-labels
kubectl get endpointslices -l kubernetes.io/service-name=web

标签应该描述稳定身份与维度,如 app、component、version、track。不要把 Pod 名、时间戳等高变化值当作 Service 的主要选择条件。选择器过宽也有风险,例如只用 app=web,可能同时选中用于实验的 canary Pod;可增加 track=stable 明确流量边界。

Service 的三种暴露方式

Service 为一组动态 Pod 提供稳定虚拟 IP 与 DNS 名。常见类型的边界如下:

类型 可访问范围 典型用途
ClusterIP 集群内部 服务间调用,默认类型
NodePort 每个节点的固定端口 测试、外部负载均衡器的后端入口
LoadBalancer 由基础设施提供外部地址 对外服务入口

NodePort 不代表流量只进入某一节点;到达任意节点端口后仍可转发到符合条件的后端。LoadBalancer 通常会组合 NodePort 或等价的数据面能力,具体实现由集群基础设施决定。若环境没有负载均衡集成,声明该类型可能长期处于地址待分配状态。

kube-proxy 监听 Service 与 EndpointSlice 变化,在节点上维护转发规则。常见实现通过 iptables、IPVS 或其他内核数据面,把发往 ClusterIP 和端口的连接转到某个就绪 Pod IP。它通常不是一个逐请求转发的用户态代理,因此排障时需要同时检查 Service、EndpointSlice、节点规则与容器网络。已有长连接也不一定因后端列表变化而立刻迁移。

命名空间的作用边界

命名空间用于资源分组、名称作用域、配额与权限边界。同一命名空间内资源名需要唯一,不同命名空间可存在同名 Service。RBAC、ResourceQuota 和 LimitRange 常按命名空间配置,适合区分团队或环境。

命名空间不是网络隔离。默认网络模型下,只要网络可达,不同命名空间的 Pod 仍可能互相访问。需要隔离时应显式编写 NetworkPolicy,并确认所用网络插件实现了策略。密钥也不会因为放在不同命名空间就自动阻止所有主体读取,访问控制仍取决于 RBAC。

一份最小可运行清单

下面的 Deployment 运行两个 Web 副本,Service 通过相同的 app: demo-web 标签选择它们:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo-web
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: demo-web
  template:
    metadata:
      labels:
        app: demo-web
    spec:
      containers:
        - name: web
          image: registry.internal/demo-web@sha256:0123abcd
          ports:
            - name: http
              containerPort: 8080
          readinessProbe:
            httpGet:
              path: /ready
              port: http
            periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:
  name: demo-web
  namespace: default
spec:
  type: ClusterIP
  selector:
    app: demo-web
  ports:
    - name: http
      port: 80
      targetPort: http

更新过程如何观察

Deployment 的发布状态不能只看 Pod 是否处于 Running。容器进程启动后,readinessProbe 通过才会成为可用端点;镜像拉取失败、调度资源不足或探针错误都会让更新停滞。下面几组字段能还原控制器当前决策:

kubectl get deployment demo-web 
  -o jsonpath='{.status.replicas} {.status.updatedReplicas} {.status.availableReplicas}{"n"}'
kubectl get rs -l app=demo-web
kubectl get pods -l app=demo-web -o wide
kubectl get events --sort-by=.metadata.creationTimestamp

replicas 是控制器管理的总副本,updatedReplicas 表示已采用新模板的副本,availableReplicas 还要求就绪满足最短可用时间。三者长期不一致时,应查看 Deployment 条件中的原因,而不是直接扩容掩盖问题。Pod 处于 Pending 常见于资源请求无法满足、亲和性或污点约束不匹配;处于 CrashLoopBackOff 则要检查退出码、当前日志和上一次容器日志。

kubectl logs pod-name -c web --previous
kubectl describe pod pod-name

资源请求也参与调度。调度器依据 requests 而非容器瞬时使用量选择节点,limit 则由运行时执行限制。请求缺失会削弱容量规划,设置过高会让 Pod 无法落点。控制器负责维持对象数量,并不替代应用容量评估。

DNS、端口与会话边界

同命名空间内可以用 demo-web 访问 Service,跨命名空间通常使用 demo-web.default 或完整集群域名。Service 的 port 是调用方连接的端口,targetPort 是后端容器实际监听端口,containerPort 主要提供声明与命名,写错它不一定阻止进程监听,但命名端口引用会受影响。

Service 只把新连接分配给可用端点,不保证业务会话持久化,也不会自动等待应用完成事务。长连接可能继续留在即将终止的 Pod 上,发布时还需配合就绪状态切换、连接排空和优雅停机。需要固定客户端来源或会话亲和时,应明确评估负载分布与故障转移代价,不要把它当作默认补救手段。

应用后若 Service 不通,可沿关联链排查:Deployment 的可用副本是否达到期望、Pod 是否 Ready、Pod 标签是否命中 selector、EndpointSlice 是否出现地址、容器是否监听 0.0.0.0:8080。若端点存在但仍不通,再检查 NetworkPolicy、节点数据面与应用协议。每一步都对应一个可观察对象,这条链比反复删除 Pod 更能暴露真正的配置断点、调用关系与责任边界。

1kViews
35Likes
3Comments
3Participants
12 minread time

Comments (3)

  • 何遇 · 2026-09-08 21:27

    有个细节想抬杠:高并发下这个锁真的够用吗?

    Reply
  • AsyncLab · 2026-09-09 07:01

    笑死,评论区全是「踩过」,说明这块是真疼。

    Reply
  • Kernighan 林 · 2026-09-09 15:44

    看完去补了监控,果然发现两个隐藏问题。

    Reply