Back to Blog
Lesson 50 of the Kubernetes: Kubernetes Concepts & Your First Pod course
KubernetesSeptember 7, 20263 min read

Using Init Containers: Ensuring Reliable Application Startup

Learn how to use InitContainers in Kubernetes to handle database migrations, dependency checks, and configuration tasks before your main application starts.

KubernetesContainersDevOpsInfrastructureCloudNative
Overhead view of yellow and weathered plastic storage bins arranged neatly.

Previously in this course, we discussed Managing Application Configuration with Kubernetes ConfigMaps and Injecting Environment Variables in Kubernetes Pods. While those lessons focused on how to pass data into your pods, this lesson addresses a common operational problem: how to guarantee that your application doesn't start until its requirements—like a database or a remote service—are actually reachable.

Understanding InitContainers

By default, when you deploy a Pod, all containers start simultaneously. If your application crashes immediately because it can't connect to a database that is still booting up, you end up in a CrashLoopBackOff state.

An initContainer is a specialized container that runs before your main application containers. They must complete successfully before the main containers begin their execution. If an initContainer fails, Kubernetes restarts the Pod repeatedly until it succeeds. This makes them perfect for:

  • Dependency Checking: Waiting for a database or API to become reachable.
  • Environment Preparation: Setting up permissions, creating directories, or pulling secret configurations.
  • Database Migrations: Running schema updates before the application code connects.

Practical Example: Waiting for a Database

In this example, we’ll create a Pod that waits for a PostgreSQL service to be ready before starting a web server.

YAML
apiVersion: v1
kind: Pod
metadata:
  name: my-app-pod
spec:
  containers:
  - name: web-app
    image: my-web-app:latest
  initContainers:
  - name: wait-for-db
    image: busybox:1.28
    command: ['sh', '-c', 'until nslookup postgres-service; do echo waiting for db; sleep 2; done;']

In this manifest, the wait-for-db container uses a simple nslookup command inside a loop. The Pod will remain in the Init phase until nslookup successfully resolves the postgres-service name via CoreDNS. Once that returns a success code (exit 0), the initContainer terminates, and the web-app container starts immediately.

Hands-on Exercise: Dependency Verification

  1. Create a file named init-demo.yaml with the code above.
  2. Deploy the pod using kubectl apply -f init-demo.yaml.
  3. Observe the startup phase using kubectl get pod my-app-pod. You will see it stuck in Init:0/1.
  4. If you have a service named postgres-service in your cluster, the pod will transition to Running. If not, it will hang indefinitely—this is the intended behavior of a dependency check!

Common Pitfalls

  • Blocking Forever: If your initContainer contains a logic error (like an infinite loop that never checks the right service), your Pod will never start. Always include a sleep command to avoid hammering your API server or network.
  • Resource Limits: InitContainers consume resources. While they run, they use the requests and limits defined in their spec. If you don't define them, they use the Pod's default resource constraints.
  • Complexity: Don't put "heavy" logic in an initContainer. It is meant for setup, not long-running tasks. If it takes too long, your deployment will appear stalled.

FAQ

Can I have multiple InitContainers? Yes. They execute sequentially in the order you define them in the YAML.

What happens if an InitContainer crashes? Kubernetes will restart the Pod based on the restartPolicy (usually Always), effectively retrying the init sequence until it succeeds.

Can I pass files from an InitContainer to my main container? Absolutely. You can mount a shared emptyDir volume in both the initContainer and the main container. The init container can write a config file, and the main container can read it.

Recap

InitContainers provide a robust way to enforce ordering in your deployments. By using them for dependency checks and setup tasks, you move complexity out of your application code and into the infrastructure layer, leading to more resilient and "self-healing" deployments.

Up next: We will explore how to run multiple containers that need to work together permanently by building Multi-Container Pods.

Similar Posts