Path to Kubernetes
Docker + Kubernetes: how images run on K8s. Pull, secrets, pod spec, troubleshooting Docker-specific issues.
Docker — Docker + Kubernetes
EXAMPLE
# ===== The relationship =====
# Kubernetes runs containers built from Docker (or OCI) images.
# K8s no longer uses Docker as the runtime (dropped containerd as default in 1.24+),
# but Docker images still work because they follow the OCI spec.
# ===== Build image, push, deploy =====
# 1. Build with Docker:
docker build -t ghcr.io/me/shop:v1 .
# 2. Push to registry:
docker push ghcr.io/me/shop:v1
# 3. Reference in K8s manifest:
apiVersion: apps/v1
kind: Deployment
metadata: { name: shop }
spec:
replicas: 3
selector: { matchLabels: { app: shop } }
template:
metadata: { labels: { app: shop } }
spec:
containers:
- name: shop
image: ghcr.io/me/shop:v1 # the Docker-built image
ports: [{ containerPort: 3000 }]
# ===== Private registry credentials =====
# Create a docker-registry secret:
kubectl create secret docker-registry ghcr-creds \
--docker-server=ghcr.io \
--docker-username=USERNAME \
--docker-password=TOKEN \
--namespace=apps
# Reference in pod spec:
spec:
imagePullSecrets:
- name: ghcr-creds
containers: [...]
# ===== Image pull policy =====
imagePullPolicy: Always # for moving tags (latest, dev)
imagePullPolicy: IfNotPresent # for immutable tags (digest, semver)
imagePullPolicy: Never # for locally-loaded images (kind / minikube)
# ===== Common issues =====
# 1. ImagePullBackOff
# - Wrong image name / tag
# - Missing imagePullSecrets for private registry
# - Registry unreachable from cluster
# 2. CrashLoopBackOff with 'exec format error'
# - Image built for wrong architecture (e.g. arm64 image on amd64 nodes)
# - Solution: buildx with --platform linux/amd64,linux/arm64
# 3. CrashLoopBackOff with exit code immediately
# - CMD wrong; check 'kubectl logs --previous'
# - Wrong entrypoint, missing env vars, file permissions
# 4. Slow startup -> liveness probe failing
# - Add startup probe with initialDelaySeconds
# - Increase failureThreshold
# ===== Multi-arch builds =====
docker buildx create --use --name multi
docker buildx build --platform linux/amd64,linux/arm64 -t ghcr.io/me/shop:v1 --push .
# Now the image works on both amd64 nodes (most cloud K8s) and arm64 nodes (Graviton, Apple Silicon).
# ===== Image scanning =====
# In CI:
trivy image ghcr.io/me/shop:v1 --severity HIGH,CRITICAL --exit-code 1
# In cluster (admission controller):
# Kyverno / Falco / Connaisseur can verify signatures + scan results before allowing pods.
# ===== Local dev =====
# kind: load image into the cluster without registry push
kind load docker-image ghcr.io/me/shop:dev --name dev
# minikube:
eval $(minikube docker-env)
docker build -t shop:dev .
# ===== Patterns =====
# - Build with Docker; pull from registry in K8s
# - imagePullSecrets for private registries
# - Pin by digest in production (image@sha256:...)
# - Multi-arch builds for cross-platform clusters
# - Scan in CI; sign images; verify at admission
# ===== Pitfalls =====
# - Image built locally + not pushed -> ImagePullBackOff
# - imagePullPolicy: Always wasting bandwidth on immutable tags
# - 'latest' tag in prod -> non-deterministic deploys
# - Wrong architecture -> 'exec format error'
Why it matters
Docker images run on K8s via the registry. Build with buildx for multi-arch, push to a registry, reference in pod spec, set imagePullSecrets for private. Pin by digest in prod, scan in CI, sign for admission. ImagePullBackOff and CrashLoopBackOff are the daily diagnoses.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
# Once you have many containers + replicas + rolling deploys, K8s starts to earn its keep. # Start with managed K8s (EKS, GKE, AKS).Try it Yourself »
Discussion
Loading…