K8s Pod 的生命周期------从 kubectl apply 到 Running 全链路拆解(浅谈)
大家好,这里是彩妙呀~
在云原生时代,Kubernetes(K8s)已经成为了容器编排的事实标准。不管你是做运维还是做开发,都绕不开一个最基础的概念------Pod。
很多小伙伴学了 kubectl apply -f pod.yaml ,Pod 跑起来了,但不知道这条命令背后到底发生了什么。当你知道了Pod底层运行的原理,排查问题的时候才不会抓瞎。
下面,彩妙将会带着大家从零开始,追踪 Pod 从创建到删除的完整生命周期。
官方文档解释 Pod https://kubernetes.io/docs/concepts/workloads/pods/
一、Pod 是什么?------先搞懂基本概念
什么是 Pod?
官方文档的解释:
A Pod is the smallest deployable unit of computing that you can create and manage in Kubernetes. A Pod is a group of one or more containers, with shared storage and network resources, and a specification for how to run the containers.
翻译:Pod 是 K8s 里最小的调度单位 ,它不是容器,而是容器的"壳"。一个 Pod 里面可以放一个或多个容器,这些容器共享网络(同一个 IP)和存储(同一个 Volume)。
为什么要这样设计?因为有些容器天生就该"绑在一起"------比如你的应用容器和它的日志采集容器,它们需要共享网络和存储,但又各自独立运行。
二、Pod 生命周期总览------一张图看清全貌
Pod 的一辈子可以分为 7 个阶段:

<注意:上面每一个箭头都对应着一件具体的事。下面我们一个一个拆开看。>
阶段①:kubectl apply 敲下去,第一站发生了什么?
kubectl 做了什么
kubectl 把你的 YAML 文件打包成一个 HTTPS 请求,发给了 API Server。
我们先准备一个最简单的 Pod 定义,后面所有讨论都基于它:
yaml
apiVersion: v1
kind: Pod
metadata:
name: my-first-pod
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
bash
# 提交这个 Pod
kubectl apply -f pod.yaml

API Server 的"三道门"
请求到了 API Server,需要过三关才能入库:
认证(Authentication)
└─ 你是谁?→ 检查证书/Token,没通过返回 401
↓ 通过
鉴权(Authorization)
└─ 你有权限做这个操作吗?→ 检查 RBAC 权限,没通过返回 403
↓ 通过
准入控制(Admission Control)
└─ 你的请求合规吗?→ 检查是否设了资源限制、是否违反安全策略
↓ 通过
写入 etcd,状态标记为 Pending
<注意:准入控制这一步很关键------Istio 就是利用 MutatingAdmissionWebhook,在你提交的 Pod 里自动注入一个 Envoy Sidecar 容器。这也是后续 Service Mesh 章节的重点内容。>
用生活中的例子类比:
你进公司大楼------先刷工卡(认证),前台看你的权限能不能进这个楼层(鉴权),安检看你有没有带违禁品(准入)。三关全过,你才能进去(写入 etcd)。
四、阶段②:谁来给 Pod 选机器?------Scheduler 调度
Pod 写入了 etcd,但此时它还不知道该去哪台机器------.spec.nodeName 是空的。
Scheduler(调度器)一直在 Watch etcd,发现来了一个新的、还没分配节点的 Pod,立刻开始工作:
调度分两步
第一步:预选(Filtering)------海选淘汰
把不满足条件的 Node 全部过滤掉:
- 资源不够的(CPU/内存不足)→ 淘汰
- 端口冲突的 → 淘汰
- 打上了污点(Taint)且你没有声明容忍(Toleration)的 → 淘汰
第二步:优选(Scoring)------决赛打分
剩下的 Node,给每台打分,哪台资源最空闲,分数最高,就选哪台。
bash
# 看看你的 Pod 被调度到了哪台机器
kubectl describe pod my-first-pod | grep "Node:"
# 输出示例:Node: vm-0-7-ubuntu/10.0.0.7
人话版:Scheduler 就像房产中介。你告诉他"我要租房子(Pod)",他先过滤掉不满足要求的(面积不够、没电梯),再从剩下的里面挑最合适的一套,告诉你"就这套了"。
新手常见坑:Pod 一直 Pending
bash
# 错误场景:提交了 Pod,但一直是 Pending 状态
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
my-first-pod 0/1 Pending 0 5m
排查思路:
bash
# 看 Events,找原因
kubectl describe pod my-first-pod
# 如果看到 "0/1 nodes are available"
# → 要么资源不够,要么 Node 有污点不让调度
五、阶段③:容器真正跑起来------Kubelet 创建容器
Scheduler 选好 Node 后,更新 Pod 的 .spec.nodeName。接下来,目标 Node 上的 Kubelet 登场了。
Kubelet 的调用链
Kubelet 自己不直接创建容器,它有一条调用链:
Kubelet
→ CRI(gRPC 接口)
→ containerd(容器管理)
→ containerd-shim(进程守护)
→ runc(真正创建容器)
#mermaid-svg-64Vc2xmZSDtNr02s{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-64Vc2xmZSDtNr02s .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-64Vc2xmZSDtNr02s .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-64Vc2xmZSDtNr02s .error-icon{fill:#552222;}#mermaid-svg-64Vc2xmZSDtNr02s .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-64Vc2xmZSDtNr02s .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-64Vc2xmZSDtNr02s .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-64Vc2xmZSDtNr02s .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-64Vc2xmZSDtNr02s .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-64Vc2xmZSDtNr02s .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-64Vc2xmZSDtNr02s .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-64Vc2xmZSDtNr02s .marker{fill:#333333;stroke:#333333;}#mermaid-svg-64Vc2xmZSDtNr02s .marker.cross{stroke:#333333;}#mermaid-svg-64Vc2xmZSDtNr02s svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-64Vc2xmZSDtNr02s p{margin:0;}#mermaid-svg-64Vc2xmZSDtNr02s .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-64Vc2xmZSDtNr02s .cluster-label text{fill:#333;}#mermaid-svg-64Vc2xmZSDtNr02s .cluster-label span{color:#333;}#mermaid-svg-64Vc2xmZSDtNr02s .cluster-label span p{background-color:transparent;}#mermaid-svg-64Vc2xmZSDtNr02s .label text,#mermaid-svg-64Vc2xmZSDtNr02s span{fill:#333;color:#333;}#mermaid-svg-64Vc2xmZSDtNr02s .node rect,#mermaid-svg-64Vc2xmZSDtNr02s .node circle,#mermaid-svg-64Vc2xmZSDtNr02s .node ellipse,#mermaid-svg-64Vc2xmZSDtNr02s .node polygon,#mermaid-svg-64Vc2xmZSDtNr02s .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-64Vc2xmZSDtNr02s .rough-node .label text,#mermaid-svg-64Vc2xmZSDtNr02s .node .label text,#mermaid-svg-64Vc2xmZSDtNr02s .image-shape .label,#mermaid-svg-64Vc2xmZSDtNr02s .icon-shape .label{text-anchor:middle;}#mermaid-svg-64Vc2xmZSDtNr02s .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-64Vc2xmZSDtNr02s .rough-node .label,#mermaid-svg-64Vc2xmZSDtNr02s .node .label,#mermaid-svg-64Vc2xmZSDtNr02s .image-shape .label,#mermaid-svg-64Vc2xmZSDtNr02s .icon-shape .label{text-align:center;}#mermaid-svg-64Vc2xmZSDtNr02s .node.clickable{cursor:pointer;}#mermaid-svg-64Vc2xmZSDtNr02s .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-64Vc2xmZSDtNr02s .arrowheadPath{fill:#333333;}#mermaid-svg-64Vc2xmZSDtNr02s .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-64Vc2xmZSDtNr02s .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-64Vc2xmZSDtNr02s .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-64Vc2xmZSDtNr02s .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-64Vc2xmZSDtNr02s .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-64Vc2xmZSDtNr02s .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-64Vc2xmZSDtNr02s .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-64Vc2xmZSDtNr02s .cluster text{fill:#333;}#mermaid-svg-64Vc2xmZSDtNr02s .cluster span{color:#333;}#mermaid-svg-64Vc2xmZSDtNr02s div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-64Vc2xmZSDtNr02s .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-64Vc2xmZSDtNr02s rect.text{fill:none;stroke-width:0;}#mermaid-svg-64Vc2xmZSDtNr02s .icon-shape,#mermaid-svg-64Vc2xmZSDtNr02s .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-64Vc2xmZSDtNr02s .icon-shape p,#mermaid-svg-64Vc2xmZSDtNr02s .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-64Vc2xmZSDtNr02s .icon-shape .label rect,#mermaid-svg-64Vc2xmZSDtNr02s .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-64Vc2xmZSDtNr02s .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-64Vc2xmZSDtNr02s .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-64Vc2xmZSDtNr02s :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 没有
有
Kubelet Watch 到
Pod 分给了自己
通过 CRI 调用 containerd
本地有 nginx 镜像?
去 Registry 拉镜像
(分层下载,只拉本地没有的层)
直接创建容器
containerd-shim 守护进程
runc 创建容器
namespace 隔离
(PID/NET/MNT/UTS/IPC)
cgroup 限制
(CPU/内存上限)
执行 Entrypoint
容器启动成功 ✅
<注意:K8s 1.24 之后默认不再使用 Docker 作为容器运行时,而是直接使用 containerd。调用链上没有 Docker Engine 这一层了。>
容器的本质:namespace + cgroup
如果你有 Linux 基础,这个概念应该不陌生。容器不是什么"轻量级虚拟机",它只是 Linux 两个老功能的组合:
bash
# namespace:隔离------让容器以为自己独占了整台机器
lsns # 查看系统上的 namespace
# cgroup:限制------让容器不能超量使用资源
cat /sys/fs/cgroup/cpu/cpu.cfs_quota_us # 查看 CPU 配额
| 机制 | 作用 | 人话版 |
|---|---|---|
| namespace | 进程/网络/文件系统隔离 | 每人一个独立房间,互不干扰 |
| cgroup | CPU/内存/IO 限制 | 每个房间装了水电表,用超了就限流 |
namespace 的五种类型:
| 类型 | 隔离什么 | 没了它会怎样 |
|---|---|---|
| PID | 进程树 | 容器里 ps aux 能看到宿主机所有进程 |
| NET | 网卡/IP/端口 | 容器没有独立 IP |
| MNT | 文件系统挂载点 | 容器和宿主机共享文件系统 |
| UTS | hostname | 容器改 hostname 会影响宿主机 |
| IPC | 进程间通信 | 容器间信号/共享内存不隔离 |
容器 vs 虚拟机:面试高频对比题
#mermaid-svg-zM5fjsDgCTeLpBKx{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-zM5fjsDgCTeLpBKx .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-zM5fjsDgCTeLpBKx .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-zM5fjsDgCTeLpBKx .error-icon{fill:#552222;}#mermaid-svg-zM5fjsDgCTeLpBKx .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-zM5fjsDgCTeLpBKx .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-zM5fjsDgCTeLpBKx .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-zM5fjsDgCTeLpBKx .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-zM5fjsDgCTeLpBKx .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-zM5fjsDgCTeLpBKx .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-zM5fjsDgCTeLpBKx .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-zM5fjsDgCTeLpBKx .marker{fill:#333333;stroke:#333333;}#mermaid-svg-zM5fjsDgCTeLpBKx .marker.cross{stroke:#333333;}#mermaid-svg-zM5fjsDgCTeLpBKx svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-zM5fjsDgCTeLpBKx p{margin:0;}#mermaid-svg-zM5fjsDgCTeLpBKx .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-zM5fjsDgCTeLpBKx .cluster-label text{fill:#333;}#mermaid-svg-zM5fjsDgCTeLpBKx .cluster-label span{color:#333;}#mermaid-svg-zM5fjsDgCTeLpBKx .cluster-label span p{background-color:transparent;}#mermaid-svg-zM5fjsDgCTeLpBKx .label text,#mermaid-svg-zM5fjsDgCTeLpBKx span{fill:#333;color:#333;}#mermaid-svg-zM5fjsDgCTeLpBKx .node rect,#mermaid-svg-zM5fjsDgCTeLpBKx .node circle,#mermaid-svg-zM5fjsDgCTeLpBKx .node ellipse,#mermaid-svg-zM5fjsDgCTeLpBKx .node polygon,#mermaid-svg-zM5fjsDgCTeLpBKx .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-zM5fjsDgCTeLpBKx .rough-node .label text,#mermaid-svg-zM5fjsDgCTeLpBKx .node .label text,#mermaid-svg-zM5fjsDgCTeLpBKx .image-shape .label,#mermaid-svg-zM5fjsDgCTeLpBKx .icon-shape .label{text-anchor:middle;}#mermaid-svg-zM5fjsDgCTeLpBKx .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-zM5fjsDgCTeLpBKx .rough-node .label,#mermaid-svg-zM5fjsDgCTeLpBKx .node .label,#mermaid-svg-zM5fjsDgCTeLpBKx .image-shape .label,#mermaid-svg-zM5fjsDgCTeLpBKx .icon-shape .label{text-align:center;}#mermaid-svg-zM5fjsDgCTeLpBKx .node.clickable{cursor:pointer;}#mermaid-svg-zM5fjsDgCTeLpBKx .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-zM5fjsDgCTeLpBKx .arrowheadPath{fill:#333333;}#mermaid-svg-zM5fjsDgCTeLpBKx .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-zM5fjsDgCTeLpBKx .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-zM5fjsDgCTeLpBKx .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-zM5fjsDgCTeLpBKx .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-zM5fjsDgCTeLpBKx .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-zM5fjsDgCTeLpBKx .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-zM5fjsDgCTeLpBKx .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-zM5fjsDgCTeLpBKx .cluster text{fill:#333;}#mermaid-svg-zM5fjsDgCTeLpBKx .cluster span{color:#333;}#mermaid-svg-zM5fjsDgCTeLpBKx div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-zM5fjsDgCTeLpBKx .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-zM5fjsDgCTeLpBKx rect.text{fill:none;stroke-width:0;}#mermaid-svg-zM5fjsDgCTeLpBKx .icon-shape,#mermaid-svg-zM5fjsDgCTeLpBKx .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-zM5fjsDgCTeLpBKx .icon-shape p,#mermaid-svg-zM5fjsDgCTeLpBKx .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-zM5fjsDgCTeLpBKx .icon-shape .label rect,#mermaid-svg-zM5fjsDgCTeLpBKx .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-zM5fjsDgCTeLpBKx .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-zM5fjsDgCTeLpBKx .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-zM5fjsDgCTeLpBKx :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 容器
虚拟机
应用
依赖库
Guest OS(完整操作系统)
Hypervisor
应用
依赖库
容器引擎
宿主机内核(共享)
物理硬件
| 维度 | 虚拟机 | 容器 |
|---|---|---|
| 启动速度 | 分钟级 | 秒级 |
| 资源占用 | 每 VM 一套完整 OS(GB 级) | 共享宿主机内核(MB 级) |
| 隔离程度 | 硬件级(更强) | 进程级 |
| 单机可运行数 | 几十个 | 成百上千 |
| 内核 | 每个 VM 独立内核 | 共享宿主机内核 |
六、阶段④:Pod 的 IP 从哪来?------CNI 网络
容器创建好了,但它还没有 IP。这时候 CNI(Container Network Interface)插件出来干活了。
CNI 做什么?
#mermaid-svg-APc5M67Fak1XX704{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-APc5M67Fak1XX704 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-APc5M67Fak1XX704 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-APc5M67Fak1XX704 .error-icon{fill:#552222;}#mermaid-svg-APc5M67Fak1XX704 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-APc5M67Fak1XX704 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-APc5M67Fak1XX704 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-APc5M67Fak1XX704 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-APc5M67Fak1XX704 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-APc5M67Fak1XX704 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-APc5M67Fak1XX704 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-APc5M67Fak1XX704 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-APc5M67Fak1XX704 .marker.cross{stroke:#333333;}#mermaid-svg-APc5M67Fak1XX704 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-APc5M67Fak1XX704 p{margin:0;}#mermaid-svg-APc5M67Fak1XX704 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-APc5M67Fak1XX704 .cluster-label text{fill:#333;}#mermaid-svg-APc5M67Fak1XX704 .cluster-label span{color:#333;}#mermaid-svg-APc5M67Fak1XX704 .cluster-label span p{background-color:transparent;}#mermaid-svg-APc5M67Fak1XX704 .label text,#mermaid-svg-APc5M67Fak1XX704 span{fill:#333;color:#333;}#mermaid-svg-APc5M67Fak1XX704 .node rect,#mermaid-svg-APc5M67Fak1XX704 .node circle,#mermaid-svg-APc5M67Fak1XX704 .node ellipse,#mermaid-svg-APc5M67Fak1XX704 .node polygon,#mermaid-svg-APc5M67Fak1XX704 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-APc5M67Fak1XX704 .rough-node .label text,#mermaid-svg-APc5M67Fak1XX704 .node .label text,#mermaid-svg-APc5M67Fak1XX704 .image-shape .label,#mermaid-svg-APc5M67Fak1XX704 .icon-shape .label{text-anchor:middle;}#mermaid-svg-APc5M67Fak1XX704 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-APc5M67Fak1XX704 .rough-node .label,#mermaid-svg-APc5M67Fak1XX704 .node .label,#mermaid-svg-APc5M67Fak1XX704 .image-shape .label,#mermaid-svg-APc5M67Fak1XX704 .icon-shape .label{text-align:center;}#mermaid-svg-APc5M67Fak1XX704 .node.clickable{cursor:pointer;}#mermaid-svg-APc5M67Fak1XX704 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-APc5M67Fak1XX704 .arrowheadPath{fill:#333333;}#mermaid-svg-APc5M67Fak1XX704 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-APc5M67Fak1XX704 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-APc5M67Fak1XX704 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-APc5M67Fak1XX704 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-APc5M67Fak1XX704 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-APc5M67Fak1XX704 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-APc5M67Fak1XX704 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-APc5M67Fak1XX704 .cluster text{fill:#333;}#mermaid-svg-APc5M67Fak1XX704 .cluster span{color:#333;}#mermaid-svg-APc5M67Fak1XX704 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-APc5M67Fak1XX704 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-APc5M67Fak1XX704 rect.text{fill:none;stroke-width:0;}#mermaid-svg-APc5M67Fak1XX704 .icon-shape,#mermaid-svg-APc5M67Fak1XX704 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-APc5M67Fak1XX704 .icon-shape p,#mermaid-svg-APc5M67Fak1XX704 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-APc5M67Fak1XX704 .icon-shape .label rect,#mermaid-svg-APc5M67Fak1XX704 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-APc5M67Fak1XX704 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-APc5M67Fak1XX704 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-APc5M67Fak1XX704 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 宿主机
veth pair
veth pair
cni0 网桥
eth0(物理网卡)
Pod A
10.42.0.5
Pod B
10.42.0.6
外部网络
CNI 做三件事:
- 分配 IP :从 Pod CIDR 地址池(比如
10.42.0.0/16)里取一个 - 创建 veth pair:一对虚拟网线,一头插 Pod 的网络空间,一头插宿主机网桥
- 配路由:确保其他 Pod 能找到这个 IP
bash
# 进 Pod 里看你自己的 IP
kubectl exec -it my-first-pod -- ip addr
# 你会看到 eth0@ifxx: 10.42.0.x
# 这就是 CNI 分配给你的 IP
<注意:Flannel、Calico 都是 CNI 的具体实现------就像不同品牌的交换机,功能都是插网线分配 IP,但实现细节不同。>
七、阶段⑤:外面怎么访问 Pod?------Service 代理
Pod IP 的问题
Pod 会死、会重建------死了重建后 IP 就变了。用户不可能每天记住 Pod 的新 IP。
Service 解决的就是这个问题:给一组 Pod 一个固定的"电话号码"(ClusterIP)。
Service 怎么找到 Pod?
#mermaid-svg-mRbP6vipUaT9tcjm{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-mRbP6vipUaT9tcjm .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-mRbP6vipUaT9tcjm .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-mRbP6vipUaT9tcjm .error-icon{fill:#552222;}#mermaid-svg-mRbP6vipUaT9tcjm .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-mRbP6vipUaT9tcjm .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-mRbP6vipUaT9tcjm .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-mRbP6vipUaT9tcjm .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-mRbP6vipUaT9tcjm .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-mRbP6vipUaT9tcjm .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-mRbP6vipUaT9tcjm .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-mRbP6vipUaT9tcjm .marker{fill:#333333;stroke:#333333;}#mermaid-svg-mRbP6vipUaT9tcjm .marker.cross{stroke:#333333;}#mermaid-svg-mRbP6vipUaT9tcjm svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-mRbP6vipUaT9tcjm p{margin:0;}#mermaid-svg-mRbP6vipUaT9tcjm .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-mRbP6vipUaT9tcjm .cluster-label text{fill:#333;}#mermaid-svg-mRbP6vipUaT9tcjm .cluster-label span{color:#333;}#mermaid-svg-mRbP6vipUaT9tcjm .cluster-label span p{background-color:transparent;}#mermaid-svg-mRbP6vipUaT9tcjm .label text,#mermaid-svg-mRbP6vipUaT9tcjm span{fill:#333;color:#333;}#mermaid-svg-mRbP6vipUaT9tcjm .node rect,#mermaid-svg-mRbP6vipUaT9tcjm .node circle,#mermaid-svg-mRbP6vipUaT9tcjm .node ellipse,#mermaid-svg-mRbP6vipUaT9tcjm .node polygon,#mermaid-svg-mRbP6vipUaT9tcjm .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-mRbP6vipUaT9tcjm .rough-node .label text,#mermaid-svg-mRbP6vipUaT9tcjm .node .label text,#mermaid-svg-mRbP6vipUaT9tcjm .image-shape .label,#mermaid-svg-mRbP6vipUaT9tcjm .icon-shape .label{text-anchor:middle;}#mermaid-svg-mRbP6vipUaT9tcjm .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-mRbP6vipUaT9tcjm .rough-node .label,#mermaid-svg-mRbP6vipUaT9tcjm .node .label,#mermaid-svg-mRbP6vipUaT9tcjm .image-shape .label,#mermaid-svg-mRbP6vipUaT9tcjm .icon-shape .label{text-align:center;}#mermaid-svg-mRbP6vipUaT9tcjm .node.clickable{cursor:pointer;}#mermaid-svg-mRbP6vipUaT9tcjm .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-mRbP6vipUaT9tcjm .arrowheadPath{fill:#333333;}#mermaid-svg-mRbP6vipUaT9tcjm .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-mRbP6vipUaT9tcjm .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-mRbP6vipUaT9tcjm .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-mRbP6vipUaT9tcjm .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-mRbP6vipUaT9tcjm .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-mRbP6vipUaT9tcjm .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-mRbP6vipUaT9tcjm .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-mRbP6vipUaT9tcjm .cluster text{fill:#333;}#mermaid-svg-mRbP6vipUaT9tcjm .cluster span{color:#333;}#mermaid-svg-mRbP6vipUaT9tcjm div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-mRbP6vipUaT9tcjm .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-mRbP6vipUaT9tcjm rect.text{fill:none;stroke-width:0;}#mermaid-svg-mRbP6vipUaT9tcjm .icon-shape,#mermaid-svg-mRbP6vipUaT9tcjm .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-mRbP6vipUaT9tcjm .icon-shape p,#mermaid-svg-mRbP6vipUaT9tcjm .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-mRbP6vipUaT9tcjm .icon-shape .label rect,#mermaid-svg-mRbP6vipUaT9tcjm .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-mRbP6vipUaT9tcjm .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-mRbP6vipUaT9tcjm .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-mRbP6vipUaT9tcjm :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 请求 → 10.96.0.1:80
kube-proxy
(查 iptables 规则)
Pod A
10.42.0.5
Ready ✅
Pod B
10.42.0.6
Ready ✅
Pod C
10.42.0.7
Not Ready ❌
(Readiness 没过)
Service 通过 Label(标签) 来匹配 Pod:
yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx # 只要 Pod 带这个标签,就自动加入通讯录
ports:
- port: 80 # Service 对外的端口
targetPort: 80 # Pod 上容器监听的端口
bash
# 创建 Service
kubectl expose pod my-first-pod --port=80 --target-port=80 --name=nginx-service
# 看 Service 的"通讯录"(Endpoints)
kubectl get endpoints nginx-service
# 输出:nginx-service 10.42.0.5:80
# 这就是 kube-proxy 会把流量转发过去的 Pod IP
kube-proxy 的两种模式
| 模式 | 原理 | 适用场景 |
|---|---|---|
| iptables | 在每台机器上写 iptables 规则,做 DNAT 转发 | 中小集群 |
| IPVS | 用 Linux 内核的 IPVS 模块做四层负载均衡 | 大集群(性能更好) |
四种 Service 类型
| 类型 | 访问范围 | 用途 |
|---|---|---|
| ClusterIP | 集群内部 | 服务间调用(默认,最常用) |
| NodePort | 节点 IP + 固定端口(30000-32767) | 测试/临时暴露 |
| LoadBalancer | 公网 IP | 对接云厂商 LB |
| ExternalName | DNS 别名 | 映射外部服务进来 |
友情小知识:南北向 vs 东西向流量
这两个词你可能经常听到,其实很简单:
- 东西向 = 集群内部服务之间的调用 = Service 管
- 南北向 = 从集群外面进来的流量 = Ingress / LoadBalancer 管
八、阶段⑥:Pod 挂了怎么办?------健康检查 + 自愈
三种探针
K8s 通过探针(Probe)来判断 Pod 是否健康:
yaml
spec:
containers:
- name: nginx
image: nginx:latest
livenessProbe: # 存活探针:你还活着吗?
httpGet:
path: /healthz
port: 80
initialDelaySeconds: 3
periodSeconds: 5
readinessProbe: # 就绪探针:你能接客吗?
httpGet:
path: /ready
port: 80
initialDelaySeconds: 3
periodSeconds: 5
startupProbe: # 启动探针:启动慢不慢?
httpGet:
path: /startup
port: 80
failureThreshold: 30
periodSeconds: 10
| 探针 | 作用 | 失败后果 |
|---|---|---|
| Liveness | 你还活着吗? | 杀掉容器,重新创建 |
| Readiness | 你能接客了吗? | 从 Service 通讯录移除(不重启) |
| Startup | 启动完了吗? | 启动期间暂停 Liveness 检查(防误杀) |
三种探测方式
bash
# 方式 1:HTTP GET(最常用)
# 访问容器里指定的 URL,看返回码是不是 200-399
# 方式 2:TCP Socket
# 试试端口能不能连上
# 方式 3:Exec 命令
# 在容器里执行命令,看返回值是不是 0
自愈是怎么做到的?
K8s 的 Controller Manager 里跑着各种控制器,每一个都在做同一件事:
无限循环:
看 etcd 里的"期望状态"(我要几个 Pod?)
→ 看集群的"实际状态"(现在有几个 Pod?)
→ 不一样?调到一样
这个循环就叫 Reconciliation Loop(调谐循环)。
bash
# 亲自试试自愈:
# 删掉一个由 Deployment 管理的 Pod
kubectl delete pod my-first-pod
# 立刻 watch
kubectl get pod -w
# 你会看到 Pod 瞬间被重建------因为 Deployment Controller 发现"少了"就立刻补
九、阶段⑦:Pod 被删除时发生了什么?
容器进程 Pod Service API Server 你 容器进程 Pod Service API Server 你 #mermaid-svg-47bd5Gk38eft4iMj{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-47bd5Gk38eft4iMj .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-47bd5Gk38eft4iMj .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-47bd5Gk38eft4iMj .error-icon{fill:#552222;}#mermaid-svg-47bd5Gk38eft4iMj .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-47bd5Gk38eft4iMj .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-47bd5Gk38eft4iMj .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-47bd5Gk38eft4iMj .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-47bd5Gk38eft4iMj .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-47bd5Gk38eft4iMj .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-47bd5Gk38eft4iMj .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-47bd5Gk38eft4iMj .marker{fill:#333333;stroke:#333333;}#mermaid-svg-47bd5Gk38eft4iMj .marker.cross{stroke:#333333;}#mermaid-svg-47bd5Gk38eft4iMj svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-47bd5Gk38eft4iMj p{margin:0;}#mermaid-svg-47bd5Gk38eft4iMj .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-47bd5Gk38eft4iMj text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-47bd5Gk38eft4iMj .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-47bd5Gk38eft4iMj .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-47bd5Gk38eft4iMj .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-47bd5Gk38eft4iMj .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-47bd5Gk38eft4iMj #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-47bd5Gk38eft4iMj .sequenceNumber{fill:white;}#mermaid-svg-47bd5Gk38eft4iMj #sequencenumber{fill:#333;}#mermaid-svg-47bd5Gk38eft4iMj #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-47bd5Gk38eft4iMj .messageText{fill:#333;stroke:none;}#mermaid-svg-47bd5Gk38eft4iMj .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-47bd5Gk38eft4iMj .labelText,#mermaid-svg-47bd5Gk38eft4iMj .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-47bd5Gk38eft4iMj .loopText,#mermaid-svg-47bd5Gk38eft4iMj .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-47bd5Gk38eft4iMj .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-47bd5Gk38eft4iMj .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-47bd5Gk38eft4iMj .noteText,#mermaid-svg-47bd5Gk38eft4iMj .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-47bd5Gk38eft4iMj .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-47bd5Gk38eft4iMj .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-47bd5Gk38eft4iMj .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-47bd5Gk38eft4iMj .actorPopupMenu{position:absolute;}#mermaid-svg-47bd5Gk38eft4iMj .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-47bd5Gk38eft4iMj .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-47bd5Gk38eft4iMj .actor-man circle,#mermaid-svg-47bd5Gk38eft4iMj line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-47bd5Gk38eft4iMj :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 应用处理完手头请求自己优雅退出 ✅ === 如果 30s 到了还没退 === kubectl delete pod xxx打 deletionTimestamp +启动 30s 倒计时立刻从 Endpoints 移除(新流量不再进来)执行 PreStop Hook(如果有)发送 SIGTERM(信号 15)SIGKILL(信号 9) 强杀 💀
一步一步看
- API Server 收到删除请求 → 给 Pod 打上
deletionTimestamp,启动 30 秒倒计时 - Service 立刻把这个 Pod 从通讯录移除------新流量不会再发给它
- 如果配置了
PreStop Hook,先执行(比如通知注册中心下线) - Kubelet 发 SIGTERM(信号 15)给容器主进程------"收拾东西,该走了"
- 进程处理完手头请求,优雅退出
- 30 秒到了还没退出? → SIGKILL(信号 9)强杀------保安架你出去
新手最常踩的坑:你的应用没处理 SIGTERM
c++
// ❌ 错误示范:程序完全不知道要退出
// 在 main 函数里面直接死循环跑业务逻辑
// Kubectl delete 后,30 秒后被 SIGKILL 强杀
// 正在处理的请求全部丢失
int main() {
while (true) {
handle_request(); // 如果正在处理请求时被强杀...
}
}
c++
// ✅ 正确示范(C++ 版):捕获 SIGTERM,优雅退出
#include <csignal>
#include <atomic>
std::atomic<bool> running{true};
void signal_handler(int signum) {
if (signum == SIGTERM) {
std::cout << "收到 SIGTERM,准备退出..." << std::endl;
running = false; // 通知主循环停下来
}
}
int main() {
signal(SIGTERM, signal_handler); // 注册信号处理
while (running) {
handle_request(); // 处理完当前请求再退出
}
std::cout << "优雅退出完成" << std::endl;
return 0;
}
go
// ✅ 正确示范(Go 版):捕获 SIGTERM,优雅退出
// 下半年学了 Go 之后你就能写这个了~
import (
"os"
"os/signal"
"syscall"
)
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, syscall.SIGTERM, syscall.SIGINT)
<-sigCh // 阻塞等待信号
// 收到信号后:停止接收新请求 → 等待现有请求处理完 → 退出
<注意:SIGTERM 和 SIGKILL 的区别是 Linux 基础面试高频题------SIGTERM(15)可以被捕获和处理,SIGKILL(9)不行,内核直接杀进程。你的 Linux 3 分基础完全够解释这个。>
十、Pod 生命周期核心接口速查
bash
# push(创建 Pod)
kubectl apply -f pod.yaml
# top(查看当前 Pod 状态)
kubectl get pod -w # -w 实时 watch
kubectl describe pod xxx # 看详情 + Events
kubectl logs xxx # 看日志
kubectl logs xxx --previous # 看上一次崩溃的日志
# front(进入容器)
kubectl exec -it xxx -- /bin/bash
# pop(删除 Pod)
kubectl delete pod xxx
# empty(判空)
kubectl get pod # 看看有哪些 Pod
# size(查看 Pod 内部)
kubectl get pod xxx -o yaml # 看完整配置
kubectl describe pod xxx # 看详细信息
十一、新手最常踩的 5 个坑(附排查方式)
坑 1:Pod 一直 Pending
bash
# ❌ 问题现象
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
my-first-pod 0/1 Pending 0 5m
# ✅ 排查方式
kubectl describe pod my-first-pod
# 翻到 Events,看是不是:
# "0/1 nodes are available" → 资源不够或节点有污点
# "persistentvolumeclaim not found" → 挂载的 PVC 不存在
坑 2:Pod 反复重启(CrashLoopBackOff)
bash
# ❌ 问题现象
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
my-first-pod 0/1 CrashLoopBackOff 4 3m
# ✅ 排查方式
kubectl logs my-first-pod --previous
# 99% 的情况是应用启动后立刻退出了(缺少依赖、配置错误、panic)
坑 3:Pod Running 了但外面访问不到
bash
# ✅ 排查方式
# 1. 检查 Readiness Probe
kubectl describe pod my-first-pod | grep -A5 Readiness
# 2. 检查 Service Endpoints 是否为空
kubectl get endpoints nginx-service
# 如果 ENDPOINTS 列是 <none> → Service 没找到 Ready 的 Pod
坑 4:ClusterIP ping 不通
bash
# ❌ 错误测试方式
ping 10.96.0.1 # 不通!但这是正常现象
# ✅ 正确测试方式
curl http://10.96.0.1:80 # 通就对了
# 因为 ClusterIP 是虚拟 IP,不对应任何物理网卡
# ping 用的是 ICMP 协议,不走传输层,所以不通
坑 5:删 Pod 偶尔丢请求
bash
# 原因:应用没处理 SIGTERM → 30 秒后 SIGKILL 强杀 → 正在处理的请求丢了
# ✅ 解决:在 Pod 配置中加 PreStop Hook,给流量排空留时间
spec:
terminationGracePeriodSeconds: 60 # 把倒计时延长到 60 秒
containers:
- name: my-app
lifecycle:
preStop:
exec:
command: ["/bin/sh", "-c", "sleep 5"] # 等待 5 秒让流量排空
十二、动手验证(在你的 k3s 上跑一遍)
全部在 VS Code 连服务器的终端里操作:
bash
# === 实验 1:创建 Pod,看它的诞生过程 ===
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: my-first-pod
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
EOF
kubectl get pod -w
# 看到 Running 后 Ctrl+C 退出
# 你会看到:Pending → ContainerCreating → Running
bash
# === 实验 2:看 Pod 的事件记录 ===
kubectl describe pod my-first-pod
# 翻到 Events 部分,你会看到:
# Scheduled → Pulling → Pulled → Created → Started
# 这就是阶段①~⑤的完整证据链
bash
# === 实验 3:进容器看内部 ===
kubectl exec -it my-first-pod -- /bin/bash
# 进去后执行:
ps aux # 看进程------只能看到容器自己的进程
ip addr # 看自己 IP------能看到 CNI 分配的 10.42.0.x
env # 看环境变量
exit # 退出
bash
# === 实验 4:创建 Service,看通讯录 ===
kubectl expose pod my-first-pod --port=80 --target-port=80 --name=nginx-service
kubectl get endpoints nginx-service
# 应该看到 ENDPOINTS 列有你的 Pod IP:80
bash
# === 实验 5:优雅终止测试 ===
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: graceful-test
spec:
terminationGracePeriodSeconds: 60
containers:
- name: nginx
image: nginx:latest
lifecycle:
preStop:
exec:
command: ["/bin/sh", "-c", "echo 'PreStop: 开始清理...' && sleep 5 && echo 'PreStop: 清理完成'"]
EOF
kubectl delete pod graceful-test
kubectl get pod -w
# 观察从 delete 到 Pod 真正消失的时间
十三、总结
一条 kubectl apply -f pod.yaml,背后是 7 个组件在接力:
你 → kubectl → API Server(三道门) → etcd(持久化)
→ Scheduler(调度) → Kubelet(创建容器) → CNI(分配网络)
→ Service(注册对外入口) → Controller Manager(持续自愈)
#mermaid-svg-ylbgSiK9RAa043vs{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ylbgSiK9RAa043vs .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ylbgSiK9RAa043vs .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ylbgSiK9RAa043vs .error-icon{fill:#552222;}#mermaid-svg-ylbgSiK9RAa043vs .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ylbgSiK9RAa043vs .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ylbgSiK9RAa043vs .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ylbgSiK9RAa043vs .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ylbgSiK9RAa043vs .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ylbgSiK9RAa043vs .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ylbgSiK9RAa043vs .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ylbgSiK9RAa043vs .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ylbgSiK9RAa043vs .marker.cross{stroke:#333333;}#mermaid-svg-ylbgSiK9RAa043vs svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ylbgSiK9RAa043vs p{margin:0;}#mermaid-svg-ylbgSiK9RAa043vs .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ylbgSiK9RAa043vs .cluster-label text{fill:#333;}#mermaid-svg-ylbgSiK9RAa043vs .cluster-label span{color:#333;}#mermaid-svg-ylbgSiK9RAa043vs .cluster-label span p{background-color:transparent;}#mermaid-svg-ylbgSiK9RAa043vs .label text,#mermaid-svg-ylbgSiK9RAa043vs span{fill:#333;color:#333;}#mermaid-svg-ylbgSiK9RAa043vs .node rect,#mermaid-svg-ylbgSiK9RAa043vs .node circle,#mermaid-svg-ylbgSiK9RAa043vs .node ellipse,#mermaid-svg-ylbgSiK9RAa043vs .node polygon,#mermaid-svg-ylbgSiK9RAa043vs .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ylbgSiK9RAa043vs .rough-node .label text,#mermaid-svg-ylbgSiK9RAa043vs .node .label text,#mermaid-svg-ylbgSiK9RAa043vs .image-shape .label,#mermaid-svg-ylbgSiK9RAa043vs .icon-shape .label{text-anchor:middle;}#mermaid-svg-ylbgSiK9RAa043vs .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ylbgSiK9RAa043vs .rough-node .label,#mermaid-svg-ylbgSiK9RAa043vs .node .label,#mermaid-svg-ylbgSiK9RAa043vs .image-shape .label,#mermaid-svg-ylbgSiK9RAa043vs .icon-shape .label{text-align:center;}#mermaid-svg-ylbgSiK9RAa043vs .node.clickable{cursor:pointer;}#mermaid-svg-ylbgSiK9RAa043vs .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ylbgSiK9RAa043vs .arrowheadPath{fill:#333333;}#mermaid-svg-ylbgSiK9RAa043vs .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ylbgSiK9RAa043vs .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ylbgSiK9RAa043vs .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ylbgSiK9RAa043vs .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ylbgSiK9RAa043vs .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ylbgSiK9RAa043vs .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ylbgSiK9RAa043vs .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ylbgSiK9RAa043vs .cluster text{fill:#333;}#mermaid-svg-ylbgSiK9RAa043vs .cluster span{color:#333;}#mermaid-svg-ylbgSiK9RAa043vs div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ylbgSiK9RAa043vs .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ylbgSiK9RAa043vs rect.text{fill:none;stroke-width:0;}#mermaid-svg-ylbgSiK9RAa043vs .icon-shape,#mermaid-svg-ylbgSiK9RAa043vs .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ylbgSiK9RAa043vs .icon-shape p,#mermaid-svg-ylbgSiK9RAa043vs .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ylbgSiK9RAa043vs .icon-shape .label rect,#mermaid-svg-ylbgSiK9RAa043vs .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ylbgSiK9RAa043vs .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ylbgSiK9RAa043vs .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ylbgSiK9RAa043vs :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Pod生命周期的7个站
① 提交
② 调度
③ 创建
④ 网络
⑤ 服务
⑥ 自愈
⑦ 终止
这篇文章是 K8s 学习系列的总览地图------每个组件只讲了它"做什么"。后面的文章会一个一个深挖:
- etcd 怎么存储数据、Raft 共识是怎么回事
- Scheduler 的预选策略和优选打分算法
- kube-proxy 的 iptables 规则到底长什么样
- Istio Sidecar 是怎么注入的
- Controller Manager 的自愈机制
当然,在后面文章中,当我们接触资源清单时,彩妙会进一步的为大家讲解Pod->从创建到销毁的全流程。
这些,彩妙会在后面的文章中逐个拆解~
本篇到这里就结束了,喜欢文章的小伙伴可以关注一下彩妙,我们下一篇再见~

