February 2, 2018·4 min read·engineeringistiosidecarsadmission

Istio 0.5 moves sidecar injection into Kubernetes admission

Istio 0.5 replaces initializer-based automatic injection with a mutating webhook. The implementation shows how a mesh becomes part of pod admission while supporting more selective adoption.

Adding a mesh proxy to every application manifest makes adoption depend on repeated edits to workload definitions. Automatic injection moves that work into the cluster's pod admission process. The Istio 0.5 announcement on February 2 switches automatic injection to Kubernetes mutating webhooks and ends support for the alpha initializer mechanism. Kubernetes 1.9 or later is required for this automatic path.

The release also previews incremental installation of selected Istio components. Pilot with ingress is one example of a smaller installation. I welcome that direction because the operational cost of a mesh depends on which responsibilities it assumes. Adopting routing does not automatically establish a need to deploy every policy and telemetry component at the same time.

The injector returns a patch to the API server

The 0.5.0 webhook implementation receives an AdmissionReview containing the pod object. It decodes that object and evaluates whether injection is required under its configured policy. When policy excludes the pod, it returns an allowed response without adding the proxy. Automatic injection therefore includes a decision about participation before constructing any mutation.

When injection is required, the webhook combines its sidecar template with pod metadata, the pod specification and mesh configuration. That produces an injection specification and recorded injection status. The server then builds a JSON patch and returns it with an allowed admission response. Kubernetes applies the mutation as part of handling the object through admission.

This separates the application manifest from the admitted pod representation. The user can submit an ordinary workload definition while the admission path adds containers and volumes. An operator examining what will run must consequently inspect the resulting pod as well as the original input. The sidecar is part of the pod's actual specification even if its author never wrote that container into the source manifest.

The implementation also copies the request UID into the response. That connects the returned mutation to the admission request which produced it. The response identifies its patch type as JSON Patch, rather than leaving the caller to infer how the bytes should be interpreted. Request identity and patch format are explicit parts of the webhook exchange.

Repeated injection needs to identify previous additions

The patch builder handles previously injected resources before adding the new injection specification. It removes init containers, ordinary containers and volumes identified by earlier injection status. The code uses resource names to select entries for removal. That prevents the mutation logic from blindly appending another copy of every injected component.

Array removal proceeds in reverse order. JSON Patch operations apply sequentially, so removing a lower index first would renumber subsequent entries. The implementation's ordering preserves the meaning of the remaining removal indices. This is a small implementation detail with a direct effect on which containers survive the mutation.

Addition distinguishes an absent list from an existing one. For an empty target list, the first operation supplies an array at the list's path. Subsequent additions use the append position. The same pattern applies to volumes. Injection has to construct a valid patch for pods with different existing specifications, not merely for one example manifest.

Annotations receive similar treatment. The code creates an annotation map when none exists and otherwise adds or replaces individual values. It escapes annotation keys for their use in JSON Pointer paths. That is necessary because a Kubernetes annotation key and a JSON patch path use different syntax rules, even though both appear as strings in the implementation.

Injection status provides a migration mechanism

The webhook reads an annotation containing the previous injection status. When it can decode a status with nonempty resource lists, it uses those lists to identify prior additions. This records the injector's contribution separately from the application's own containers and volumes. A later mutation can use that record to update the injected portion.

For older pods without usable status, the implementation falls back to legacy names. These include istio-proxy and istio-init, along with known volume names. The fallback supports migration from earlier injection behavior. It also demonstrates why names become operationally relevant once an automated tool uses them to distinguish its own resources.

I find this explicit accounting useful, but it adds a responsibility to admission. A sidecar template change is a change to what the cluster injects. The operator needs to understand which configuration the injector loaded and which additions it recorded. The proxy's container image is only part of the resulting pod mutation.

The webhook has its own configuration lifecycle

The server loads its mesh configuration and injection template from files, then watches their parent directories. A source comment explains that watching the directory catches symlink updates from ConfigMap volumes. On relevant filesystem events, it reloads configuration, computes the template version and replaces its active settings under a lock.

That makes configuration delivery part of the automatic injection system. Updating a ConfigMap volume is different from updating every application manifest, but the injector still has to notice and load the new files. Errors during reloading are logged. An operator investigating unexpected injection needs to check the active injector configuration and its logs, in addition to the pod's annotations.

The webhook serves its injection endpoint over TLS using a configured certificate and key. This is a connection between the API server and the admission service, separate from mesh traffic between application proxies. The source explicitly leaves mutual TLS disabled for that webhook server. Automatic sidecar injection should therefore not be confused with applying mesh mutual TLS to the admission exchange. Its handler requires JSON input and decodes the admission object before generating the response patch for the API server.

The release's incremental deployment preview and webhook switch both affect adoption, but at different stages. Component selection controls which mesh services are installed. Admission policy controls which pods receive the injected resources. The implementation then returns the precise container, volume and annotation changes needed for each included pod.