AKS clusters can be directly attached to Azure Container Registry using managed identities — no pull secrets needed. Run: az aks update --attach-acr myacr. This grants the AKS kubelet managed identity AcrPull role on the registry.
☸️ Docker for Kubernetes and AKS
Understand how Docker images become Kubernetes workloads — image requirements for K8s/AKS, Container Runtime Interface, pull secrets, and image best practices that prevent production issues.
🧒 Simple Explanation (ELI5)
Kubernetes is the airport control tower — it decides when, where, and how many times your planes (containers) fly. Docker is the plane manufacturer — it builds the aircraft (images) according to spec. Kubernetes does not care how you built the image, it just needs a compliant container image it can pull from a registry and run.
🔧 Docker Image Requirements for K8s
image + Dockerfile
registry
container runtime (containerd)
Deployment / ReplicaSet
💻 Key Docker Practices for K8s
# K8s-ready Dockerfile checklist:
# 1. Run as non-root (K8s PodSecurityStandard: restricted)
RUN addgroup -S app && adduser -S app -G app
USER app
# 2. No hard-coded ports (use env vars)
ENV PORT=8080
EXPOSE 8080
# 3. Minimal image size — smaller = faster pulls on every node
FROM node:18-alpine # alpine saves ~200MB vs node:18
# 4. Stateless — no local data that matters
# Store data in volumes/PVCs, not container filesystem
# 5. Handle SIGTERM gracefully (K8s sends SIGTERM on pod eviction)
# Node.js example:
# process.on('SIGTERM', () => { server.close(() => process.exit(0)) })
# 6. Health check endpoints (K8s probes call these)
# GET /healthz -> 200 OK (liveness)
# GET /ready -> 200/503 (readiness)# Kubernetes Deployment referencing ACR image
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
replicas: 3
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: myacr.azurecr.io/myapp:1.2.3 # always use specific tag
ports:
- containerPort: 8080
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 15
readinessProbe:
httpGet:
path: /ready
port: 8080# Attach ACR to AKS (no pull secrets needed) az aks update \ --name myaks \ --resource-group myRG \ --attach-acr myacr # Manually create an imagePullSecret (when not using managed identity) kubectl create secret docker-registry acr-secret \ --docker-server=myacr.azurecr.io \ --docker-username=$SP_ID \ --docker-password=$SP_PASSWORD \ --namespace default
🐛 Debugging Scenario
Problem: Pod is in ImagePullBackOff state and cannot start.
# Diagnose kubectl describe pod <pod-name> # check Events section at the bottom # Common error: "unauthorized" or "not found" # Fix 1: re-attach ACR to AKS az aks update --attach-acr myacr --name myaks --resource-group myRG # Fix 2: verify image exists in registry az acr repository show-tags --name myacr --repository myapp # Fix 3: verify the full image path including registry hostname and tag kubectl get pod <pod> -o yaml | grep image # Fix 4: for private registries without managed identity, use imagePullSecrets # See secret creation command above
🎯 Interview Questions
AKS uses containerd (since Kubernetes 1.19). containerd is the Container Runtime Interface (CRI) implementation — it pulls images from registries and runs OCI-compliant containers. Docker-built images are OCI-compliant and run fine on containerd. The key implication: AKS nodes do not have the Docker daemon — docker ps commands on nodes will not work. Use crictl ps for container inspection on nodes.
An imagePullSecret is a Kubernetes secret containing registry credentials used by the kubelet to authenticate when pulling private images. You need one when AKS cannot authenticate to the registry automatically. With ACR + AKS using --attach-acr, the kubelet uses managed identity for AcrPull automatically — no imagePullSecrets needed. For other private registries (Docker Hub private, GCR, etc.) you must create the secret manually.
1. Security context: K8s may enforce non-root. Check runAsNonRoot: true in the pod spec. 2. Read-only filesystem: K8s pods sometimes have readOnlyRootFilesystem — your app must not write to the container filesystem. 3. Resource limits: K8s applies strict CPU/memory limits; OOMKilled is common. 4. Health probes: liveness probe may be too aggressive and killing the container before it is ready. 5. Environment variables: Kubernetes does not share your local env — check all required vars are set via ConfigMaps/Secrets.
📋 Summary
- AKS uses containerd — Docker builds OCI-compliant images that run on it transparently.
- Use
--attach-acrto connect AKS to ACR with managed identity — no pull secrets needed. - K8s-ready images: non-root user, graceful SIGTERM handling, /healthz and /ready endpoints, no local state.
- Always specify exact image tags in Deployments — never
:latestin production. - Debug
ImagePullBackOffwithkubectl describe podand check registry auth and image path.