2. 镜像拉取策略:Always、IfNotPresent、Never 的语义与适用场景,默认策略的底层逻辑

2.1 三种策略的语义定义

Kubernetes 通过 Pod 规约中的 imagePullPolicy 字段控制 kubelet 在启动容器前如何拉取镜像。该字段支持三种枚举值,其核心语义如下表所示:

策略值 核心语义 kubelet 行为
Always 每次创建 Pod 或重启容器时,始终尝试拉取最新镜像 向镜像仓库发起 pull 请求;若拉取成功则使用新镜像;若失败则 Pod 进入 ImagePullBackOff
IfNotPresent 仅当节点本地不存在指定镜像时,才从仓库拉取 检查本地镜像缓存;存在则直接启动;不存在则拉取
Never 从不主动拉取镜像,仅依赖节点本地已有镜像 仅检查本地缓存;若不存在则 Pod 立即失败,事件为 ErrImageNeverPull
关键区分:Always 保证每次运行的都是仓库最新版本,但会引入额外的网络延迟和仓库压力;IfNotPresent 是性能与一致性之间的折中;Never 则完全依赖节点预置镜像,适用于离线或高安全环境。

2.2 适用场景分析

不同策略在集群灾备、CI/CD、离线部署等场景中有明确的选择依据:

  • Always —— 适用于开发环境、CI/CD 流水线、需要频繁发布新版本的业务。灾备场景下,若主集群与灾备集群共用同一镜像仓库且网络可靠,Always 可确保灾备集群始终运行与主集群一致的版本。
  • IfNotPresent —— 适用于生产环境、灾备集群、边缘节点。当镜像版本稳定且节点已通过预拉取或预热缓存了镜像时,IfNotPresent 可大幅降低启动延迟,避免灾备切换时因仓库不可用导致 Pod 启动失败。
  • Never —— 适用于离线环境、气隙网络、安全合规要求极高的场景。灾备集群若与主集群网络隔离,且镜像已通过离线方式导入节点,Never 可防止任何意外的外网请求。
灾备陷阱:在灾备集群中滥用 Always 策略,一旦主仓库故障或灾备集群与仓库间网络中断,所有 Pod 将无法启动,导致灾备切换失败。建议灾备集群默认使用 IfNotPresent,并配合预拉取机制。

2.3 默认策略的底层逻辑

当用户未显式设置 imagePullPolicy 时,kubelet 会根据镜像标签的格式自动推断默认策略。其底层判断逻辑如下:

// 伪代码逻辑(基于 Kubernetes 源码 pkg/kubelet/images/puller.go)
if image.tag == "latest" || image.tag == "" {
    defaultPolicy = Always
} else {
    defaultPolicy = IfNotPresent
}

具体规则:

  • 如果镜像标签为 :latest 或未指定标签(默认视为 :latest),则默认策略为 Always。
  • 如果镜像标签为明确的版本号(如 :v1.2.3、:stable、:sha256@...),则默认策略为 IfNotPresent。
  • Never 策略永远不会被自动推断,必须显式声明。
底层设计意图:Kubernetes 团队认为 :latest 标签代表“可变引用”,用户期望每次运行都获取最新内容;而固定标签代表“不可变引用”,应优先复用本地缓存以提升效率。这一设计在灾备场景中尤为重要——灾备集群应避免使用 :latest 标签,否则默认 Always 策略会引入不必要的仓库依赖。

2.4 策略选择与灾备集群的关联

下图展示了三种策略在灾备集群启动 Pod 时的决策路径,以及仓库不可用时的不同结果:

镜像拉取策略决策流程(灾备集群视角) Pod 调度到节点 读取 imagePullPolicy Always:强制拉取 IfNotPresent:检查本地 Never:仅用本地 仓库可用 → 启动 仓库不可用 → ImagePullBackOff 本地存在 → 直接启动 本地不存在 → 拉取(同 Always) 本地存在 → 启动 本地不存在 → ErrImageNeverPull 灾备集群策略建议 • 主集群:Always(保证版本一致性) • 灾备集群:IfNotPresent + 预拉取(降低仓库依赖) • 离线灾备:Never + 节点镜像预置(完全隔离)

2.5 策略配置示例

以下 YAML 片段展示了如何在 Deployment 中显式指定三种策略:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-production
spec:
  template:
    spec:
      containers:
      - name: app
        image: registry.example.com/app:v3.2.1
        imagePullPolicy: IfNotPresent   # 灾备集群推荐
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-canary
spec:
  template:
    spec:
      containers:
      - name: app
        image: registry.example.com/app:latest
        imagePullPolicy: Always         # 开发/金丝雀发布
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-offline
spec:
  template:
    spec:
      containers:
      - name: app
        image: registry.example.com/app:v3.2.1
        imagePullPolicy: Never          # 离线灾备节点
最佳实践:在灾备集群的 Deployment 中,始终为镜像指定明确的非 latest 标签,并显式设置 imagePullPolicy: IfNotPresent。这可以避免因默认策略推断为 Always 而引入的仓库单点故障,同时保留在本地镜像缺失时自动拉取的能力。