1.3 Pod:声明的最小落地单元


1.3 Pod:声明的最小落地单元

Pod 是 Kubernetes 调度与运行的最小单元,内部可含一个或多个共享网络与存储命名空间的容器。Deployment 生产出来的每个副本就是一个 Pod。理解 Pod 的内部构造与状态流转,是读懂调度(第3章)与探针(第3章)的前提。

前两节里 Pod 一直作为"副本"出现,本节把它放到放大镜下:一个 Pod 里到底装了什么、几个容器怎么共处、从提交到就绪要经过哪些状态。这份认知会直接决定你后面能不能看懂调度失败、探针误杀这类故障。

现场还原:Pod 里到底有什么

很多人以为 Pod 就是容器换了个名字,差矣。Pod 是一台"逻辑小主机":它有自己的 IP 地址、自己的主机名、自己的端口空间,里面的所有容器像同居室友——共享这套网络设施,彼此用 localhost 通信,看起来就像跑在同一台机器上。

底层靠的是一个先于所有业务容器启动的 pause 容器(也叫基础设施容器)。它体积极小,唯一的职责是先占住网络命名空间,随后加入的容器全部挂进这个命名空间。你用 describe 看不到它,但它一直在。这个设计带来一个重要推论:同 Pod 的容器不能争抢同一个端口,就像同住一台机器的两个进程。

什么时候该在一个 Pod 里放多个容器?判定标准是"是否需要同生共死、共享生命周期"。经典场景是 sidecar 模式:主容器跑业务,伴随容器干辅助活。给 orders-api 配一个日志收集伴随容器的例子:

apiVersion: v1 kind: Pod metadata: name: orders-with-sidecar labels: app: orders-api spec: containers: - name: orders-api # 主容器:业务本体 image: orders-api:1.4.2 ports: - containerPort: 8080 volumeMounts: - name: logs # 把共享卷挂到日志目录 mountPath: /var/log/app - name: log-shipper # 伴随容器:把日志送往集中平台 image: log-shipper:2.1 volumeMounts: - name: logs # 挂同一个卷,读主容器写的日志 mountPath: /var/log/app volumes: - name: logs emptyDir: {} # Pod 级共享卷,Pod 销毁即消失

两个容器挂同一块 emptyDir 卷:主容器往里写日志,伴随容器从里读走。配合 localhost 通信,这对搭档配合得天衣无缝。反例也常见:把数据库和 Web 应用塞进同一个 Pod——两者伸缩节奏完全不同,数据库也不该随 Web 副本数复制,这就该拆成两个 Pod、用 Service 通信(第5章)。

Pod 的状态流转

从"被调度"到"能接流量",Pod 要走一条状态流水线。用 kubectl get 看到的 STATUS 列就是流水线上的当前位置:

几个状态值得单独点名。Pending 最常见的原因是资源不满足或没有可用节点——声明在排队等调度器(第3章 3.2 会教你查证据);CrashLoopBackOff 意味着容器反复崩溃,系统按指数退避重启(10 秒、20 秒、40 秒……封顶 5 分钟),最常见根因是配置错误或依赖不可达;Ready 与 Running 的区别是探针说了算,这个裁判制度在 3.4 节专门讲。

⚠️ 常见坑:把 Running 当作"服务可用了"。Running 只表示容器进程在跑,READY 列显示的 1/1 才表示就绪探针也通过。大促扩容时盯着 READY 而不是 STATUS,才不会把还没就绪的副本计入容量。

观察 Pod:describe 的三段式读法

排障时 kubectl describe 是第一工具。输出很长,但按三段读就不慌——事件段最靠后也最值钱:

kubectl describe pod orders-with-sidecar -n production # ...输出节选... # Containers: # orders-api: # State: Running # 当前状态与起止时间 # Ready: True # 就绪判定 # Restart Count: 0 # 重启计数,CrashLoop 的证据 # Environment: APP_MODE=production # log-shipper: # State: Running # Conditions: # Type Status # Ready True # Pod 级就绪条件 # Events: # 事件段:排障金矿 # Normal Scheduled 10m 默认调度器 Successfully assigned to node-a # Normal Pulling 10m kubelet Pulling image "orders-api:1.4.2" # Normal Created 9m kubelet Created container orders-api # Normal Started 9m kubelet Started container orders-api

事件段按时间排列,谁调度了它、谁拉了镜像、谁起的容器一目了然。第7章的排障手册会大量用到它,这里先记住阅读顺序:Events 看"经过"、Conditions 看"判定"、Containers 段看"现状"

案例:一次重启计数引发的排查

背景:同事反馈某个订单服务副本"总在重启",监控曲线呈锯齿状。

操作:先看全局再个体——

# 第一步:锁定异常副本(RESTARTS 列非零者) kubectl get pods -n production -l app=orders-api # NAME READY STATUS RESTARTS AGE # orders-api-6d9f7c8b5-9mjq4 1/1 Running 0 2d # orders-api-6d9f7c8b5-2vxk7 1/1 CrashLoopBackOff 7 2d # orders-api-6d9f7c8b5-x3p2q 1/1 Running 0 2d # 第二步:看该副本上一轮容器的日志(-p 取上一实例) kubectl logs orders-api-6d9f7c8b5-2vxk7 -n production -p --tail=5 # FATAL cannot connect to config service at startup, retry exhausted

结果:日志显示启动时连不上配置服务。进一步查发现该副本所在节点访问配置服务的网络策略被收紧,放开策略后副本自动恢复。

解读:CrashLoopBackOff 不是病,是症状的计步器。重启计数告诉我们"反复死",上一轮日志告诉我们"死因"。注意 3 个副本里只有 1 个异常,说明问题不在声明本身(否则 3 个都崩),而在节点局部环境——这种"个别副本"的分布特征本身就是线索。

变式:如果 3 个副本全部 CrashLoop,优先怀疑共性因素:镜像版本、环境变量、依赖服务整体不可达。排查顺序应从"最近的变更"入手,而不是逐台机器翻日志。

本节要点回顾

  • Pod 是逻辑小主机:独立 IP 与端口空间,内部容器经 localhost 互访,靠 pause 容器先占网络命名空间;
  • 多容器判定标准:同生共死才同 Pod,sidecar 共享卷是典型搭档;伸缩节奏不同的服务必须拆开;
  • 状态流水线:Pending 与 ContainerCreating 是落地前的两站,Running 不等于 Ready,探针才是就绪裁判;
  • CrashLoopBackOff 是计步器:指数退避重启,病因要看上一轮日志;
  • describe 三段读法:Events 看经过、Conditions 看判定、Containers 段看现状。

至此,orders-api 的声明已经写好、也理解了它的落地产物。下一章跟随这份声明穿过集群的大门:API Server 如何验明你的身份、准入控制器会做哪些修订、etcd 如何把声明记入集群的记忆。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U