初始化容器

一、什么是 Init 容器?(核心定义)

Init 容器是 Pod 中专门用于 “前置初始化” 的容器,它满足两个核心特征:

  1. 运行时机:在 Pod 的所有业务容器启动之前 运行;
  2. 运行规则:必须成功执行并退出(退出码 0),否则 K8s 会反复重启 Init 容器,业务容器永远不会启动。
生活化比喻:

把 Pod 比作 “一家店”:

  • Init 容器 = 开店前的准备工作(打扫卫生、检查水电、备货);
  • 业务容器 = 店员(开始营业);
  • 只有准备工作全部做完(Init 成功),店员才会上班(业务容器启动)。
你之前的实操关联:

你部署 Calico 时看到的Init:ImagePullBackOff,就是 Calico Pod 的Init 容器拉取镜像失败,导致 Calico 的业务容器(calico-node)根本没机会启动,最终节点一直NotReady

二、Init 容器的核心特点(和业务容器的区别)

特性 Init 容器 业务容器
运行时机 所有业务容器启动前,按定义顺序执行 Init 容器全部成功后才启动
运行次数 仅运行一次(成功退出即可) 可长期运行(如 Web 服务)
重启策略 仅当执行失败时重启(默认 Always) 支持 Always/OnFailure/Never
资源限制 独立资源配额(和业务容器不共享) 共享 Pod 的资源总配额
网络 / 存储 和业务容器共享 Pod 的网络 / Volume 和 Init 容器共享 Pod 的网络 / Volume

三、Init 容器的核心作用(实战场景)

Init 容器是解决 “应用启动前依赖准备” 的最佳方案,生产中常见用法:

1. 等待依赖服务就绪(最常用)

比如:业务容器依赖 Redis/MySQL/apiserver/etcd,Init 容器循环检查这些服务是否可用,直到通了才退出。

# 示例逻辑:等待apiserver的6443端口通了再启动业务容器
until nc -z 192.168.200.10 6443; do echo "等待apiserver..."; sleep 2; done
2. 初始化配置 / 环境

比如:从 ConfigMap/Secret 拉取配置文件,写入业务容器的挂载目录;修改系统参数、创建目录。

3. 环境检查 / 预处理

比如:检查节点网络、磁盘空间、权限;下载依赖包、预热数据。

4. 依赖解耦

把 “初始化逻辑” 和 “业务逻辑” 分开,避免业务容器镜像臃肿(比如业务容器只跑 Java,Init 容器处理所有前置操作)。

四、实操:写一个带 Init 容器的 Pod YAML(直接运行)

下面写一个 “先检查百度可访问,再启动 Nginx” 的 Pod,帮你直观理解 Init 容器的运行逻辑:

# 保存为 init-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx-with-init
spec:
  # Init容器列表(按顺序执行)
  initContainers:
  - name: check-network
    image: busybox:1.36  # 轻量镜像,支持ping/wget
    command: ['sh', '-c', 'until wget -qO- https://www.baidu.com; do echo "等待网络/百度..."; sleep 2; done']
  # 业务容器
  containers:
  - name: nginx
    image: nginx:alpine
    ports:
    - containerPort: 80
执行命令 & 验证:
# 创建Pod
kubectl apply -f init-pod.yaml

# 查看Pod状态(先显示Init:0/1,等Init成功后变为Running)
kubectl get pods nginx-with-init

# 查看Init容器日志(看等待/执行过程)
kubectl logs nginx-with-init -c check-network

# 进入业务容器验证(Init成功后才能进入)
kubectl exec -it nginx-with-init -- /bin/sh

五、Init 容器常见故障排查(对应你之前的问题)

你之前遇到的Init:ImagePullBackOff是最典型的 Init 容器故障,下面列出所有常见问题及解决方法:

故障状态 原因 解决方法
Init:ImagePullBackOff Init 容器镜像拉取失败(网络 / 源 / 权限) 1. 换国内镜像源(如 busybox 换mirror.ccs.tencentyun.com/busybox);2. 手动拉取镜像并打 tag;3. 配置 containerd 镜像加速器
Init:Error Init 容器执行命令失败(退出码非 0) 1. 查看 Init 容器日志:kubectl logs <Pod名> -c <Init容器名>;2. 检查命令逻辑(比如端口写错、依赖服务真的不可用)
Init:CrashLoopBackOff Init 容器反复执行失败重启 先解决 Init 容器执行失败的根因(比如依赖服务一直不可用、命令语法错)
Init:0/2 多个 Init 容器,只完成了 0 个 按顺序排查每个 Init 容器的状态和日志

针对你之前的 Calico Init 容器故障:
# 1. 查看Calico Init容器的具体错误
kubectl describe pod <calico-node-xxx> -n kube-system  # 看Events里的Init容器报错
kubectl logs <calico-node-xxx> -c calico-node-init -n kube-system  # 看Init容器日志

# 2. 解决镜像拉取问题(换腾讯云镜像)
sudo ctr -n k8s.io images pull mirror.ccs.tencentyun.com/calico/cni:v3.25.1
sudo ctr -n k8s.io images tag mirror.ccs.tencentyun.com/calico/cni:v3.25.1 calico/cni:v3.25.1

# 3. 删除故障Pod,触发重新启动
kubectl delete pod <calico-node-xxx> -n kube-system

健康检测

一、为什么需要 Pod 健康检测?(先理解本质)

K8s 默认只判断 “容器进程是否存在”(比如docker ps看进程),但进程存在 ≠ 服务可用

  • 比如 Nginx 进程在,但配置错误导致 80 端口没监听(进程活着,服务用不了);
  • 比如 apiserver 容器 Running,但 etcd 连接没建立(进程活着,请求超时);
  • 比如 Java 应用启动要 3 分钟,启动中接收请求会直接报错。

健康检测(探针)就是让 K8s 能精准判断服务真实状态,并自动执行修复动作(重启容器、剔除流量),替代人工排查。

二、三种核心探针(存活 / 就绪 / 启动)

K8s 提供 3 类探针,覆盖容器全生命周期,核心区别和用途如下:

探针类型 核心作用 触发动作 适用场景
存活探针(livenessProbe) 检测容器 “是否活着”(进程是否正常工作) 探针失败 → 重启容器(自愈核心) 应用卡死、死循环(Nginx/Redis)
就绪探针(readinessProbe) 检测容器 “是否能提供服务”(端口 / 接口是否可用) 探针失败 → 从 Service 中剔除 Pod(不接收流量) 应用启动中、依赖未就绪(数据库 / API)
启动探针(startupProbe) 检测容器 “是否启动完成”(针对慢启动应用) 探针失败 → 持续检测,直到成功 / 超时;超时则触发存活探针重启 慢启动应用(Java/apiserver/ETCD)
探针的 3 种检测方式(新手常用前 2 种)
  • httpGet:发送 HTTP 请求,返回 200-400 则成功(适合 Web 服务、API);
  • tcpSocket:检测 TCP 端口是否通(适合数据库、Redis、apiserver 6443 端口);
  • exec:执行容器内命令,返回 0 则成功(适合自定义检测逻辑)。

三、实操:写一个带完整健康检测的 Nginx Pod

下面是包含三种探针的 Nginx Pod YAML(注释全,可直接运行),覆盖新手最常用的httpGet检测方式:

# 保存为 nginx-pod-with-probe.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx-probe-demo
  labels:
    app: nginx
spec:
  containers:
  - name: nginx
    image: nginx:alpine  # 轻量版Nginx,国内拉取快
    ports:
    - containerPort: 80  # Nginx默认端口
    # 1. 存活探针:检测Nginx是否卡死,卡死则重启
    livenessProbe:
      httpGet:
        path: /  # 检测Nginx根路径
        port: 80
      initialDelaySeconds: 10  # 容器启动后10秒开始检测(给Nginx启动时间)
      periodSeconds: 5         # 每5秒检测一次
      timeoutSeconds: 2        # 检测超时时间(2秒没响应则失败)
      failureThreshold: 3      # 连续3次失败则触发重启
    # 2. 就绪探针:检测Nginx是否能提供服务,不行则剔除流量
    readinessProbe:
      httpGet:
        path: /
        port: 80
      initialDelaySeconds: 5   # 启动后5秒开始检测(比存活探针早,优先保证流量不进未就绪Pod)
      periodSeconds: 3
      timeoutSeconds: 2
      failureThreshold: 2
    # 3. 启动探针:针对慢启动应用(这里Nginx启动快,仅演示配置)
    startupProbe:
      httpGet:
        path: /
        port: 80
      initialDelaySeconds: 3   # 启动后3秒开始检测
      periodSeconds: 2
      failureThreshold: 10     # 最多检测10次(2*10=20秒),超时则触发存活探针重启
运行与验证步骤
  1. 创建 Pod
    kubectl apply -f nginx-pod-with-probe.yaml
    
  2. 查看 Pod 状态(探针正常则 STATUS 为 Running):
    kubectl get pods nginx-probe-demo
    
  3. 模拟探针失败(验证自愈)
    • 进入 Pod,故意让 Nginx 停止 80 端口监听:
      kubectl exec -it nginx-probe-demo -- /bin/sh
      # 执行以下命令,关闭Nginx 80端口
      nginx -s stop
      exit
      
    • 等待 10 秒(存活探针检测周期),查看 Pod 事件:
      kubectl describe pod nginx-probe-demo
      
    • 能看到 Events 中提示:Liveness probe failedKilling containerStarted container(K8s 自动重启了容器)。

四、生产级配置技巧(避坑指南)

  1. 启动探针(startupProbe)必配:对慢启动应用(Java/apiserver/ETCD),一定要配置启动探针,避免就绪 / 存活探针在启动中频繁失败:

    startupProbe:
      tcpSocket:  # 检测apiserver 6443端口
        port: 6443
      failureThreshold: 30  # 最多检测30次
      periodSeconds: 5      # 每5秒检测一次(总共150秒=2.5分钟,足够apiserver启动)
    

    ✨ 关键:启动探针成功前,存活 / 就绪探针不会执行,避免误判。

  2. 就绪探针(readinessProbe)决定流量走向

    • 若 Pod 未就绪,K8s 会把它从 Service 的 Endpoint 中剔除,流量不会打到这个 Pod;
    • 比如数据库 Pod,要等初始化完成(建表 / 加载数据)后,就绪探针才返回成功。
  3. 参数调优(新手易踩坑)

    • initialDelaySeconds:不要太小(比如 Java 应用设为 60 秒,而非 5 秒);
    • failureThreshold:慢启动应用调大(比如 apiserver 设为 30);
    • timeoutSeconds:网络检测设为 2-3 秒,避免偶发网络抖动导致失败。

五、常见问题排查

  1. Pod 反复重启(CrashLoopBackOff)

    • 原因:存活探针失败,且failureThreshold次数用尽;
    • 排查:
      # 看探针失败原因
      kubectl describe pod <Pod名> | grep -A 10 "Liveness probe failed"
      # 手动验证检测地址
      kubectl exec -it <Pod名> -- curl -I http://localhost:80  # 验证httpGet
      kubectl exec -it <Pod名> -- telnet localhost 80          # 验证tcpSocket
      
  2. Pod 一直处于 NotReady 状态

    • 原因:就绪探针失败;
    • 排查:检查服务端口是否真的监听(比如netstat -tnlp | grep 80),或依赖服务(如 ETCD)是否就绪。
  3. 启动探针超时

    • 原因:failureThreshold * periodSeconds < 应用实际启动时间;
    • 解决:调大这两个参数(比如 apiserver 设为 30 次 ×5 秒 = 150 秒)。
Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐