KEEL · 龙骨 · A CURRICULUM FOR THE AI ERA

00 · Pod — keel 龙骨

类型:主题概念 · 应用课对应:02 章 · 清单解剖

类型:主题概念 · 应用课对应:02 章 · 清单解剖

这一页只回答四件事:它为什么会出现、它是什么、它长什么样、它怎么工作。

一、它为什么会出现

从 Docker 过来的人会撞上一个很具体的错位:

在 Docker 里,你 run 出来的东西叫「容器」,容器就是那个单位。
到了集群里,kubectl get pods 出来的行叫 Pod,名字还是自己拼的。
你要看它的地址,得 get pods -o wide,而地址并不属于容器。

这个错位不是命名习惯不同。集群要干的事是"把一份工作放到某台机器上,并在它坏掉时补一个"——
那么它必须能回答一个问题:一次放上去的、以及一次换掉的,到底是多大的一块?

如果答案是"一个容器",就会缺一块:有些容器必须和别人待在一起才能工作。一个负责业务、
一个负责把日志转发出去,它们得在同一台机器上、用同一个地址、看同一份文件。
拆成两个可以各自调度的单位,这件事就没法表达。

所以调度的单位不是容器。它多出来的那一层,就是为了让"必须一起的那些容器"有地方放。

二、它是什么

一句话:Pod 是集群里最小的一次调度单位——一个能被放上某台机器、也能被整个换掉的盒子,
里面装着一个或多个容器,它们共享同一个地址。

由此有两个直接后果,都是日常要用的判断:

它不是这两样东西——混淆会带来误判:

三、它长什么样

一个 Pod 自己写出来的样子,和它在列表里的样子,是同一件事的两面。

列表里(kubectl get pods,Kubernetes v1.37.0):

NAME                  READY   STATUS    RESTARTS   AGE
web-565bc6668-c9g8d   1/1     Running   0          33s

这是一行 Pod,READY 的分母读的是容器。 地址不在这里,加 -o wide 才看得到:

NAME                  READY   STATUS    RESTARTS   AGE   IP           NODE
web-565bc6668-c9g8d   1/1     Running   0          36s   10.244.0.8   keel-lab-control-plane

它自己写出来的样子(-o yaml 的骨架,省略掉大量由集群填写的字段):

apiVersion: v1
kind: Pod
metadata:
  name: web-565bc6668-c9g8d
  labels:
    app: web
spec:
  containers:            # ← 这里可以有多个;它们共享下面的地址
    - name: web
      image: nginx:1.27-alpine
status:
  phase: Running
  podIP: 10.244.0.8      # ← 地址在这一层,不在容器上

两处要读准:containers 是列表(这就是"一个盒子可以装多个"的写法),
podIP 在 status 里、和 containers 同级(这就是"地址属于盒子不属于容器"的写法)。

四、它怎么工作

一个 Pod 从被提到到消失,五步:

① 提出   你交的模板被算成一份 Pod 定义(名字、镜像、标签、要多少资源)
② 落位   调度器找一台装得下它的节点,把它交给那台节点
③ 造物   那台节点上的组件按定义把里面的容器挨个造出来,并分配一个地址给它
④ 就绪   里面该起来的容器都起来了,这个 Pod 才算 Ready
⑤ 替换   它被删掉时,整份定义连同地址一起作废;要补,就按同一份定义再造一个全新的

第 ⑤ 步是全部误会里最要紧的一步:没有"修复"这个动作,只有"重造"。
所以你删掉一个 Pod 之后看到的那个新名字、新地址,不是原物被救回来了,
而是同一份定义被又执行了一遍。

五、它会带出哪些概念

六、回到应用课

应用课里的那句话 现在你知道它为什么成立
01 章:"调度失败的原因是没有任何节点满足这个 Pod 的 requests" 账是按整个 Pod 里所有容器的 requests 之和算的,不是按某一个容器算的——这就是为什么多容器共处一个盒子会互相影响能不能落位
02 章:"Service 不创建 Pod,只『选择』 Pod" 标签写在Pod 上(metadata.labels),所以 Service 维护的那份名单是盒子的名单;盒子被换掉,名单跟着换
02 章:"改了 Pod 标签……Deployment 完全正常,4 个 Pod 都 Running 且 Ready" 改的是盒子身上的标记,跟盒子里跑什么无关——所以它能同时做到"服务全挂"和"每个容器都健康"
03 章:"健康被拆成三个判断,因为『进程活着』与『能服务』是两件事" 探针探的是盒子里的那个容器,但结论写在盒子的状态上——你在 get pods 里看到的 READY 就是这份结论

这一页改变了你的哪个判断:以后读 kubectl get pods,你要先问一句"这一行的单位是什么"——
名字、地址、READY 的分母、以及它会不会被整个替换,四件事全挂在"盒子"这个单位上,
任何一条按"容器"去理解都会推错。

自测题

  1. kubectl get pods -o wide 里 IP 那一列,为什么在 -o yaml 里不是写在 containers 下面?
  2. 删掉一个 Pod 之后回来的那个,名字和地址都变了。这个"变"是替换还是修复?

进入 keel 阅读