Introduction
An init container runs before the main application containers in a Pod. Each init container must finish successfully before Kubernetes starts the next init container or any regular container. This makes init containers useful for preparing files, checking dependencies, or performing small setup tasks that should not stay running beside the application.
In this lab, you will add an init container that writes a startup file into a shared emptyDir volume, confirm that the application container can read the file, inspect the init container's completed status and logs, and then use the same pattern in a Deployment template.
Prepare an Init Container Namespace
In this step, you will prepare a clean namespace for init container practice.
Start in /home/labex/project. You will write Pod and Deployment manifests in this directory.
mkdir -p /home/labex/project
cd /home/labex/project
Check that the Kubernetes API server is reachable. If the VM has just started and the node is not ready yet, wait a few seconds and run the command again.
kubectl get nodes --request-timeout=5s
Expected output includes:
NAME STATUS ROLES AGE VERSION
labex-v135 Ready control-plane ... v1.35...
Init containers run inside Pods, so wait until the cluster networking Pod is Ready before creating workloads.
kubectl wait --namespace kube-system --for=condition=Ready pod -l k8s-app=calico-node --timeout=120s
Expected output:
pod/calico-node-... condition met
Create a namespace named ckad-prep-init:
kubectl create namespace ckad-prep-init
Set this namespace as the current context namespace:
kubectl config set-context --current --namespace=ckad-prep-init
Confirm the current namespace:
kubectl config view --minify --output 'jsonpath={..namespace}'; echo
Expected output:
ckad-prep-init
Prepare Shared Data Before the App Starts
In this step, you will create a Pod where an init container prepares a file before the application container starts.
The emptyDir volume is created when the Pod is assigned to a node and is shared by containers in the same Pod. Both the init container and the app container mount this volume at /work. The init container writes /work/startup.txt, then exits. Only after it exits successfully does Kubernetes start the app container.
Create init-file-pod.yaml:
cat > init-file-pod.yaml <<'EOF'
apiVersion: v1
kind: Pod
metadata:
name: init-file-demo
labels:
app: init-file-demo
spec:
terminationGracePeriodSeconds: 0
volumes:
- name: shared-work
emptyDir: {}
initContainers:
- name: prepare-startup-file
image: busybox:1.36
command:
- /bin/sh
- -c
- 'echo init-started; echo prepared-by-init > /work/startup.txt; echo init-finished'
volumeMounts:
- name: shared-work
mountPath: /work
containers:
- name: app
image: busybox:1.36
command:
- /bin/sh
- -c
- 'echo app-started; cat /work/startup.txt; sleep 3600'
volumeMounts:
- name: shared-work
mountPath: /work
EOF
Apply the manifest:
kubectl apply -f init-file-pod.yaml
Expected output:
pod/init-file-demo created
Wait until the Pod is Ready:
kubectl wait --for=condition=Ready pod/init-file-demo --timeout=120s
Expected output:
pod/init-file-demo condition met
Read the file from inside the app container. This proves that the init container prepared data on the shared volume before the app started.
kubectl exec init-file-demo -c app -- cat /work/startup.txt
Expected output:
prepared-by-init
Inspect Init Container Status and Logs
In this step, you will inspect evidence that the init container completed before the app container kept running.
Init containers appear under .status.initContainerStatuses, while regular containers appear under .status.containerStatuses. The init container should have a Completed reason because it exited successfully.
kubectl get pod init-file-demo -o 'jsonpath={.status.initContainerStatuses[0].name}{" "}{.status.initContainerStatuses[0].state.terminated.reason}{"\n"}'
Expected output:
prepare-startup-file Completed
Now inspect the regular application container status. It should be ready and running.
kubectl get pod init-file-demo -o 'jsonpath={.status.containerStatuses[0].name}{" "}{.status.containerStatuses[0].ready}{" "}{.status.containerStatuses[0].state.running.startedAt}{"\n"}'
Expected output includes:
app true ...
Read the init container logs. Even though the init container has finished, its logs remain available through kubectl logs -c.
kubectl logs init-file-demo -c prepare-startup-file
Expected output:
init-started
init-finished
Read the app container logs. The app starts after the init container writes the file, so its logs include the prepared value.
kubectl logs init-file-demo -c app
Expected output includes:
app-started
prepared-by-init
Add an Init Container to a Deployment
In this step, you will use the same init container pattern inside a Deployment template.
For application workloads, you usually place init containers in a controller's Pod template instead of creating standalone Pods. When the Deployment creates a Pod, Kubernetes runs the init container first for each Pod created from that template.
Create init-deployment.yaml:
cat > init-deployment.yaml <<'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
name: init-web
spec:
replicas: 1
selector:
matchLabels:
app: init-web
template:
metadata:
labels:
app: init-web
spec:
terminationGracePeriodSeconds: 0
volumes:
- name: web-content
emptyDir: {}
initContainers:
- name: render-index
image: busybox:1.36
command:
- /bin/sh
- -c
- 'echo deployment-init > /site/index.txt'
volumeMounts:
- name: web-content
mountPath: /site
containers:
- name: web
image: busybox:1.36
command:
- /bin/sh
- -c
- 'cat /site/index.txt; sleep 3600'
volumeMounts:
- name: web-content
mountPath: /site
EOF
Apply the Deployment:
kubectl apply -f init-deployment.yaml
Expected output:
deployment.apps/init-web created
Wait until the Deployment is available:
kubectl wait --for=condition=Available deployment/init-web --timeout=120s
Expected output:
deployment.apps/init-web condition met
Find the Pod created by the Deployment:
web_pod="$(kubectl get pods -l app=init-web -o 'jsonpath={.items[0].metadata.name}')"
echo "$web_pod"
Expected output shows a generated Pod name:
init-web-...
Read the app container logs from that Pod:
kubectl logs "$web_pod" -c web
Expected output:
deployment-init
Inspect the init container completion status inside the Deployment-created Pod:
kubectl get pod "$web_pod" -o 'jsonpath={.status.initContainerStatuses[0].name}{" "}{.status.initContainerStatuses[0].state.terminated.reason}{"\n"}'
Expected output:
render-index Completed
Summary
You added init containers to a Pod and a Deployment template. You used an emptyDir volume to share prepared files with the app container, inspected completed init container status, read init and app logs, and confirmed that the same pattern works for controller-managed application Pods.


