18.3.1.3 Kubernetes Pull Policies
A focused guide to Kubernetes Pull Policies, connecting core concepts with practical Docker and container operations.
Kubernetes pull policies, the explicit choice between Always, IfNotPresent, and Never for a given container, deserve a deliberate decision rather than relying purely on the implicit default tied to tag mutability, since each of the three values fits a genuinely distinct deployment scenario and choosing incorrectly produces specific, recognizable problems.
Always: appropriate for mutable references specifically
Always forces a registry check on every single pod creation, confirming whether the referenced tag currently points to different content than what might already be cached locally, which is necessary whenever the reference itself is genuinely mutable and expected to change without a corresponding manifest update:
image: my-api:latest
imagePullPolicy: Always
For a digest-pinned or genuinely immutable version-tagged reference, Always provides no actual benefit, since the content referenced can never change regardless of how often the policy forces a fresh check, making it pure, unnecessary overhead, an extra round trip to the registry on every pod creation, for a reference where IfNotPresent would produce an identical functional result with less overhead.
IfNotPresent: the right default for immutable references
IfNotPresent checks the node's local cache first and only pulls from the registry if the image is not already present there, which is the correct, efficient choice for any reference that is genuinely immutable, a specific version tag intended never to be reused, or a digest reference, since the cached content is guaranteed to remain accurate indefinitely for that exact reference:
image: my-api:1.4.2
imagePullPolicy: IfNotPresent
image: my-api@sha256:3f29a8c1...
imagePullPolicy: IfNotPresent
This is the more efficient default for the production deployment pattern of pinning by specific version or digest, since it avoids unnecessary registry round trips for content that, by the nature of the reference itself, cannot have changed since it was last cached.
Never: for pre-loaded, air-gapped, or local-only images
Never instructs the kubelet to use only whatever is already present in the node's local cache, failing outright rather than attempting any pull at all, which is the deliberate, correct choice specifically for air-gapped environments with no registry access, or for genuinely local-only images built and loaded directly onto a node without ever being pushed anywhere:
image: my-local-test-image:dev
imagePullPolicy: Never
docker save my-api:1.4.2 -o my-api.tar
ctr images import my-api.tar
A pod using this policy fails immediately and clearly if the image is not already present, which is the appropriate, fail-fast behavior for this specific scenario, rather than attempting and failing a pull against a registry the node may have no path to reach at all.
Choosing deliberately rather than relying on the implicit default
Because the default policy depends specifically on whether the tag happens to be latest, relying on this implicit default rather than setting the field explicitly means the actual pull behavior is determined by tag naming convention alone, which is easy to overlook and can produce unexpected behavior if a tag's naming changes later without anyone reconsidering the resulting pull policy implication:
image: my-api:stable
imagePullPolicy: IfNotPresent # explicit, rather than relying on the implicit non-latest default
Setting the field explicitly, regardless of which value is chosen, documents the actual intended behavior directly in the manifest rather than leaving it as an implicit consequence of tag naming that a future reader would need to already know about to correctly infer.
Consistency across containers within the same pod
A pod with multiple containers can, in principle, have different pull policies for each one, but inconsistent policies within the same pod are worth a deliberate, documented reason rather than an accidental oversight, since a pod's overall startup behavior depends on every one of its containers successfully pulling, regardless of which specific policy each one happens to use.
containers:
- name: api
image: my-api:1.4.2
imagePullPolicy: IfNotPresent
- name: sidecar
image: my-sidecar:latest
imagePullPolicy: Always
This kind of mixed configuration is occasionally legitimate, a frequently updated sidecar alongside a stable, version-pinned main container, but should be a deliberate choice rather than an inconsistency that crept in unnoticed across different container definitions within the same pod.
Testing pull policy behavior directly
Confirming a chosen policy actually behaves as expected, particularly Never for an air-gapped scenario, by deliberately testing it against a node's actual current cache state, verifies the configuration genuinely matches the deployment scenario's real constraints rather than assuming correctness based on the manifest's apparent intent alone.
kubectl delete pod my-api-7d9f8b
kubectl get events --field-selector reason=Failed
Common mistakes
- Using
Alwaysfor a digest-pinned or genuinely immutable version-tagged reference, adding unnecessary registry round-trip overhead with no corresponding benefit. - Relying on the implicit default policy tied to tag naming rather than setting the field explicitly to document actual intended behavior directly in the manifest.
- Using
Neverfor an image that genuinely needs to be pullable from a registry, producing an unnecessary, avoidable failure for a scenario that does not actually warrant this restrictive policy. - Leaving inconsistent pull policies across containers within the same pod without a deliberate, documented reason for the difference.
- Not testing a chosen pull policy's actual behavior directly against a node's real cache state, assuming correctness based only on the manifest's apparent intent.
Kubernetes pull policies should be set explicitly and deliberately for every container, matching Always to genuinely mutable references, IfNotPresent to immutable version or digest pins, and Never to air-gapped or pre-loaded scenarios specifically, rather than relying on the implicit, tag-naming-dependent default that leaves actual pull behavior an easily overlooked consequence of naming convention alone.