一、initc、mainc、探针、钩子理论
| 组件 | 什么时候干? | 干不好会怎样? | 是否持续运行? |
|---|---|---|---|
| InitC(初始化容器) | 主容器启动前(串行执行) | Pod卡住,主容器永远不启动 | ❌ 干完就退 |
| MainC(主容器) | InitC 全部成功后启动 | 崩溃了就被重启 | ✅ 必须常驻 |
| PostStart(钩子) | MainC刚启动时执行 | MainC直接被杀(启动失败) | ❌ 只执行一次 |
| PreStop(钩子) | MainC被删除前执行 | 阻塞删除,直至执行完毕 | ❌ 只执行一次 |
| startupProbe(启动探针) | MainC 启动初期 | 失败则触发liveness 重启 | ✅ 启动成功后停用 |
| readinessProbe(就绪探针) | MainC运行时持续检查 | 踢出 Service(不杀容器) | ✅ 持续检测 |
| livenessProbe(存活探针) | MainC运行时持续检查 | 杀死容器并重启 | ✅ 持续检测 |
二、initc
代码举例:
apiVersion: v1 # API 版本 kind: Pod # 资源类型 metadata: # 元数据 name: initc-1 # Pod 名称 labels: # 标签 app: initc # 标签键值对 spec: # 规格定义 #这个是mainc主容器列表 containers: # 主容器列表 - name: myapp-container # 主容器名称 image: wangyanglinux/tools:busybox # 镜像地址 command: ['sh', '-c', 'echo The app is running! && sleep 3600'] # 启动命令(输出信息并睡眠1小时) #这个initContainers是就是initc初始化容器列表 initContainers: # 初始化容器列表(串行执行) - name: init-myservice # 第一个初始化容器,检查 myservice image: wangyanglinux/tools:busybox # 镜像地址 command: ['sh', '-c', 'until nslookup myservice; do echo waiting for myservice; sleep 2; done;'] # 轮询解析 myservice 直到成功 - name: init-mydb # 第二个初始化容器,检查 mydb image: wangyanglinux/tools:busybox # 镜像地址 command: ['sh', '-c', 'until nslookup mydb; do echo waiting for mydb; sleep 2; done;'] # 轮询解析 mydb 直到成功| 特性维度 | 核心说明 | 大白话解释 | 对应示例/影响 |
|---|---|---|---|
| 1. 执行顺序 | 严格串行执行,按定义顺序一个接一个运行,绝不并行。 | 第1个InitC不干完退出,第2个连动都不动。 | 你YAML里init-myservice必须先成功退出,init-mydb才能启动。 |
| 2. 生命周期 | 一次性任务,必须主动退出(Exit 0),不能是常驻进程。 | “临时工”干完活就立刻下班,绝不赖在办公室里。 | 里面不能写sleep 3600或while true,否则主容器永远进不来。 |
| 3. 失败阻断 | 任意InitC失败(非0退出码),主容器不创建,Pod卡在Init:Error。 | “一票否决制”——后台没把食材备好,大厨连厨房门都摸不着。 | 如果nslookup myservice永远失败,myapp-container永远不会启动。 |
| 4. 健康检查 | 不支持探针(liveness/readiness)和钩子(PostStart/PreStop),只看退出码(0=成功)。 | 老师不看你过程,只看你最终交没交卷,卷面分是不是0分。 | 无法用livenessProbe监控它,成功与否全看nslookup返回0还是非0。 |
| 5. 资源调度 | 调度时取所有InitC资源请求最大值与所有MainC资源总和的较大者。 | 哪怕InitC只疯跑几秒钟,也得按它的“峰值饭量”给分配个大桌子。 | InitC若请求2G内存,MainC只请求1G,调度器会按2G找节点。 |
| 6. 重启策略 | 无独立策略,完全继承Pod的restartPolicy(Always/Never/OnFailure)。 | 小跟班没有话语权,老大(Pod)让重试就重试,让放弃就放弃。 | Pod设restartPolicy: Never,InitC失败了就直接躺平,不再重试。 |
三、mainc特性:
| 特性维度 | 核心说明 | 大白话解释 | 对应示例/影响 |
|---|---|---|---|
| 1. 执行方式 | 并行启动。同一个 Pod 内的多个 MainC 同时启动(无先后顺序)。 | 厨房里的多个大厨同时开火炒菜,谁也不等谁。 | 你的myapp-1和busybox-1同时抢 80 端口,导致bind 98错误。 |
| 2. 生命周期 | 常驻进程(长跑选手)。必须持续运行,不能主动退出(除非被杀死或崩了)。 | 正式员工,每天必须待在工位上,不能干完活就走。 | 命令必须写成sleep 3600或启动 Web 服务;如果写成echo hello(执行完就退),容器会立即 Crash。 |
| 3. 启动条件 | 必须等所有 InitC 全部成功退出,才会被允许创建和启动。 | 后勤(InitC)不把食材备好,大厨(MainC)连厨房门都摸不着。 | 你的 YAML 中,myapp-container必须等init-myservice和init-mydb都成功退出才启动。 |
| 4. 健康检查 | 完全支持探针(liveness/readiness/startup)和钩子(PostStart/PreStop)。 | 配备专职保镖(探针)和门禁系统(钩子),随时监控和干预。 | livenessProbe失败了直接杀掉容器;readiness失败了踢出流量;PostStart失败则容器起不来。 |
| 5. 资源计算 | 累加求和。调度器计算节点资源时,将所有 MainC 的 Requests/Limits 直接相加。 | 多个大厨的饭量累加算总账,厨房必须能同时管饱所有人。 | MainC-1 要 1G 内存,MainC-2 要 1G,调度器就按2G去找节点(而 InitC 是取最大值)。 |
| 6. 重启策略 | 崩溃立即重启(除非 Pod 的restartPolicy: Never)。容器退出(无论成功或失败)都会触发立即重建。 | 大厨晕倒了(崩溃),立马抬走换一个新大厨上来,且不耽误出菜。 | 进程崩溃退出码非 0,Kubelet 马上重启;不同于 InitC(失败会卡住重试,而这里是直接重启进程)。 |
| 7. 命名空间共享(补充分类) | 共享网络、IPC、UTS 命名空间(PID 默认不共享,需手动开启)。 | 几个大厨共用一个灶台(IP)和一口锅(IPC),但各自有自己的工牌号(PID)。 | 共享网络 = 端口冲突(你的bind 98);共享 IPC = 能用共享内存通信;PID 默认隔离 =ps看不到对方进程。 |
四、探针
4.1就绪探测:readinessProbe
1. HTTP GET 就绪探针(readiness-httpget-pod)
容器启动后,kubelet 每 3 秒向http://<PodIP>:80/index1.html发送 GET 请求。若返回状态码在 200~399 之间,则标记为就绪;否则未就绪。由于镜像中可能没有/index1.html,该探针通常失败,Pod 将一直处于READY 0/1状态。
apiVersion: v1 kind: Pod metadata: name: readiness-httpget-pod # Pod 名称 namespace: default # 所属命名空间 labels: # 自定义标签,便于选择 app: myapp env: test spec:#期望 containers: - name: readiness-httpget-container # 容器名称 image: wangyanglinux/myapp:v1.0 # 容器镜像(内部运行一个简单 Web 服务) imagePullPolicy: IfNotPresent # 本地有镜像则优先使用,否则拉取 readinessProbe: # 就绪探针定义 httpGet: # 探针类型:HTTP GET 请求 port: 80 # 目标端口 path: /index1.html # 请求路径(如果有这个文件,探针探到,会成功。这里我设置一个不存在的文件,用于演示就绪检查失败的情况) initialDelaySeconds: 1 # 容器启动后等待 1 秒再开始探测 periodSeconds: 3 # 每隔 3 秒探测一次2. 命令执行(Exec)就绪探针(readiness-exec-pod)
容器启动后立即创建/tmp/live,因此前 60 秒内test -e /tmp/live返回 0(成功),Pod 为就绪状态。60 秒后文件被删除,探测命令返回非 0(失败),Pod 变为未就绪。该示例演示了探针随时间动态变化的效果。
apiVersion: v1 kind: Pod metadata: name: readiness-exec-pod # Pod 名称 namespace: default # 默认命名空间 spec: containers: - name: readiness-exec-container # 容器名称 image: wangyanglinux/tools:busybox # 基于 busybox 的工具镜像 imagePullPolicy: IfNotPresent # 本地优先 command: # 容器启动命令(多行写法) - /bin/sh - -c - | touch /tmp/live # 启动时创建 /tmp/live 文件 sleep 60 # 等待 60 秒 rm -rf /tmp/live # 60 秒后删除该文件 sleep 3600 # 保持容器运行 1 小时(便于观察后续状态) readinessProbe: # 就绪探针 exec: # 探针类型:执行命令 command: # 执行的命令列表 - test # test 命令 - -e # -e 选项检查文件是否存在 - /tmp/live # 检查目标文件(结果:肯定先探测到,60s后就探测不到了,pod就失败了) initialDelaySeconds: 1 # 启动后 1 秒开始探测 periodSeconds: 3 # 每 3 秒探测一次3.TCP Socket 就绪探针(readiness-tcp-pod)
kubelet 尝试与容器的 80 端口建立 TCP 连接。如果连接成功(表示服务已在监听),则认为就绪;若连接失败(端口未开放或拒绝连接),则未就绪。该探针适合检查服务是否已启动并绑定了指定端口。
apiVersion: v1 kind: Pod metadata: name: readiness-tcp-pod # Pod 名称 spec: containers: - name: readiness-exec-container # 容器名称(注意此处名称与 exec 示例相同,实际可随意) image: wangyanglinux/myapp:v1.0 # 镜像包含 Web 服务,监听 80 端口 readinessProbe: # 就绪探针 initialDelaySeconds: 5 # 启动后等待 5 秒再开始探测 timeoutSeconds: 1 # 每次探测超时时间(秒),连接超时即视为失败 tcpSocket: # 探针类型:TCP 连接检查 port: 80 # 目标端口4.2存活探测:livenessProbe
1. 基于 Exec 方式的存活探针(liveness-exec-pod)
容器启动后立即创建/tmp/live,因此前 60 秒内test -e /tmp/live返回 0(成功),Pod 被视为存活。60 秒后文件被删除,探测命令返回非 0(失败),kubelet 将根据restartPolicy(默认为 Always)重启容器。该示例演示了存活探针如何检测应用内部状态(如临时文件)并触发容器重启。
apiVersion: v1 kind: Pod metadata: name: liveness-exec-pod # Pod 名称 namespace: default # 默认命名空间 spec: containers: - name: liveness-exec-container # 容器名称 image: wangyanglinux/tools:busybox # 基于 busybox 的工具镜像 imagePullPolicy: IfNotPresent # 本地有镜像则使用,否则拉取 command: # 容器启动命令 - /bin/sh - -c - | touch /tmp/live # 启动时创建 /tmp/live 文件 sleep 60 # 等待 60 秒 rm -rf /tmp/live # 60 秒后删除该文件 sleep 3600 # 保持容器运行 1 小时(便于观察后续行为) livenessProbe: # 存活探针定义 exec: # 探针类型:执行命令 command: # 执行的命令列表 - test # test 命令(检查文件是否存在) - -e # -e 选项 - /tmp/live # 目标文件路径 initialDelaySeconds: 1 # 容器启动后等待 1 秒再开始探测 periodSeconds: 3 # 每隔 3 秒探测一次2.基于 HTTP GET 方式的存活探针(liveness-httpget-pod)
kubelet 每隔 3 秒向http://<PodIP>:80/index.html发送 GET 请求。如果返回的 HTTP 状态码在 200~399 之间,则视为存活;否则视为失败。若连续失败次数达到阈值(默认由failureThreshold控制,默认为 3),容器将被重启。该探针适合检查 Web 服务是否正常响应。
apiVersion: v1 kind: Pod metadata: name: liveness-httpget-pod # Pod 名称 namespace: default # 默认命名空间 spec: containers: - name: liveness-httpget-container # 容器名称 image: wangyanglinux/myapp:v1.0 # 镜像包含一个 Web 服务,监听 80 端口 imagePullPolicy: IfNotPresent ports: # 声明容器端口(便于阅读,非强制) - name: http containerPort: 80 # 实际监听端口 livenessProbe: # 存活探针 httpGet: # 探针类型:HTTP GET 请求 port: 80 # 目标端口 path: /index.html # 请求路径(镜像中通常存在该文件,探测成功) initialDelaySeconds: 1 # 启动后 1 秒开始探测 periodSeconds: 3 # 每 3 秒探测一次 timeoutSeconds: 3 # 超时时间(秒),超时视为失败3.基于 TCP Socket 方式的存活探针(liveness-tcp-pod)
kubelet 尝试与容器的 80 端口建立 TCP 连接。如果连接成功,则认为容器存活;否则失败。该探针适用于检查服务是否已启动并绑定端口,但不关心具体业务逻辑(如 HTTP 响应状态)。适用于数据库、缓存等 TCP 服务。
apiVersion: v1 kind: Pod metadata: name: liveness-tcp-pod # Pod 名称 spec: containers: - name: liveness-tcp-container # 容器名称 image: wangyanglinux/myapp:v1.0 # 镜像中的服务监听 80 端口 livenessProbe: # 存活探针 initialDelaySeconds: 5 # 启动后等待 5 秒再开始探测 timeoutSeconds: 1 # 连接超时时间(秒),超时视为失败 tcpSocket: # 探针类型:TCP 连接检查 port: 80 # 目标端口总结:存活探测如果发现pod异常或者说死了,并且你设置了自动重启,会创建一个新的pod。
4.3启动探测:startupProbe
apiVersion: v1 kind: Pod metadata: name: startupprobe-1 # Pod 名称 namespace: default # 命名空间 spec: containers: - name: myapp-container # 容器名称 image: wangyanglinux/myapp:v1.0 # 镜像(包含 Web 服务,监听 80 端口) imagePullPolicy: IfNotPresent # 本地优先 ports: # 声明容器端口(便于阅读) - name: http containerPort: 80 # 实际监听端口 readinessProbe: # 就绪探针(检查业务是否就绪) httpGet: port: 80 path: /index2.html # 注意:此路径可能不存在,用于演示失败 initialDelaySeconds: 1 # 启动后 1 秒开始探测 periodSeconds: 3 # 每 3 秒探测一次 startupProbe: # 启动探针(延迟其他探针,直到启动成功) httpGet: path: /index1.html # 启动期间检查 /index1.html 是否存在 port: 80 failureThreshold: 30 # 允许连续失败 30 次 periodSeconds: 10 # 每 10 秒探测一次总结:只有启动探测启动,就绪探测才可以启动。
五、钩子
Podhook(钩子)是由Kubernetes管理的kubelet发起的,当容器中的进程启动前或者容器中的进
程终止之前运行,这是包含在容器的生命周期之中。可以同时为Pod中的所有容器都配置hook。
Hook的类型包括两种:
exec:执行一段命令
HTTP:发送HTTP请求
钩子类型:
postStart 钩子:在容器启动后(但入口进程启动前)立即执行(启动后钩子)
preStop 钩子:在容器被终止前执行(启动前钩子)
5.1exec类型:
作用:在容器的内部文件系统中,直接执行一段指定的命令或脚本。
# 指定 Kubernetes API 版本,v1 表示核心稳定版本 apiVersion: v1 # 声明要创建的资源类型为 Pod kind: Pod # 元数据部分,定义 Pod 的名称等属性 metadata: # Pod 的名称,用于在命名空间中唯一标识 name: lifecycle-exec-pod # 规格部分,定义 Pod 的具体运行配置 spec: # 定义 Pod 包含的容器列表 containers: # 第一个容器的配置 - name: lifecycle-exec-container # 使用的基础镜像(注意:此镜像可能已下架,如拉取失败可换成 nginx:latest) image: wangyanglinux/myapp:v1.0 # 生命周期钩子配置 lifecycle: # postStart 钩子:在容器启动后(但入口进程启动前)立即执行 # 适用于初始化操作,如配置加载、环境准备 postStart: # 执行命令的方式 exec: # 要执行的命令:使用 /bin/sh 执行 shell 脚本 # 将 "postStart" 字符串写入 /usr/share/message 文件 command: ["/bin/sh", "-c", "echo postStart > /usr/share/message"] # preStop 钩子:在容器被终止前执行 # 适用于优雅关闭,如保存状态、通知其他服务、清理连接 preStop: exec: # 将 "preStop" 字符串写入 /usr/share/message 文件 command: ["/bin/sh", "-c", "echo preStop > /usr/share/message"]这个结果就是你生成容器,会往/usr/share/message里写内容,当你删除容器,容器删除前,还是会往/usr/share/message里重定向内容。
5.2http类型:
作用:Kubernetes 的 kubelet 进程从容器外部(宿主机网络层面)向容器内监听的 HTTP/HTTPS 端口发送一个 GET 请求。
第一步:启动一个你nginx容器 [root@k8s-master01 xuexi]# docker run -it --rm -p 1234:80 wangyanglinux/myapp:v1.0 Unable to find image 'wangyanglinux/myapp:v1.0' locally v1.0: Pulling from wangyanglinux/myapp 10f623ae1ff6: Pull complete 87f35c454b8f: Pull complete 9398808236ff: Pull complete 10840918b3c8: Pull complete 03ce7c584195: Pull complete 95045127ee09: Pull complete 3f34dbc1d74e: Pull complete Digest: sha256:77d7ec4cd4c00f79304ee9e53ca3d72e0aba22fbaf7a86797528649e3fc66e41 Status: Downloaded newer image for wangyanglinux/myapp:v1.0 第二步:新增pod内容如下 apiVersion: v1 kind: Pod metadata: name: lifecycle-httpget-pod labels: name: lifecycle-httpget-pod spec: containers: - name: lifecycle-httpget-container image: wangyanglinux/myapp:v1.0 ports: - containerPort: 80 lifecycle: postStart: httpGet: host: 192.168.66.11 path: index.html port: 1234 preStop: httpGet: host: 192.168.66.11 path: hostname.html port: 1234 第三步:启动pod,然后再关闭pod nginx的打印如下 192.168.66.13 - - [08/Sep/2026:09:26:07 +0800] "GET /index.html HTTP/1.1" 200 48 "-" "kube-lifecycle/1.29" 192.168.66.13 - - [08/Sep/2026:09:27:23 +0800] "GET /hostname.html HTTP/1.1" 200 13 "-" "kube-lifecycle/1.29"5.3一个综合案例
# ============================================================ # Pod 定义:包含 Init Container、两个业务容器、探针和生命周期钩子 # ============================================================ apiVersion: v1 kind: Pod metadata: name: lifecycle-pod # Pod 名称 labels: app: lifecycle-pod # 标签,用于选择器 spec: # ============================================================ # Init Containers(在业务容器启动前按顺序执行,全部成功后才启动主容器) # ============================================================ initContainers: # --- Init Container 1:检查 myservice 服务是否可解析 --- - name: init-myservice image: wangyanglinux/tools:busybox # 镜像(包含 nslookup 等工具) command: # 启动命令:循环解析 myservice,直到成功 - sh - -c - until nslookup myservice; do echo waiting for myservice; sleep 2; done; # --- Init Container 2:检查 mydb 服务是否可解析 --- - name: init-mydb image: wangyanglinux/tools:busybox command: - sh - -c - until nslookup mydb; do echo waiting for mydb; sleep 2; done; # ============================================================ # 主容器列表(两个业务容器) # ============================================================ containers: # -------- 容器 1:busybox-container -------- # 作用:模拟业务容器,通过创建/删除文件来演示存活探针 - name: busybox-container image: wangyanglinux/tools:busybox command: # 启动命令(按顺序执行) - /bin/sh - -c - touch /tmp/live ; sleep 600; rm -rf /tmp/live; sleep 3600 # 解释: # 1. touch /tmp/live – 创建存活标记文件 # 2. sleep 600 – 等待 600 秒(10 分钟) # 3. rm -rf /tmp/live – 删除标记文件(此时探针会失败,触发重启) # 4. sleep 3600 – 再等待 3600 秒(1 小时),容器保持运行 # --- 存活探针(livenessProbe) --- # 作用:检查 /tmp/live 文件是否存在,若不存在则重启容器 livenessProbe: exec: # 执行命令方式 command: - test # test 命令 - -e # -e 检查文件是否存在 - /tmp/live initialDelaySeconds: 1 # 容器启动后 1 秒开始探测 periodSeconds: 3 # 每 3 秒探测一次 # --- 生命周期钩子(lifecycle) --- lifecycle: # postStart:容器启动后立即执行(注意:与主命令异步,不阻塞) postStart: httpGet: # 发送 HTTP GET 请求 host: 192.168.66.11 # 目标主机 IP(此处写死为 Master IP,需确保可达) path: index.html # 请求路径 port: 1234 # 目标端口 # preStop:容器终止前执行(用于优雅关闭) preStop: httpGet: host: 192.168.66.11 path: hostname.html port: 1234 # -------- 容器 2:myapp-container -------- # 作用:Web 服务容器,演示 httpGet 探针 - name: myapp-container image: wangyanglinux/myapp:v1.0 # 镜像(可能已下架,建议替换为 nginx 等测试) # --- 存活探针(livenessProbe) --- # 作用:检查 /index.html 是否可访问,失败则重启容器 livenessProbe: httpGet: port: 80 # 容器监听端口 path: /index.html # 健康检查路径 initialDelaySeconds: 1 # 启动后 1 秒开始探测 periodSeconds: 3 # 每 3 秒探测一次 timeoutSeconds: 3 # 超时时间 3 秒 # --- 就绪探针(readinessProbe) --- # 作用:检查 /index1.html 是否可访问,失败则从 Service 端点移除 # 注意:该文件可能不存在,会导致 Pod 永远 NotReady,可根据实际情况调整 readinessProbe: httpGet: port: 80 path: /index1.html # 就绪检查路径(注意:此文件可能不存在) initialDelaySeconds: 1 periodSeconds: 3描述细节
┌─────────────────────────────────────────────────────────────────────┐ │ 阶段 1:提交 YAML │ │ 用户执行 kubectl create -f lifecycle-pod.yaml │ │ → API Server 接收请求,进行语法和权限校验 │ │ → 校验通过后,Pod 对象被存入 etcd │ │ ⚠️ 阻塞点:YAML 语法错误 / 权限不足 → 直接拒绝创建 │ └─────────────────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────────────┐ │ 阶段 2:调度(Scheduling) │ │ API Server 通知调度器(Scheduler)有新的 Pod 需要调度 │ │ → 调度器根据资源、亲和性、污点等规则,为 Pod 选择一个合适的 Node │ │ → 调度结果写回 etcd,Pod 的 nodeName 字段被赋值 │ │ ⚠️ 阻塞点:所有 Node 资源不足 / 不满足调度条件 → Pod 永久 Pending │ │ (可通过 kubectl describe pod 查看 Events 排查) │ └─────────────────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────────────┐ │ 阶段 3:kubelet 开始创建 Pod │ │ 目标 Node 上的 kubelet 监听到有新的 Pod 分配到自己 │ │ → 开始执行 Pod 创建流程 │ │ → 先创建 Pod 的 pause 容器(Infra Container),申请网络和存储资源 │ │ ⚠️ 阻塞点:pause 容器创建失败(如网络插件未就绪)→ Pod 卡在 Pending│ └─────────────────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────────────┐ │ 阶段 4:Init Container 阶段(初始化容器) │ │ ┌─────────────────────────────────────────────────────────────┐ │ │ │ 按 YAML 中定义的顺序依次执行(串行,前一个成功才执行下一个)│ │ │ │ │ │ │ │ ① init-myservice: │ │ │ │ 命令:until nslookup myservice; do sleep 2; done; │ │ │ │ 作用:循环检查 DNS 中 myservice 这个域名是否可解析 │ │ │ │ │ │ │ │ ② init-mydb: │ │ │ │ 命令:until nslookup mydb; do sleep 2; done; │ │ │ │ 作用:循环检查 DNS 中 mydb 这个域名是否可解析 │ │ │ └─────────────────────────────────────────────────────────────┘ │ │ ⚠️ 全局阻塞点:任一 Init Container 执行失败(命令返回非 0) │ │ → 停止执行后续 Init Container │ │ → 主容器(Main Containers)永远不会被启动 │ │ → Pod 状态:Pending,Conditions.Initialized = False │ │ → 直至所有 Init Container 全部成功,才进入下一阶段 │ └─────────────────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────────────┐ │ 阶段 5:主容器启动阶段(两个容器并行启动) │ │ Init Container 全部成功 → 开始同时启动 YAML 中定义的所有主容器 │ │ │ │ ┌─────────────────────────────────────────────────────────────────┐│ │ │ 容器 A:busybox-container ││ │ │ ├── ① 执行 postStart 钩子(httpGet) ← 此处有钩子 ││ │ │ │ → 向 192.168.66.11:1234/index.html 发 GET 请求 ││ │ │ │ ⚠️ 钩子失败(超时/非2xx响应) ││ │ │ │ → 该容器被终止,不会执行主命令 ││ │ │ │ → 容器重启(根据 restartPolicy) ││ │ │ │ ││ │ │ └── ② 执行主命令:touch /tmp/live; sleep 600; rm -rf ... ││ │ │ → 主命令正常执行,容器保持运行 ││ │ │ → 主命令退出(异常退出或 sleep 结束后退出) ││ │ │ → 容器被重启(取决于 restartPolicy) ││ │ ├─────────────────────────────────────────────────────────────────┤│ │ │ 容器 B:myapp-container ││ │ │ ├── ① 无 postStart 钩子 → 直接跳过 ││ │ │ └── ② 启动 Web 服务进程(监听 80 端口) ││ │ │ → 主进程运行正常,容器保持 Running ││ │ │ → 主进程崩溃退出 → 容器被重启 ││ │ └─────────────────────────────────────────────────────────────────┘│ │ │ │ 📌 两个容器的 postStart 互不影响: │ │ 一个容器的 postStart 失败,不会影响另一个容器的启动 │ └─────────────────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────────────┐ │ 阶段 6:探针检测阶段(容器持续运行期间,周期执行) │ │ │ │ ┌──────────────────────────────────────────────────────────────┐ │ │ │ 容器 A:busybox-container │ │ │ │ ├── livenessProbe(存活探针) │ │ │ │ │ 方式:exec → 执行 test -e /tmp/live │ │ │ │ │ 频率:初始延迟 1s,之后每 3s 探测一次 │ │ │ │ │ ✅ 返回 0 → 容器健康,继续运行 │ │ │ │ │ ❌ 返回非 0 → kubelet 认为容器“不存活” │ │ │ │ │ → 直接重启该容器(无论主命令是否还在执行) │ │ │ │ └── 无 readinessProbe(此容器未定义) │ │ │ ├──────────────────────────────────────────────────────────────┤ │ │ │ 容器 B:myapp-container │ │ │ │ ├── livenessProbe(存活探针) │ │ │ │ │ 方式:httpGet → GET /index.html:80 │ │ │ │ │ 频率:初始延迟 1s,之后每 3s 探测一次 │ │ │ │ │ ✅ 返回 2xx/3xx → 容器健康,继续运行 │ │ │ │ │ ❌ 返回非 2xx/3xx 或超时 → kubelet 重启该容器 │ │ │ │ │ │ │ │ │ └── readinessProbe(就绪探针) │ │ │ │ 方式:httpGet → GET /index1.html:80 │ │ │ │ 频率:初始延迟 1s,之后每 3s 探测一次 │ │ │ │ ✅ 返回 2xx/3xx → Pod 标记为 Ready │ │ │ │ → Service 开始将流量转发到这个 Pod │ │ │ │ ❌ 返回非 2xx/3xx 或超时 → Pod 标记为 NotReady │ │ │ │ → Service 不会将流量转发到这个 Pod │ │ │ │ → 但 Pod 中的容器不会因此被重启 │ │ │ └──────────────────────────────────────────────────────────────┘ │ │ │ │ 📌 两个探针的区别: │ │ liveness 失败 → 重启容器(粗暴恢复) │ │ readiness 失败 → 摘除流量(不影响容器运行,给时间自我修复) │ └─────────────────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────────────┐ │ 阶段 7:Running(稳态运行) │ │ 所有容器都已启动且通过存活探针检查 │ │ → Pod 状态变为 Running │ │ → 如果 readinessProbe 也通过,Pod 变为 Ready,可接收 Service 流量 │ │ → 在运行期间: │ │ • livenessProbe 持续监测,发现异常则重启容器 │ │ • readinessProbe 持续监测,发现异常则摘除流量 │ │ • 主容器进程持续运行(或按业务逻辑执行任务) │ └─────────────────────────────────────────────────────────────────────┘ ↓ (收到删除信号 —— kubectl delete pod lifecycle-pod) ↓ ┌─────────────────────────────────────────────────────────────────────┐ │ 阶段 8:终止阶段(Graceful Shutdown) │ │ API Server 收到删除请求,Pod 状态变为 Terminating │ │ │ │ ① 执行 preStop 钩子(并行执行所有容器的 preStop) │ │ ┌─────────────────────────────────────────────────────────────────┐│ │ │ 容器 A:busybox-container 有 preStop 钩子(httpGet) ││ │ │ → 向 192.168.66.11:1234/hostname.html 发 GET 请求 ││ │ │ ✅ 成功 → 记录事件,继续 ││ │ │ ❌ 失败 → 记录事件(Warning),但继续执行后续流程 ││ │ │ ⏱️ 钩子执行超时 → 进入下一步(不阻塞) ││ │ │ ││ │ │ 容器 B:myapp-container 无 preStop 钩子 → 直接跳过 ││ │ └─────────────────────────────────────────────────────────────────┘│ │ │ │ ② 向所有容器发送 SIGTERM 信号(优雅终止信号) │ │ → 容器内进程收到信号,开始执行优雅退出逻辑 │ │ → 应用应在此阶段完成:关闭连接、保存状态、释放资源 │ │ ⏱️ 等待宽限期:terminationGracePeriodSeconds(默认 30 秒) │ │ │ │ ③ 宽限期结束,强制终止 │ │ → 发送 SIGKILL 信号给仍未退出的容器 │ │ → 强制杀死所有残留进程 │ │ │ │ ④ 清理资源 │ │ → 删除 Pod 的网络和存储资源(Volume 等) │ │ → 从 etcd 中删除 Pod 记录 │ │ → Pod 彻底消失 │ └─────────────────────────────────────────────────────────────────────┘简易版总结
1. 提交 YAML → API Server 存入 etcd 2. 调度器分配 Node 3. kubelet 创建 pause 容器(申请网络/存储) 4. Init Container(按顺序串行执行) → 全部成功才继续,否则主容器永不启动 5. 主容器启动(所有主容器并行启动) ├── 容器1(busybox): │ ├── postStart 钩子(有)→ 失败则容器被重启 │ └── 主命令执行 └── 容器2(myapp): ├── postStart 钩子(无)→ 直接跳过 └── 主进程启动 6. 探针持续监测(容器运行期间) ├── livenessProbe:失败 → 重启容器 └── readinessProbe:失败 → 摘除流量(不重启) 7. Pod 进入 Running/Ready 稳态 8. 收到删除信号 → preStop 钩子 → SIGTERM → 宽限期结束 → SIGKILL → 删除