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 时的决策路径,以及仓库不可用时的不同结果:
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 而引入的仓库单点故障,同时保留在本地镜像缺失时自动拉取的能力。