Init containers run first; native sidecars live alongside
Init containers are run before any app container, one at a time, each to successful completion. If one fails, the kubelet retries it according to the Pod's restart policy and the app never starts. They suit blocking until a dependency is reachable, running a one-time migration, or fetching configuration. Because they are separate containers, they can use tools you do not want in the app image.
The classic problem with sidecars was lifecycle. A log shipper or service-mesh proxy placed in the main containers list had no ordering guarantee, so the app could start before the proxy was ready, and in a Job the sidecar never exited, leaving the Pod running forever after the work finished. Native sidecars fix this: a container declared in initContainers with restartPolicy Always starts before the app, is kept running, is excluded from the Pod's completion condition, and is shut down after the main containers finish.
Check the version: sidecar containers were introduced behind a feature gate in 1.28, enabled by default as beta in 1.29 and became generally available in a later release. Our source tutorial states stable in 1.29, which is stale; confirm against the Kubernetes release notes for your cluster.
Gotcha: an init container that waits forever for a dependency that never appears leaves Pods stuck in Init:0/1. Add a timeout, and look at kubectl describe pod and the init container's logs.