Should a platform standard put a minimal init in every image, or require each application to be its container's first process?
answer
- two costs, not one
- a standard beats a convention
- conventions regress silently
- the init must pass the status through
- verify in the pipeline, not in review
basics
~20 sNeither is free. A mandated minimal init makes every image survive wrappers and stray children, at the cost of an extra process and an exit-status contract. Requiring applications to hold position one is cheaper but is a discipline that regresses in images nobody reviewed.
solid answer
~50 sThe trade is uniformity against simplicity. A minimal init at position one in every image buys behaviour you can reason about estate-wide: stop requests are forwarded, finished children are collected, and an image that grows a wrapper or a second process does not silently break. It costs one more process everywhere, an exit-status pass-through that must be exact or supervisors read the wrong outcome, a dependency in every build, and a component that can mask an application that never handled a stop request at all. The alternative — a convention that the application is the first process and installs a handler — is simpler and has nothing to pass through, but it is per-team discipline with no enforcement point, and it breaks the day an image needs two processes. Most estates mandate the init *and* keep the handler discipline, then verify both in the build pipeline rather than in review.
go deeper
The point to take away is that the container's first position has two jobs, and a team has to decide deliberately what fills it rather than letting whatever the image happens to start end up there.
Be able to state both costs of a mandated init: an extra component in every image, and an exit-status pass-through that must be exact or every supervisor reads the wrong outcome.
Show that you enforce rather than document. A stop smoke test in the build pipeline catches a non-forwarding wrapper and a missing handler before either reaches an environment.
Own the framing: this is about where a guarantee lives and who is accountable when it lapses. Weigh a central component in every image against a per-team discipline that fails silently and shows up as lost work.
## What each option is actually buying Both options are answers to the same question: who guarantees that the container's first position does its two jobs — forwarding a stop request to whatever is really doing the work, and collecting the processes that end beneath it. They differ in *where* the guarantee lives. - **A mandated minimal init** puts the guarantee in the image template, once, for everyone. It holds regardless of what the application is, what language it is written in, whether it shells out, or whether anyone reviewed it. - **A convention that the application holds position one** puts the guarantee in each team's code and each team's attention. It is simpler when it holds, and it is invisible when it stops holding. That is the whole argument, and it is a governance argument more than a technical one. The mechanism is not in dispute; who is accountable for it is. ## What a mandated init costs The cost is real and worth stating honestly, because teams that are told it is free stop believing the rest of the standard: - **One more process in every container.** Tiny, but it is a component in every image's supply chain, with its own updates and its own audit surface. - **An exit-status contract.** The init must pass the main child's exit status outward as the container's own, exactly. An init that reports its own success instead tells every supervisor that a crashed workload ended cleanly, which is a worse defect than the one it was added to fix. - **A masking effect.** With forwarding guaranteed, an application that never installed a handler now receives a request it still ignores — and the stop still ends in a forced kill. The init fixed delivery, not handling, and a team that believes otherwise stops looking. - **A build dependency.** Every image now needs it present and current, which is one more thing a base-image change can quietly remove. ## Where the convention quietly breaks - The day an image legitimately needs two processes, position one has to become something that manages both, and the convention has no answer. - The day someone adds a setup step by wrapping the start command, the wrapper takes position one and nothing notices. - The day a team inherits a service from another team, the handler is nobody's memory. - Nothing fails loudly at any of those moments; the regression shows up months later as work lost during an ordinary deploy. ## The two side by side | | Mandated minimal init | Application holds position one | |---|---|---| | Where the guarantee lives | The image template, centrally owned | Each team's code and discipline | | Survives a wrapper being added | Yes | No | | Survives a second process being added | Yes | No | | Exit status | Must be passed through correctly | Naturally correct | | Extra components in every image | One | None | | Failure mode when it lapses | Visible in a build check | Silent until an incident | ## Making either one stick Whichever you choose, the decision is only as good as its enforcement point, and review is not one: 1. **Put it in the shared image template**, so the default state of a new service is the compliant one and non-compliance takes effort. 2. **Add a smoke test to the build pipeline**: start the freshly built image, let it reach a working state, send it a stop request, and assert both that the application logged the entry to its shutdown path and that the container ended well inside the window. That single test catches a non-forwarding wrapper, a missing handler and a swallowed request, before any of them reach an environment. 3. **Sweep the estate periodically** for images whose first position is something other than what the standard says, and treat drift as a finding rather than as a conversation. The honest summary is that most estates end up doing both: the init as insurance against images nobody thought about, the handler discipline because the init cannot shut down an application for it, and a pipeline check because neither survives on goodwill.
- One image genuinely needs two processes. Does that settle the argument for the whole estate?It settles it for that image — something at position one must forward and collect, so an init goes in. It says little about the estate, because a standard exists for the images nobody thought about, not for the one that raised the question. Decide the estate rule on how many images you can actually audit.
- If every image carries a minimal init, can teams stop worrying about their own shutdown handler?No, and believing so is the standard's main hazard. An init guarantees the request is delivered; it cannot finish in-flight work, close connections or exit on the application's behalf. Without a handler the workload receives a request it ignores and is still cut off by the forced kill.
- What single cheap check catches most violations of either rule?A stop smoke test in the build pipeline: start the built image, send it a stop request, and assert that the application logged the entry to its shutdown path and that the container ended well inside the window. It fails on a non-forwarding wrapper, on a missing handler, and on an application that swallows the request.
saying these in an interview costs you the question
- Claims a minimal init removes the need for a shutdown handler
- Treats the extra process as free because it is small
- Assumes every image starts exactly one process to begin with
- Lets the init report its own status instead of the child's
- Relies on code review to keep every team's image compliant