Init Containers in Kubernetes

Init Containers in Kubernetes

A friendly, step-by-step guide to the small helper containers that get a pod ready before your application starts: what they are, how they run in order, how they share files, where they shine, where they hurt, and how to use them safely.

Imagine a theatre on the evening of a big show. Before the audience walks in, a crew has already been busy. Someone sweeps the stage. Someone sets the props in the right places. Someone tests the lights and the microphones. Only when every job is done does the curtain rise and the actors step out. If the crew had not finished, the actors would trip over boxes or speak into a dead microphone.

Kubernetes has exactly such a crew. Before the main application in a pod starts, one or more small helper containers run first, do their preparation jobs one after another, and then disappear. Only when every helper has finished successfully does the real application begin. These helpers are called init containers.

In this guide we will build the idea from zero, one small step at a time. Every new word is explained the first time it appears, and every big idea comes with an everyday comparison so it sticks. By the end you will know what init containers are, exactly how they behave, when to use them, when to avoid them, and how to keep them safe and healthy.

1What Are Init Containers?

To understand init containers we first need a handful of simple words: container, pod, kubelet, volume and init.

Word 1

Container

A container is a small sealed box that holds a program and everything it needs to run. Kubernetes starts and stops containers for you.

Word 2

Pod

A pod is the smallest unit Kubernetes runs. It holds one or more containers that live together on the same computer and share the same network address.

Word 3

Kubelet

The kubelet is the agent that runs on every computer in the cluster. It starts the containers of the pods placed on its computer and watches over them.

Word 4

Volume

A volume is a folder that containers in a pod can share. One container can write files into it, and another can read them.

Word 5

Init

“Init” is short for “initialise”, which means “get things ready”. An init container gets the pod ready. It is a preparation step, not the main event.

Word 6

App container

The ordinary containers in a pod, the ones that do the real work for your users, are called app containers to tell them apart from init containers.

So what exactly is an init container?

An init container is a special container inside a pod that runs before any of the pod’s app containers. It runs to completion, which means it does its job and then exits. If the pod has several init containers, they run strictly one after another, in the order they are written. The app containers start only after the last init container has finished successfully.

Think of it as a checklist that must be fully ticked before the doors open. Each item is a small container. If any item fails, the checklist stops, the item is tried again, and the doors stay closed until everything passes.

Everyday analogy

Think of a pilot’s pre-flight checklist. Check the fuel. Check the flaps. Check the instruments. The pilot does not skip ahead, and the plane does not take off until every item is done. The checklist items are the init containers. The flight itself is the application.

The four golden rules

Almost everything about init containers follows from four simple rules. Keep these in mind and the rest of the guide will feel natural.

Rule 1

They run first

Every init container must finish before any app container starts. The app never sees a half-prepared pod.

Rule 2

They run in order

Init containers run one at a time, top to bottom. The second does not start until the first has succeeded.

Rule 3

They must succeed

A failed init container is retried. The pod cannot move on while any init container is failing.

Rule 4

They run again on a fresh start

If the whole pod is restarted, every init container runs again from the beginning. So they must be safe to repeat.

A short history

Google released Kubernetes as open source in 2014. Very early on, users noticed that many applications need some preparation before they can start: waiting for a database, fetching a settings file, fixing folder permissions. People squeezed these tasks into complicated start-up scripts inside the main container, which made images bloated and fragile. Init containers arrived as an early experimental feature and became a stable, officially supported part of Kubernetes in version 1.6, in 2017. They have been a standard tool ever since.

i
Remember this

An init container answers one question: “What must be true before my application starts?” Anything that is a one-time preparation step, and must finish before the app begins, is a candidate.

2The Problem Init Containers Solve

Ordinary containers all start at the same time, with no promise about order. That is fine for many programs and painful for others.

Everything starts together

In a pod, all the ordinary containers are launched at about the same moment. Kubernetes does not wait for one to become ready before starting the next. This is simple and fast, but it creates several real-world headaches.

Headache 1

Missing neighbours

An application needs a database or another service to be reachable at start-up. If it starts too early, it crashes, restarts, crashes again, and floods the logs with errors until the neighbour finally appears.

Headache 2

Missing files

The application expects a settings file, a certificate or a data set to be present when it starts. Something has to fetch or create it first.

Headache 3

Wrong permissions

A freshly attached storage folder is owned by the administrator, but the application runs as an ordinary user and cannot write to it. Someone has to fix the ownership before the app starts.

Headache 4

Heavy tools in the wrong place

Preparation often needs tools such as a git client, a download tool or a database client. Adding them to the application image makes it larger and gives attackers more to play with.

The old workaround and why it hurts

Before init containers were common, teams wrote long start-up scripts that ran inside the application container. The script would wait for the database, download files, fix permissions, and only then start the program. This works, but it has serious downsides.

The image must contain every tool the script needs, so it grows. The script runs with the same permissions as the application, so any power needed for preparation, such as changing file ownership, stays available to the application forever. Errors in the script are mixed with errors in the application, which makes logs confusing. And nobody can see from outside whether the pod is “preparing” or “running”, since it is all one container.

ConcernStart-up script inside the app imageInit container
Tools needed for preparationBundled into the application imageLive in a separate, purpose-made image
Permissions during preparationSame as the application, for its whole lifeSeparate, and gone once the step ends
LogsMixed with application outputKept in a separate stream per init container
VisibilityPod just says RunningPod shows Init progress such as Init:1/3
Retrying failuresWritten by hand in the scriptProvided by Kubernetes
ReuseCopy the script into every imageShare one init image across many applications
flowchart TB
  subgraph WITHOUT["Without init containers: everything starts at once"]
    direction LR
    A1["Pod starts"] --> A2["App container starts immediately"]
    A2 --> A3["Database or file not ready yet"]
    A3 --> A4["App crashes and restarts repeatedly"]
  end
  subgraph WITH["With init containers: preparation comes first"]
    direction LR
    B1["Pod starts"] --> B2["Init container prepares and waits"]
    B2 --> B3["Preparation succeeds"]
    B3 --> B4["App container starts into a ready world"]
  end
    
Figure 1. The same pod, without and with an init container.
Everyday analogy

Consider a restaurant kitchen at opening time. The head chef could start cooking the moment the door opens and hunt for missing onions in the middle of service. Or a prep cook can arrive an hour earlier, wash, chop and stock the stations, and leave before the first customer sits down. The chef then cooks in a ready kitchen. The prep cook is the init container, and their tools, such as a big chopping board, never clutter the main stove.

1st
init containers always run before app containers
1 by 1
they run in order, never in parallel
0
app containers start while any init container is unfinished
!
Watch out

Init containers are not a cure for fragile applications. A well-built application should also cope with a neighbour being briefly unavailable later on. Use init containers for real one-time preparation, not to hide poor error handling.

3Core Concepts

Init containers look like ordinary containers, but a few important differences define how they behave. Learn these and everything else will fit.

How init containers differ from ordinary containers

QuestionInit containerOrdinary app container
When does it start?Before any app containerAfter all init containers finish
How many run at once?One at a time, in written orderAll together
How long does it live?Until it finishes, then it is goneFor the life of the pod
What if it fails?Retried; the pod cannot proceedRestarted according to the pod’s restart rule
Health probes?Not supported for the classic kindLiveness, readiness and startup probes allowed
Does it receive traffic?NoYes, when the pod is ready
Can it share folders with app containers?Yes, through volumesYes, through volumes

What they share and what they keep separate

All containers in a pod share the same network address and can share volumes. Each container, however, has its own image and therefore its own file system. This is the key design idea. An init container can use a completely different image from the app, packed with exactly the tools it needs. It communicates its results to the app through a shared volume, a folder both can see.

Shared

Network

The init container and the app share the pod’s network address. An init container can reach other services just as the app would, so it can truthfully test whether they are ready.

Shared

Volumes

A folder mounted in both lets the init container leave files behind for the app. This is the main way results are handed over.

Separate

Image and tools

Each container uses its own image, so preparation tools never have to be installed in the application image.

Separate

Security settings

An init container can run with different permissions from the app. It can, for example, briefly run as an administrator to fix folder ownership, while the app runs as an ordinary user.

Separate

Resource requests

Each container asks for its own processor and memory. The pod’s overall need is worked out from all of them, as we explain in Chapter 5.

Separate

Logs

Each container has its own log stream, so preparation messages never mix with application messages.

Everyday analogy

Imagine a shared workshop with one entrance and one big table in the middle. The carpenter who prepares the wood and the painter who finishes the piece bring different tools and wear different clothes, but they share the room and the table. The carpenter finishes first and leaves the prepared wood on the table for the painter. The table is the shared volume.

Reading the pod status

Because init containers run first, the pod’s status column tells a story as they progress. You will meet these words often.

Status shownMeaning
Init:0/2The pod has two init containers, and none has finished yet
Init:1/2One of two init containers has finished; the second is running or waiting
Init:ErrorAn init container exited with a failure
Init:CrashLoopBackOffAn init container keeps failing, and Kubernetes is waiting longer between retries
PodInitializingAll init containers are done; the app containers are being created
RunningThe app containers are up
i
Good to know

While init containers are running, the pod is not Ready and receives no traffic. That is exactly the point: nobody is sent to a pod that is still preparing itself.

4Architecture and Components

Init containers are not a separate machine or a separate service. They are part of the pod, managed by the same parts of Kubernetes that manage every other container. Let us meet the players.

flowchart TB
  API["API Server holds the pod definition"] --> SCH["Scheduler picks a node using the pod's effective resource needs"]
  SCH --> KUB["Kubelet on the chosen node"]
  KUB --> SBX["Pod sandbox: network address and shared settings"]
  KUB --> IC1["Init container 1"]
  IC1 --> IC2["Init container 2"]
  IC2 --> APP["App containers"]
  VOL["Shared volume"] --- IC1
  VOL --- IC2
  VOL --- APP
  KUB -->|"status and events"| API
    
Figure 2. The pod definition travels to a node, where the kubelet runs the init containers one by one, then the app containers, sharing volumes throughout.

Piece by piece

The pod definition is where you write the init containers. It has one list for init containers and another for the ordinary app containers. The order of the init list is the order of execution. Names must be unique across both lists, so an init container cannot share a name with an app container.

The API server stores the definition and is the notice board through which everything else learns about it. When the kubelet reports progress, such as “init container one finished”, the API server records it in the pod’s status, which is what you see with your status commands.

The scheduler decides which computer will host the pod. It must know how much processor and memory the pod needs. For a pod with init containers, this is worked out in a special way that we explain in the next chapter, so a hungry init container can affect where the pod lands.

The kubelet is the star of the show. It runs on the chosen computer, creates the pod’s shared environment, starts each init container in turn, watches for its exit, and then starts the next step. It is also the one that decides what to do when an init container fails.

The pod sandbox is the shared environment that exists before any of your containers. It holds the pod’s network address and shared settings. Because it is created first, even the very first init container already has a network address and can reach other services, which is essential for the “wait for a neighbour” pattern.

The container runtime is the software that actually creates and runs containers on request from the kubelet. It pulls images, starts processes, and reports exit codes back.

Shared volumes are the bridge between preparation and application. The most common kind is a temporary folder that is created empty when the pod starts and deleted when the pod ends. An init container fills it. The app reads it.

Everyday analogy

Think of moving into a new office. The building management (API server and scheduler) assigns you a floor. The facilities supervisor (kubelet) walks the floor. First the electricians (init containers) wire the desks, then the cleaners (a second init container) polish the floor, one after the other. The shared cupboard in the corner (a volume) is where the electricians leave the keys for the staff. Only then do the employees (app containers) walk in.

1
kubelet per computer controls the whole start-up order
2
lists in the pod definition: init containers and app containers
Same
network address for init and app containers in one pod
!
Common surprise

Init containers cannot be added to a running pod. The list is fixed at creation, and only the image of an init container may be changed later. Changing it restarts the pod, so it is best to change init containers through a new rollout of the workload that owns the pod.

5How Init Containers Work Internally

Here is what the kubelet does, step by step, from the moment a pod arrives on its computer.

flowchart TD
  A["Kubelet picks the next init container in written order"] --> B["Pull the image if needed and start it"]
  B --> C{"Did it exit with code zero?"}
  C -->|"Yes"| D{"Are more init containers waiting?"}
  D -->|"Yes"| A
  D -->|"No"| E["Start all app containers"]
  C -->|"No"| F{"Does the pod restart rule allow a retry?"}
  F -->|"Yes"| G["Wait with a growing delay then restart the same init container"]
  G --> B
  F -->|"No"| H["Pod is marked as failed"]
    
Figure 3. The decision loop that runs for every init container.
1

Prepare the ground

The kubelet creates the pod sandbox with its network address, attaches the volumes, and pulls any secrets or settings the pod refers to. If a required secret or setting is missing, the pod cannot proceed, and its status says so.

2

Start the first init container

The image is downloaded if it is not already on the computer, then the container starts. The kubelet now simply waits for it to end.

3

Judge by the exit code

An exit code of zero means success, and anything else means failure. This is the only signal that matters. The kubelet does not read the container’s output or judge how “good” the work was.

4

Move on or retry

On success the kubelet starts the next init container. On failure it retries the same one, using growing waits between attempts, up to five minutes, provided the pod’s restart rule allows retrying. If the rule is “never”, the whole pod is marked failed instead.

5

Record the milestone

When the last init container succeeds, the pod gains a condition named Initialized. This is a public sign that preparation is complete.

6

Start the app containers

All app containers are started together. From here on, the usual rules of probes, readiness and restarts apply.

How the scheduler counts resources

Because init containers run one at a time, and each finishes before the next begins, they never use resources at the same moment. The app containers, on the other hand, all run together. Kubernetes therefore computes the pod’s effective need in a clever way: for each resource, it takes the larger of two numbers. The first number is the biggest request of any single init container. The second is the total of all the app containers’ requests added together.

Here is a worked example. The first init container asks for half a processor core and 256 megabytes of memory. The second asks for a fifth of a core and one gigabyte. The app containers together ask for four tenths of a core and 512 megabytes. For processor, the biggest init request is half a core, and the app total is four tenths, so the pod counts as needing half a core. For memory, the biggest init request is one gigabyte, and the app total is 512 megabytes, so the pod counts as needing one gigabyte.

The lesson is important. A heavy init container, for example one that unpacks a big archive, can make the whole pod look expensive to the scheduler for its entire life, even though that heavy work lasts only seconds. Keep init containers modest, or you may find pods refusing to fit onto computers where they would otherwise be welcome.

Everyday analogy

Think of booking a hall for a wedding. The decorators arrive first and need a large empty space to unroll their equipment. The guests arrive later and need seating for everyone. The hall you must book is large enough for the bigger of the two moments, not the sum of both, because they never overlap. But if the decorators need an enormous space, you book an enormous hall even though the guests will use a smaller part of it.

What retries really mean

When an init container fails, Kubernetes does not create a new pod. It restarts the same init container inside the same pod. Between attempts the delay grows: roughly ten seconds, then twenty, forty, and so on, up to a maximum of five minutes. This keeps a broken step from hammering the computer, but it also means a pod with a persistently failing init container may sit in the status Init:CrashLoopBackOff, retrying every few minutes for as long as nobody fixes the cause.

Notice that there is no built-in time limit for an init container. If it waits forever for a database that never appears, the pod waits forever too. The only outer limit is the pod-wide deadline, an optional setting that ends the pod after a set number of seconds no matter what. Good init containers therefore carry their own sensible time limits and give up with a clear message.

i
Tip

Print a clear, human-readable message from every init container: what it is waiting for, how long it has waited and why it failed. When someone looks at the logs at three in the morning, that message will be the whole investigation.

6Data Flow and Lifecycle

Now let us follow one pod through its whole life, watching what the init containers do and how their results reach the application.

sequenceDiagram
  participant U as User
  participant A as API Server
  participant K as Kubelet
  participant I1 as Init container 1
  participant I2 as Init container 2
  participant P as App containers
  U->>A: Create the pod
  A->>K: Pod is assigned to this node
  K->>K: Create the sandbox and attach volumes
  K->>I1: Start init container 1
  I1-->>K: Exit with code zero
  K->>I2: Start init container 2
  I2-->>K: Exit with code zero
  K->>P: Start the app containers
  K->>A: Report Initialized then Ready
    
Figure 4. From creating a pod to a running application, with init containers finishing in turn.

The stages of life

Stage 1

Pending

The pod exists, and is being placed on a computer and set up. The phase stays Pending throughout the whole init period.

Stage 2

Initialising

Init containers run one by one. The status shows how many have finished, such as Init:1/2.

Stage 3

Initialized

The last init container has succeeded. The pod records this milestone.

Stage 4

Starting

App containers are created and start. The status may briefly show PodInitializing or ContainerCreating.

Stage 5

Running and Ready

The app’s probes pass, and the pod begins receiving traffic. The finished init containers appear in the details as terminated with reason Completed.

Stage 6

Terminating

When the pod is deleted, app containers are stopped politely and the pod disappears, along with its temporary volumes.

How data moves from init container to application

The usual pattern is a shared temporary folder. The pod definition declares a volume, and mounts it into both the init container and the app container, possibly at different folder paths. The init container writes its result there, such as a downloaded settings file or a generated certificate. When it exits, the folder and its contents remain. The app then starts and simply reads the files as though they had always been there.

Other channels exist too. An init container can write to a persistent volume, which survives the pod. It can also call a remote service to register the pod or to fetch a secret. What it cannot do is pass an environment variable to the app: environment variables are fixed when each container is created, and one container cannot change another’s.

When do init containers run again?

This is the most important lifecycle question, and the source of many surprises. There are three situations.

An app container crashes and restarts

The init containers do not run again. Only the crashed app container restarts, in the same pod, with the shared volume intact. The preparation done earlier is still in place.

The whole pod is recreated

A new pod, for example after a deployment update, a scale-up, or the old pod being deleted, is a brand-new pod. Its init containers run from the very start, and the temporary volume begins empty again.

The pod’s sandbox is restarted

If the pod’s shared environment is recreated on the same computer, for instance after the computer restarts, all init containers run again, in order, before the app containers return. The same can happen if the record of a finished init container is cleaned up. This is why every init container must be safe to run more than once.

Everyday analogy

Setting up a market stall each morning is like an init container. If a customer knocks over one basket during the day, you just pick it up; you do not tear down and rebuild the whole stall. But if the stall is packed away overnight and set up again tomorrow, the entire opening routine happens again from step one.

!
Read this twice

Do not put a step in an init container that would be harmful if repeated, such as “add a row to a billing table” or “send a welcome email”. Assume every init container will run more than once, and design each so that repeating it changes nothing.

7Usage Patterns You Will Meet

Most real-world init containers fall into a small set of patterns. Learn to recognise them and you can design a good one for almost any situation.

Wait for a dependency

The most famous pattern. The init container repeatedly checks whether a database, a message broker or another service is reachable, sleeping a few seconds between tries. When the check succeeds, it exits with success and the application starts, knowing its neighbour is there. Each check is tiny, such as a network connection attempt or a name lookup.

flowchart TD
  S["Init container starts"] --> P["Try to reach the database"]
  P --> Q{"Did it answer?"}
  Q -->|"Yes"| OK["Exit with code zero and let the app start"]
  Q -->|"No"| W{"Waited longer than the limit?"}
  W -->|"No"| Z["Sleep a few seconds"]
  Z --> P
  W -->|"Yes"| F["Print a clear message and exit with an error"]
    
Figure 5. The wait-for-dependency pattern, with a sensible time limit.

Fetch configuration or secrets

The init container contacts a settings service or a secrets vault, downloads what the application needs, and writes it into a shared folder. The application then reads plain files and needs no knowledge of the vault, and no credentials to reach it.

Clone content from a source repository

A web server pod needs the latest site content. An init container with a git tool clones the content into a shared folder. The web server image stays small and contains no git tool at all.

Render a configuration from a template

Some programs need a settings file that combines fixed text with values known only at run time, such as the pod’s own address. An init container fills in the template and writes the finished file for the application.

Fix folder ownership and permissions

A newly attached storage volume is often owned by the administrator. An init container running with just enough power changes the ownership so that the application, running as an ordinary user, can write. The elevated power exists only during this brief step.

Tune the environment

A few programs need kernel-level settings, such as a higher limit on memory maps for search engines. An init container with special permission can apply them before the application starts. This needs care, because it requires privileges that we discuss in the security chapter.

Generate certificates or keys

The init container creates a private key and requests a certificate for this specific pod, storing both in a shared folder that only this pod can see. The application starts with its own identity ready.

Download data or models

A machine-learning service needs a large model file. An init container downloads it once at start-up, verifies it, and unpacks it into a shared folder. The service image stays small and the download logic is separate from the model-serving code.

Copy tools or plug-ins into a shared folder

Instead of baking a monitoring agent into every application image, an init container from a separate image copies the agent files into a shared folder, and the application is started with the agent attached. One agent image serves many applications.

Set up network rules

Service mesh products classically use an init container with special network permission to redirect the pod’s traffic through a helper proxy before the application starts. Users of a mesh meet this pattern without writing it.

Database schema migration, with caution

Some teams run migrations that update database tables in an init container, so that the new application version always finds the schema it expects. This can work for small systems. For larger ones it is risky, because several pods start together and each one would try to migrate. We discuss the safer alternatives in Chapter 10.

Everyday analogy

These patterns are the tasks on an airline ground crew’s list: check the runway is clear (wait for a dependency), load the passengers’ luggage (fetch data), fuel the plane (fix permissions and tune the environment), and attach the boarding stairs (copy tools). None of these are the flight itself, and all must be complete before take-off.

!
Watch out

The more jobs you put in init containers, the slower every pod starts, and the harder it is to scale quickly under sudden load. Each init step is a delay that every single new pod pays.

8Init Containers and Native Sidecars

Recent versions of Kubernetes stretched the idea of init containers to solve a different old problem: helper containers that must start before the app and keep running beside it.

What is a sidecar?

A sidecar is a helper container that runs alongside the main application for its whole life. Common examples are a log shipper that forwards logs, a proxy that handles secure connections, and a small agent that refreshes credentials. The name comes from the sidecar of a motorcycle: an extra seat attached to the main vehicle.

For years, sidecars were just ordinary containers in the same pod, with all the problems of ordinary containers: they start at the same time as the app, with no promise that the proxy is ready before the app makes its first call, and on shutdown they may stop in any order, so a log shipper could vanish before the app finished writing its final logs. Batch jobs had a special headache: a sidecar that never exits stopped the job from ever finishing.

The native sidecar idea

Kubernetes solved this by letting an init container carry a special setting that makes it restart-always. Such an init container starts in the normal init order, but, unlike a classic init container, it does not have to finish. Kubernetes considers it “started” once it is running, and the next init container, or the app containers, can proceed. It then keeps running for the whole life of the pod, and can even have health probes.

On shutdown, the order is reversed: app containers stop first, and sidecars stop afterwards, in reverse start order. The log shipper can therefore send the last logs, and a batch job can finish, because the sidecar is shut down once the main work is done. This feature became stable in recent Kubernetes releases, so check which version your cluster runs before relying on it.

Kind of containerWhen it startsHow long it livesProbes allowed?
Classic init containerBefore the app, in orderUntil it finishesNo
Native sidecar (restart-always init container)Before the app, in orderFor the whole pod life, stopped after the appYes
Ordinary containerTogether with the other app containersFor the whole pod lifeYes
Everyday analogy

Imagine a hospital operating theatre. The set-up nurse prepares instruments and leaves (a classic init container). The anaesthetist arrives before the surgeon, stays throughout, and is the last to leave (a native sidecar). The surgeon (the app) begins only when the anaesthetist is ready, and finishes before the anaesthetist steps away.

Use it for

Log shippers

They must be ready when the app starts writing logs and must outlive it to send the final lines.

Use it for

Network proxies

A proxy must be running before the app makes its first outside call, or those first calls will fail.

Use it for

Credential refreshers

A small agent keeps a short-lived token fresh in a shared folder for the whole life of the pod.

Not for

One-time setup

Anything that should run once and finish is still a job for a classic init container.

i
Tip

Ask two questions to choose. Does it need to finish before the app starts? Then it is a classic init container. Does it need to run beside the app the whole time, but start before it? Then it is a native sidecar.

9Security of Init Containers

Init containers run before your application, often with extra power, and often reach out to the network. That makes them useful, and also an attractive target.

Power

Give the least privilege

An init container that fixes file ownership needs only the power to change ownership, not the power to do everything. Avoid the fully privileged mode whenever a smaller permission will do.

Rules

Init containers are covered by pod security rules

Cluster security policies that limit privileged or root containers apply to init containers too. An init container that demands special power may be refused in a strict namespace.

Supply

Trust the image

An init container runs before your app, with access to the pod’s shared folders and network. A poisoned image is dangerous. Use images from trusted registries, pin exact versions, and scan them.

Downloads

Verify what you fetch

If the init container downloads files from outside, check a checksum or signature before trusting them. Otherwise a tampered download reaches your application quietly.

Secrets

Limit who sees credentials

Give a secret only to the container that needs it. Remember that files written to a shared folder are visible to every container that mounts it.

Network

Restrict outbound access

Where possible, allow the init container to reach only the specific places it needs. An unrestricted download step is an open door for data theft.

The shared identity

All containers in a pod share the pod’s service account, which is the identity the pod uses when it talks to the cluster itself. An init container therefore has the same cluster permissions as the app. If an init container is compromised, everything that identity may do is at risk. Keep the pod’s identity narrow.

Who can add an init container?

Anyone who can edit a workload’s pod template can add an init container, and an init container is arbitrary code that runs first, before your application’s own defences. Treat permission to edit pod templates as a powerful permission. Many organisations use admission policies to require that init containers come only from approved registries and never request privileged mode.

Everyday analogy

The night cleaning crew in an office has keys to every room. They are usually honest and essential, but that is exactly why building managers check who they hire, give them keys to only the floors they clean, and watch the entrance camera. An init container is the cleaning crew of your pod.

A short security checklist

Least privilege for each init container. No fully privileged mode unless there is no alternative. Trusted, pinned and scanned images. Verified downloads. Secrets given only where needed. Narrow outbound network access. No secrets in command arguments or logs. Approval rules for who may change pod templates.

!
Read this twice

Command arguments and environment values are visible to anyone who can read the pod definition. Never write passwords or tokens directly there. Pass them through proper secret mechanisms, and never print them in the init container’s logs.

10Choosing the Right Tool

Init containers are one of several ways to get work done around a pod. Choosing well avoids slow starts, fragile systems and surprising failures.

flowchart TD
  A["I have a task to do around my app"] --> B{"Must it finish before the app starts?"}
  B -->|"No"| C{"Must it run beside the app all the time?"}
  C -->|"Yes"| D["Ordinary container or native sidecar"]
  C -->|"No"| E["Separate job or scheduled task"]
  B -->|"Yes"| F{"Is it needed for every single pod start?"}
  F -->|"Yes"| G["Init container"]
  F -->|"No, only once per release"| H["Separate job that runs once per release"]
    
Figure 6. A simple decision path for choosing between init containers and other tools.

Reading the decision path

Start at the top with your task. The first question is about timing: must the task finish before the application begins? If not, it does not belong in an init container. Some tasks need to run beside the app for its whole life, which points to an ordinary container or a native sidecar. Others are separate concerns that can run on their own, such as a nightly report, and should be a separate job.

If the task must finish first, ask how often. A step needed by every pod, such as fetching this pod’s certificate, is a perfect init container. A step needed only once per release, such as changing the database layout, is better as a separate job that runs once per release, before the rollout, instead of being repeated by every pod that starts.

ToolRunsBest forWeak spot
Init containerAt every pod start, before the appPer-pod preparation and readiness gatesSlows every pod start
Native sidecarBefore the app and beside itProxies, log shippers, refreshersNeeds a recent cluster version
Ordinary extra containerTogether with the appSimple helpers without start-order needsNo start or stop ordering
Separate jobOnce, on demandMigrations and one-time tasks per releaseNeeds its own coordination
Scheduled taskOn a timetableReports, clean-ups, backupsNot tied to pod start
Retry logic in the appInside the app, alwaysSurviving dependencies that come and goRequires changing the app
Readiness probeContinuouslyDeciding when to send trafficDoes not block the app from starting

The case for putting resilience in the app

The wait-for-dependency init container is popular, but it has a limit. It checks the dependency only at start-up. If the database restarts tomorrow while the app is running, no init container will help. A well-built application handles missing dependencies itself, retrying connections with delays and reporting itself as not ready until they succeed. Where you can change the application, resilience inside the app is more robust. Init containers shine when you cannot change the app, or when the preparation is truly a separate concern.

Init containers versus readiness probes

People confuse these two. An init container runs first and blocks the app from starting. A readiness probe runs while the app is already running, and simply controls whether the pod receives traffic. If your worry is “do not send visitors until the app has warmed up”, that is a readiness probe. If your worry is “do not start the app until its files exist”, that is an init container.

Everyday analogy

Think of a restaurant. Setting the tables before opening is an init container. A waiter who stays on the floor all evening is a sidecar. The “open” sign that flips only when the kitchen is ready is a readiness probe. The monthly deep-clean is a scheduled job. All are useful, and each has its own moment.

i
Rule of thumb

Use an init container when the task is per pod, must finish first, and is a separate concern from the application code. If any of those three is missing, look at the other tools first.

11Performance and Startup Time

Every init container adds time to every pod start. That price is small for one pod and large when hundreds of pods must start quickly.

Where the time goes

Total start-up delay is the sum of several parts. First comes pulling each init image, if it is not already on the machine. Then each init container starts and runs its work, one after another. Only afterwards do the app containers begin their own image pulls and starts. Because init containers run in sequence, three steps of ten seconds each add thirty seconds before the app even begins.

1 by 1
Init containers run in strict sequence, so their times add up
Images
Pulling a large init image is often the slowest part
Per pod
The delay repeats for every new pod, including during scaling
Image

Keep init images small

A small image pulls quickly. Use minimal base images that contain only the tool the step needs.

Count

Use as few steps as possible

Merge tiny related tasks into one init container when they share an image and purpose, and split only when the tools or permissions differ.

Waiting

Poll quickly but politely

A check every one or two seconds notices readiness faster than every thirty seconds, without overloading the dependency.

Caching

Cache big downloads

If an init step downloads a large file, consider a shared cache volume or baking the file into an image so repeated starts do not re-download it.

Limits

Set sensible time limits

A step that could hang forever should give up with a clear error after a reasonable time, so failures show up quickly.

Placement

Move once-per-release work out

Anything that need not run for every pod is wasting time inside an init container.

Resource reservations and scheduling

Recall from Chapter 5 that a pod’s effective request is the larger of the biggest init request and the total of the app requests. A heavy init container, for example one that unpacks a large archive, can therefore make the whole pod harder to place on a busy machine, even though that memory is needed only briefly. Give init containers realistic, modest requests, and if a step needs a large burst, ask whether it should be a separate job instead.

Scaling under sudden load

When traffic spikes and an autoscaler adds pods, each new pod must go through its init steps before it can help. If init takes a minute, the extra capacity arrives a minute late. For workloads that must scale fast, keep init lean, pre-pull images onto machines where possible, and keep slow preparation out of the start-up path.

Everyday analogy

A pizzeria that must knead fresh dough for every single order will never keep up with a rush. One that prepares dough in advance can serve the crowd quickly. Init containers that redo heavy work for every pod are the dough kneaded to order.

!
Watch out

Measure before optimising. Look at the time between a pod being created and its app container starting. That gap is your init cost, and it often reveals one slow step that dominates all the others.

12Advantages, Disadvantages and Trade-offs

Every design choice buys something and costs something. Here is an honest ledger for init containers.

Advantage

Clean separation

Set-up logic lives in its own image, apart from the application, so each can change independently.

Advantage

Smaller, safer app images

Utilities and powerful tools stay out of the final application image, shrinking its attack surface.

Advantage

Guaranteed order

The app never sees a half-prepared world, because Kubernetes enforces the sequence.

Advantage

Temporary power

Elevated permissions exist only for the brief set-up step, not for the app’s whole life.

Advantage

Built-in retries

Failures are retried automatically with growing delays, with no extra code.

Advantage

Works with unmodifiable apps

Third-party images can be prepared without touching their code.

Disadvantage

Slower starts

Each step delays every pod, including new ones created by scaling.

Disadvantage

Start-only checks

They cannot react to dependencies that fail later while the app runs.

Disadvantage

Harder to debug

Pods stuck in init states hide the app, and the reason lives in the init container’s own logs.

Disadvantage

Rerun on recreation

Steps must be safe to repeat, which takes careful design.

Disadvantage

Tight coupling in one pod

A failing init step blocks the whole pod, and many pods of the same workload together.

Disadvantage

Limited features

Classic init containers have no probes or lifecycle hooks, which limits health reporting during long steps.

The trade-offs in plain words

The core trade-off is start-up speed against clean design. Init containers make your system tidier, safer and more predictable, and in exchange each pod takes longer to become useful. For most applications, a few seconds of start-up are a fair price. For applications that scale rapidly, the price matters and deserves measurement.

A second trade-off is start-time checks against run-time resilience. Waiting for a dependency at start-up feels reassuring, but it tempts teams to skip building real resilience into the application. The safest systems use both: an init step for genuine preparation, and application-level retries for dependencies that come and go.

A third trade-off is one bigger container against several small ones. Putting many tasks into one init container reduces overhead but mixes tools and permissions. Splitting them gives clarity and least privilege at the cost of extra image pulls and start-up steps. Choose based on whether the tasks need different tools or different powers.

Everyday analogy

A safety checklist before a flight makes aircraft far safer, at the cost of a few extra minutes at the gate. Nobody wants to skip it, but airlines still work hard to keep it short and smooth. Init containers are that checklist.

13Monitoring, Logging and Failure Handling

When a pod is stuck before its app even starts, you need to know where to look. This chapter is your troubleshooting map.

Reading the pod status

The status column of a pod listing is your first clue. It tells you which stage the pod is in, and the stage tells you where to look.

Status you seeWhat it meansWhere to look first
Init:0/2Zero of two init containers finished; the first is running or waitingThe first init container’s logs
Init:1/2The first finished; the second is running or waitingThe second init container’s logs
Init:ErrorAn init container exited with a failureIts logs and exit code
Init:CrashLoopBackOffAn init container keeps failing and Kubernetes is waiting longer between retriesLogs of the previous attempt, plus the cause of failure
Init:ImagePullBackOffThe init image cannot be downloadedImage name, tag, registry access
PodInitializingAll init containers finished; app containers are startingApp container events
PendingThe pod has not been placed on a machine yetScheduling events, resource requests

A calm troubleshooting routine

First, describe the pod. The events at the bottom read like a diary of what happened: image pulls, container starts, failures and back-offs. Second, read the logs of the specific init container by naming it, since a pod’s default logs show only app containers. Third, ask for the logs of the previous attempt, because a container that crashed and restarted has fresh logs that hide the failure. Fourth, check the exit code shown in the describe output: a code of one often means the script’s own error, while codes such as 137 hint at being killed for using too much memory.

Fifth, check the shared parts. Is the volume mounted where you think it is? Does the ownership allow writing? Is the network path to the dependency open, and does the name resolve? Sixth, compare the init container’s requests and limits with what it needs, because a step killed for memory looks like a mysterious crash.

Symptom

Stuck forever at Init:0/1

Usually a wait loop with no exit, a dependency that never comes, or a missing name. Check that the awaited service exists and its name is spelled right.

Symptom

Init:Error, quickly repeating

The step itself fails. The logs usually say why: a missing file, a refused connection, a permission error.

Symptom

ImagePullBackOff

Wrong image name or tag, or missing registry credentials. Fix the reference or the pull secret.

Symptom

App starts but files are missing

The init step wrote to a folder that the app does not mount, or to a path not on the shared volume.

Symptom

Pod stays Pending

Not an init problem yet. The scheduler cannot place the pod, perhaps because the effective request is too large.

Symptom

Works once, fails on restart

The step was not idempotent. It assumed a clean folder and broke when files already existed.

A worked troubleshooting example

Imagine a pod that shows Init:1/2 for ten minutes. The number tells you that the first init container finished, and the second one is the suspect. You describe the pod and see, in the events, that the second init container has started once and has not restarted, so it is running rather than crashing. That already narrows the cause: it is waiting for something. You read that container’s logs and find repeated lines saying it is waiting for a service named “payments-db” to answer. You check the cluster and discover that the service is called “payments-database”. A single spelling difference kept the pod waiting. Fixing the name in the pod definition and rolling it out solves the problem.

Notice the path of reasoning. The status gave the stage, the events gave the behaviour, the logs gave the cause, and a comparison with reality gave the fix. Nothing required guessing, and the application code was never involved. With practice, this routine takes only a few minutes, and it works for nearly every init problem you will meet.

Logging good init containers

Init containers are short-lived, and their logs are valuable evidence. Write clear, human-readable lines about what the step is checking, what it found, and why it is exiting. A line such as “waiting for the database, attempt 4 of 30” saves a stranger an hour of guessing. Never print secrets. Because logs of finished pods can disappear with the pod, send logs to a central logging system so you can investigate after the fact.

Monitoring at the fleet level

Track how many pods are in init states, how long pods spend initialising, and how often init containers restart. A sudden rise in time-to-start is an early warning that a dependency has become slow. Alerts on pods stuck in initialisation for longer than a sensible limit catch quiet failures that dashboards on running apps never see, since those pods never became apps at all.

Designing for failure

Assume every init step will fail sometimes, and design so that failure is safe and visible. Make steps idempotent so retries are harmless. Set time limits so a hopeless step ends with a clear error. Emit clear messages. Keep steps small, so a failure points to one precise cause. And decide in advance whether a failure should be retried forever, as with the default policy, or should mark the pod failed, as with a never-restart policy in a batch setting.

Everyday analogy

When a flight is delayed, the departure board says exactly why: crew late, weather, or technical check. Clear status messages make delays bearable. An init container that fails silently is a departure board that just says “delayed”, leaving everyone guessing.

i
Tip

Always name your init containers meaningfully, such as “wait-for-database” or “fetch-certificate”. The name appears in statuses, events and log commands, and a good name shortens every investigation.

14Design Patterns and Anti-patterns

A pattern is a proven way of solving a repeated problem. An anti-pattern is a tempting approach that keeps causing pain. Knowing both saves months of learning the hard way.

Patterns worth adopting

Pattern

One job per init container

Each init container does exactly one thing and is named for it. Failures point to a precise cause, and permissions can be tuned for each step.

Pattern

Shared folder hand-off

The init container writes results into a shared, temporary folder. The app reads them as ordinary files. The contract between them is simply a file path.

Pattern

Idempotent steps

Every step first checks whether its work is already done and skips it if so, so reruns after recreation are harmless.

Pattern

Bounded waiting

Wait loops have a maximum time and print a clear message on giving up, so a missing dependency shows as a clear failure rather than an endless wait.

Pattern

Tool-carrier images

A small dedicated image carries the tools the step needs, keeping the application image lean.

Pattern

Least-power set-up

The powerful step runs as an init container with narrow rights, and the application runs as an ordinary user afterwards.

Anti-patterns to avoid

Anti-pattern

The giant init container

One image with every tool, doing ten unrelated jobs. It is slow, hard to secure and hard to debug.

Anti-pattern

Endless waiting

A loop that never gives up leaves pods stuck for hours with no clear error.

Anti-pattern

Migrations in every pod

Ten pods starting together each try to change the database layout at once, causing conflicts and half-finished changes.

Anti-pattern

Init as the only resilience

Relying on start-up checks alone means the app is helpless when a dependency fails later.

Anti-pattern

Privileged by default

Running init steps as fully privileged because it “just works” hands attackers a powerful foothold.

Anti-pattern

Secrets in arguments

Passwords typed straight into container arguments are visible to anyone who can read the pod definition.

DECISION 01 · Where should database migrations run? Accepted
Context

A team deploys an application with ten replicas. Each new release changes the database layout. Running the migration inside each pod’s init container would make ten pods attempt the same change at the same moment.

Options considered

Run migrations in every pod’s init container. Run a single separate job before the rollout. Let the application migrate itself while holding a lock.

Decision

Run one separate job per release that completes before the new pods are rolled out. Keep init containers for per-pod tasks only, such as waiting for the database to accept connections.

Consequences

Releases gain one extra coordination step, but concurrent migration conflicts disappear and each pod starts quickly. Rollback planning must consider that the database layout changes once per release, not once per pod.

Everyday analogy

Repainting a building is done once by a specialist crew before tenants return, not by every tenant painting the shared lobby each morning. Per-tenant tasks, like unlocking your own door, belong to each tenant. Init containers are for the unlocking, not the repainting.

15Best Practices and Common Mistakes

This chapter gathers everything into checklists you can pin beside your desk.

Best practices

Design

Give each init container one clear job and a meaningful name. Make each step idempotent. Bound every wait with a time limit. Use a shared temporary volume to hand over results. Keep once-per-release work in separate jobs. Also build retry logic into the application itself.

Images

Use small images from trusted registries. Pin exact versions rather than a floating “latest” label so that every pod starts with identical tools. Scan images for known weaknesses and rebuild them regularly.

Security

Grant only the permissions each step needs. Avoid fully privileged mode. Keep secrets out of arguments and logs. Verify downloads. Restrict the pod’s service account to what it truly needs, and restrict who can edit pod templates.

Resources

Set realistic requests and limits on init containers. Remember that the largest init request can dominate the pod’s scheduling needs. Watch for steps killed for exceeding memory.

Operations

Write clear log messages. Ship logs to a central system. Alert on pods stuck initialising. Track time-to-start. Document what each init container does, why it exists and what it expects from its neighbours.

Common mistakes

MistakeWhy it hurtsBetter approach
Forgetting init containers rerunNon-repeatable steps break after a pod is recreatedMake each step safe to run again
Writing to a folder the app does not mountApp starts and finds nothingMount the same shared volume in both places
Wait loops with no limitPods hang without a visible errorAdd a time limit and a clear failure message
Using floating image labelsDifferent pods get different toolsPin exact versions
Expecting probes on classic init containersNot supported, so long steps look silentLog progress, or use a native sidecar where suitable
Changing init settings and expecting a live updateOnly the image field can change on a running podRoll out a new pod definition
Reading the wrong logsDefault log view skips init containersName the init container when reading logs
Giving a huge memory requestPod becomes hard to scheduleUse realistic requests or move heavy work to a job
Blaming the app when the pod is stuckThe app has not even startedCheck the init state first
i
Review habit

Whenever you see an init container in a review, ask three things: is this per pod, can it safely rerun, and does it have the least power it needs? Those three questions catch most problems.

16Real-World Usage Stories

These generic stories, based on common patterns rather than any specific company, show how init containers appear in everyday systems.

The online shop that started before its database

A small online shop’s web pods kept crashing after every cluster maintenance window. The cause was simple: the database took longer to come back than the web pods. The team added a small init container that waited, with a limit, for the database to accept connections. Crash loops during maintenance vanished, and the application code stayed untouched. Later they also added connection retries inside the application to survive brief database restarts during normal running.

The media site with fresh content

A publishing team served static pages from a lightweight web server. Content changed often, and rebuilding the server image for every article was slow. They used an init container that fetched the latest published content into a shared folder before the web server started. The web server image changed rarely, and content updates required just a pod restart.

The bank-style service with strict secrets

A service needed credentials held in a central vault. The team refused to give the application any vault knowledge. An init container authenticated to the vault, fetched only that service’s secrets, and wrote them to a memory-backed shared folder. The app read them as plain files. The vault client library never entered the application image, and the audit trail was simple.

The analytics platform with permission trouble

A data team attached persistent storage to a processing pod and found the app could not write, because the volume belonged to the administrator. Running the whole app as administrator was rejected by the security team. An init container with just the ownership-changing power fixed the folder, then exited. The app ran as an ordinary user, and the security team approved.

The machine-learning service with a huge model

Model files were several gigabytes, too big to bake into every image version. An init container downloaded the model from storage, verified its checksum and placed it in a shared folder. Start-up was slower, so the team later added a cache volume, and the delay dropped sharply on repeat starts. They also learned to alert on pods stuck initialising, since downloads occasionally stalled.

The service mesh that hides its init step

Teams using a service mesh often never write the network-rules init container that the mesh injects automatically into their pods. They meet it only when a pod shows a mysterious extra init step, or when a strict security policy refuses it because it needs network administration permission. Understanding init containers turns that mystery into a five-minute fix.

Everyday analogy

These stories are like the small print of a building’s daily opening routine: unlock doors, switch on lights, check the alarm, stock the till. Customers never notice the routine, and only notice when it is skipped. Init containers are your system’s opening routine.

Three worked scenarios: thinking like a designer

Stories are useful, but the real skill is deciding what to do with a fresh problem. Here are three short scenarios, each with the reasoning a careful designer would follow.

Scenario one: the application needs a generated settings file

An application reads a settings file at start-up, and the file must contain this pod’s own address and a value from a central settings service. Ask the three questions. Is it per pod? Yes, the address differs for every pod. Must it finish before the app starts? Yes, because the app reads the file immediately. Is it a separate concern from the application code? Yes, since the application should not know about the settings service. All three answers point to an init container. The design is simple: one init container, named for its purpose, mounts a shared temporary folder, fetches the value, fills in the template, and exits. The application mounts the same folder and reads the finished file. To make it safe on rerun, the init container overwrites the file completely instead of appending to it.

Scenario two: the report generator that needs fresh data every night

A team wants a nightly job that refreshes data before a reporting service serves it. The first idea is an init container that refreshes data whenever a pod starts. Test it against the questions. Is it per pod? No, the refresh happens once a night for the whole system. Would ten pods each refresh the same data? Yes, wastefully and possibly in conflict. The answer is a scheduled task that runs once per night, with the reporting pods simply reading the result. The lesson is that an init container is the wrong tool whenever the work is about the system as a whole rather than about one pod.

Scenario three: a secure proxy that must outlive the application

An application must send all its outside traffic through a secure proxy, and the proxy must be running before the first request and must keep running until the last response. A classic init container cannot do this, because it must finish before the app starts, which would stop the proxy. A native sidecar fits well, since it starts before the app, stays alongside it, and stops after it. If the cluster version does not support native sidecars, the team falls back to an ordinary extra container, and adds retry logic to the app for the first few seconds, accepting the weaker ordering.

A short mental checklist for new designs

Before adding any init container, pause and walk through a short list. State the job in one sentence. If you cannot, the container is doing too much. Decide what it needs to read and what it must write, and confirm the shared folder both sides will use. Decide what happens when it runs twice. Decide what happens when it runs for an hour, and set a limit. Decide which permissions it needs, and remove everything else. Decide what a stranger would see in its logs at three in the morning. Finally, estimate the time it adds to every pod start and ask whether that price is acceptable. Ten minutes on this checklist prevents most of the problems described in this article.

Init containers are best when they are boring: one small job, done quickly, safe to repeat, and clearly logged.

17Frequently Asked Questions

Quick answers to the questions beginners ask most often.

Q1What is an init container in one sentence?
A helper container that runs and finishes before the main application containers start, used to prepare the pod.
Q2Can a pod have more than one init container?
Yes. They run one at a time in the order listed, and each must succeed before the next begins.
Q3Do init containers run at the same time as the app?
No. Classic init containers finish before any app container starts. Only native sidecars, which are a special kind, keep running beside the app.
Q4What happens if an init container fails?
By default Kubernetes retries it, waiting longer between attempts, and the app does not start until it succeeds. If the pod’s restart policy is never, the pod is marked failed instead.
Q5Do init containers run again when the app container restarts?
No. If only an app container crashes and restarts, init containers do not rerun. They rerun when the pod’s sandbox is recreated or a new pod is made, so steps should be safe to repeat.
Q6Do init containers share files with the app?
Only through shared volumes that both mount. Their own container file systems are separate.
Q7Can init containers use different images from the app?
Yes, and that is one of their main benefits. Tools stay out of the application image.
Q8Can I add health probes to an init container?
Not to classic init containers. Native sidecars, which are restart-always init containers, may have probes.
Q9Can I change an init container of a running pod?
Only its image field can be changed on a live pod, and doing so restarts the pod. Other changes need a new pod definition, usually rolled out through the workload that owns the pod.
Q10How do init containers affect resource requests?
The pod’s effective request is the larger of the biggest single init request and the sum of all app container requests, per resource type.
Q11Where do I see init container logs?
Read the logs while naming the init container. The default view shows only app containers.
Q12Should I run database migrations in an init container?
Usually not for systems with several replicas. A separate job per release avoids concurrent migration attempts.
Q13Do init containers slow down pod startup?
Yes, by the total time of all steps plus image pulls. Keep steps few, small and quick.
Q14Is a native sidecar the same as an init container?
It is a special init container with a restart-always setting. It starts in init order but keeps running for the pod’s life. Check that your cluster version supports it.
Q15Can an init container be privileged?
Yes if policy allows, but grant only the narrow permission needed and avoid full privileged mode where possible.
Q16What is the difference between an init container and a readiness probe?
An init container runs first and blocks the app from starting. A readiness probe runs while the app is running and controls whether it receives traffic.
Q17Can init containers talk to the network?
Yes. They share the pod’s network address and can reach other services just like app containers, subject to network policies. They are often used to check whether a neighbouring service is reachable.
Q18Is it safe to run the same init container twice?
It should be. Kubernetes may rerun init containers whenever the pod’s sandbox is recreated, so each step must check what is already done and skip repeated work. Steps that fail when files already exist are the classic cause of trouble after a machine restart.
Q19How many init containers is too many?
There is no fixed limit, but every one adds start-up time and another image to pull. If you have more than three or four, ask whether some can be merged, moved into a separate job, or handled by the application itself.
Q20Why does my pod say Init:CrashLoopBackOff?
An init container keeps failing and Kubernetes is waiting longer between retries. Read that init container’s logs, including the previous attempt, check its exit code, and confirm that the volumes, network paths and permissions it needs are in place.
Q21Can two init containers run in parallel?
Not as classic init containers. They always run one after another in the listed order. If you need parallel preparation, do it inside one init container or use separate jobs.
Q22Do init containers count toward the pod’s limits?
Yes, in the sense of scheduling. Their requests are considered by the scheduler using the maximum-versus-sum rule, though they do not run at the same time as the app containers.

This post was written without live web research. Please verify version-sensitive details, such as native sidecar support, against the official documentation for your cluster version.

18Summary and Key Takeaways

Let us close the loop, returning to our theatre crew from the start of this article.

Just as a stage crew sets the scene before the curtain rises and only then lets the actors begin, init containers prepare a pod before its application starts. They run in order, each one finishing before the next begins. They can carry different tools, hold different permissions and produce results in shared folders. They retry when they fail, and they rerun when a pod is recreated, which is why they must be safe to repeat.

You met the problem they solve, the ordering headache of starting an app before its world is ready. You saw their core concepts, their architecture, and how the kubelet drives them through a decision loop. You followed data through the lifecycle, met the usage patterns, compared them with native sidecars, and learned how to secure, size, monitor and troubleshoot them. You also saw where they do not belong.

Takeaway 1

Before, in order, to completion

Init containers run before app containers, one at a time, each to success.

Takeaway 2

Shared volumes are the hand-off

Files passed through shared volumes are how init steps deliver their results.

Takeaway 3

Design for reruns

Idempotent steps make recreation and retries safe.

Takeaway 4

Least privilege

Give each step only the power it needs, and keep secrets out of arguments and logs.

Takeaway 5

Mind the start-up cost

Every step delays every pod, so keep them few, small and bounded.

Takeaway 6

Use the right tool

Per-pod, must-finish-first, separate-concern tasks fit init containers. Others fit jobs, sidecars or the app itself.

Version drift and things to verify

Kubernetes changes steadily, and details around init containers have shifted over the years. Native sidecar support arrived much later than classic init containers, and the exact behaviour of features such as probes on sidecars, shutdown ordering and resource accounting has been refined across releases. Because this article was written without live web research, treat version-specific statements as a starting point. Before relying on a feature in production, read the official documentation for your cluster’s exact version, try the behaviour in a test namespace, and note the version in your team’s own documentation so that future upgrades prompt a re-check.

It also helps to know your managed platform. Cloud providers sometimes run older or newer versions than you expect, and some add their own admission rules that change what init containers may do, such as blocking privileged mode or requiring images from an approved registry. A five-minute check of your platform’s rules can save an afternoon of confusing errors.

A small glossary to keep nearby

Term

Pod

The smallest deployable unit in Kubernetes: one or more containers sharing a network address and storage.

Term

Init container

A helper container that runs to completion, in order, before the application containers start.

Term

Native sidecar

An init container set to restart always, so it starts early and keeps running beside the application.

Term

Idempotent

Safe to run more than once, because repeated runs leave the same final result.

Term

Kubelet

The agent on each machine that starts and watches the containers of pods placed there.

Term

Shared volume

A storage area mounted by several containers in the same pod, used to hand over files.

Term

Back-off

A growing pause between retries, so a failing step does not hammer the system.

Term

Effective request

The resource amount the scheduler reserves for a pod, considering both init and application containers.

i
Your next step

Look at one real pod in your own cluster. Find any init containers, read their names, and ask whether each is per pod, repeatable and least-privileged. That small review teaches more than any article.