在K8S中,镜像下载策略有哪些?
在 Kubernetes 中,控制容器镜像如何从镜像仓库下载的策略由 imagePullPolicy
字段定义。这个策略设置在 Pod 的容器定义部分 (spec.containers[].imagePullPolicy
)。主要有以下三种策略:
-
Always
- 行为: 每次启动 Pod 或容器时,Kubelet 都会强制尝试从镜像仓库拉取(下载)指定的镜像。
- 用途:
- 确保你总是使用镜像仓库中最新版本的镜像(例如,当你的镜像标签是
:latest
时,但这通常不是生产环境的最佳实践)。 - 在开发或测试环境中,需要频繁更新镜像并立即生效的场景。
- 当本地节点上的缓存镜像可能已被修改或损坏时(尽管这不是主要设计目的)。
- 确保你总是使用镜像仓库中最新版本的镜像(例如,当你的镜像标签是
- 注意: 即使本地节点上已经存在相同标签的镜像,也会重新拉取。这可能导致不必要的网络流量和启动延迟。
-
IfNotPresent
- 行为: Kubelet 会首先检查本地节点上是否已经存在该镜像。如果镜像存在,则直接使用本地镜像;如果镜像不存在,则从镜像仓库拉取。
- 用途:
- 最常用的策略,尤其在生产环境中。
- 优化启动速度(避免不必要的拉取)和减少网络带宽消耗。
- 适用于使用特定版本标签(如
:v1.2.3
,:sha256:abc123...
)的镜像,这些镜像一旦拉取到节点,通常不会频繁改变。
- 注意: 它依赖于本地节点的缓存。如果节点上存在一个旧的、包含安全漏洞的镜像,并且仓库中的镜像已经更新(但标签未变),
IfNotPresent
策略不会自动拉取更新。你需要更改标签或使用其他机制(如滚动更新配合新标签)来触发更新。
-
Never
- 行为: Kubelet 只使用本地节点上已有的镜像。如果本地节点上不存在所需的镜像,则不会尝试去镜像仓库拉取,容器启动会失败。
- 用途:
- 完全离线环境(air-gapped),节点无法访问任何外部镜像仓库。
- 所有需要的镜像都已预先加载(pre-pulled)到集群的所有节点上(例如,在节点初始化时通过脚本完成)。
- 对启动速度有极端要求,且能严格保证节点镜像一致性的特殊场景。
- 注意: 使用此策略需要极其谨慎地管理所有节点的镜像缓存,确保所需镜像在所有节点上都存在且版本正确。否则极易导致 Pod 启动失败。
默认行为:
- 如果你在容器定义中没有显式指定
imagePullPolicy
:- 如果容器使用的镜像标签是
:latest
(显式或隐式省略标签,K8s 会默认当作:latest
),那么默认策略是Always
。 - 如果容器使用的镜像标签是任何其他明确的标签(如
:v1.0
,:stable
,:sha256:...
),那么默认策略是IfNotPresent
。
- 如果容器使用的镜像标签是
重要注意事项:
- 标签 vs 摘要:
IfNotPresent
策略检查的是镜像标签。即使仓库中该标签指向的镜像内容已经更新(例如,myapp:latest
被重新构建推送),只要标签名没变,并且本地节点上存在一个名为myapp:latest
的镜像(无论内容新旧),Kubelet 就不会重新拉取。要确保每次拉取绝对相同的镜像内容,应使用镜像摘要(如myapp@sha256:45b23dee08af5e...
)。无论策略如何,使用摘要时 Kubelet 都会校验本地镜像的摘要是否匹配。 - 私有仓库: 从私有镜像仓库拉取镜像时(无论哪种策略,只要需要拉取),你必须通过
imagePullSecrets
为 Pod 提供访问该仓库所需的凭证(Secret)。 latest
标签的风险: 在生产环境中强烈建议避免使用:latest
标签,因为它代表一个移动的目标,难以追踪版本、回滚和保证一致性。使用语义化版本标签或提交哈希是更好的实践。使用:latest
标签结合Always
策略虽然能保证最新,但也增加了引入未知错误的风险。- 更新镜像: 当你想更新运行中的 Pod 使用的镜像时:
- 如果使用
Always
策略且标签不变(如:latest
),通常需要删除并重新创建 Pod 来触发重新拉取(Deployment 的滚动更新会自动处理这个过程)。 - 如果使用
IfNotPresent
策略,你需要修改 Pod 模板(例如,在 Deployment 中)中的镜像标签为一个新值(如从:v1.2.3
改为:v1.2.4
),然后触发滚动更新。Kubelet 看到新标签在本地不存在,就会去仓库拉取。
- 如果使用
总结:
策略 | 行为 | 典型用途 | 默认触发条件 |
---|---|---|---|
Always |
总是从仓库拉取镜像。 | 开发测试;要求绝对最新(结合latest 标签); |
镜像标签为 :latest |
IfNotPresent |
(推荐) 仅当本地不存在时拉取。 | 生产环境首选;使用固定版本标签; | 镜像标签非:latest |
Never |
只使用本地镜像,绝不拉取。 | 离线环境;所有镜像已预加载; | N/A |
选择哪种策略取决于你的具体需求、环境限制(网络、安全)以及对镜像版本控制和一致性的要求。IfNotPresent
通常是生产环境的最佳平衡点。