From cfee24c3637680f016104ac684f78d2ffd690916 Mon Sep 17 00:00:00 2001 From: Alejandro Pedraza Date: Wed, 3 Jun 2026 17:34:00 -0500 Subject: [PATCH 1/2] Update edge docs for native sidecars enabled by default in Linkerd 2.20 As of Linkerd 2.20 the proxy is injected by default as a native sidecar container (an init container with `restartPolicy: Always`) instead of a regular container. Update the edge docs accordingly: - features/native-sidecars.md: state the new default and replace the "Enabling" section with instructions for disabling the mode, via the `config.linkerd.io/proxy-enable-native-sidecar: false` annotation at the namespace or workload level, or globally via the Helm value `proxy.nativeSidecar: false` - features/proxy-injection.md, reference/architecture.md: mention the proxy is now injected as a native sidecar by default - features/cni.md, tasks/grafana.md: scope the initContainer networking limitation (and its workarounds) to the case where native sidecars have been disabled, since init containers now have network access by default - tasks/graceful-shutdown.md: meshed Jobs and Cronjobs now complete without extra configuration; scope the hanging-pod issue and the manual /shutdown workaround to the non-native-sidecar case. Drop the `--wait-before-seconds` option and the "Slow Updating Clients" section, which are no longer relevant with native sidecars - tasks/adding-your-service.md: fix the mesh verification command to look for the proxy under `spec.initContainers` instead of `spec.containers` --- linkerd.io/content/2-edge/features/cni.md | 15 +++- .../2-edge/features/native-sidecars.md | 14 +++- .../2-edge/features/proxy-injection.md | 5 +- .../content/2-edge/reference/architecture.md | 10 ++- .../2-edge/tasks/adding-your-service.md | 13 +++- .../content/2-edge/tasks/graceful-shutdown.md | 76 ++++--------------- linkerd.io/content/2-edge/tasks/grafana.md | 13 ++-- 7 files changed, 63 insertions(+), 83 deletions(-) diff --git a/linkerd.io/content/2-edge/features/cni.md b/linkerd.io/content/2-edge/features/cni.md index 5dd3845009..b383e3c45e 100644 --- a/linkerd.io/content/2-edge/features/cni.md +++ b/linkerd.io/content/2-edge/features/cni.md @@ -110,10 +110,17 @@ The most important flags are: ### Allowing initContainer networking When using the Linkerd CNI plugin the required `iptables` rules are in effect -before the pod is scheduled. Also, the `linkerd-proxy` is not started until -after all `initContainers` have completed. This means no `initContainer` will -have network access because its packets will be caught by `iptables` and the -`linkerd-proxy` will not yet be available. +before the pod is scheduled. As of Linkerd 2.20, the proxy runs by default as +a [native sidecar container](native-sidecars/), starting before the +application's `initContainers`, so those containers have network access and no +extra configuration is needed. + +However, if you have +[disabled native sidecars](native-sidecars/#disabling-native-sidecars-in-linkerd), +the `linkerd-proxy` is not started until after all `initContainers` have +completed. This means no `initContainer` will have network access because its +packets will be caught by `iptables` and the `linkerd-proxy` will not yet be +available. It is possible to bypass these `iptables` rules by running the `initContainer` as the UID of the proxy (by default `2102`). Processes run as this UID are diff --git a/linkerd.io/content/2-edge/features/native-sidecars.md b/linkerd.io/content/2-edge/features/native-sidecars.md index 53de6ee79f..28e8aea252 100644 --- a/linkerd.io/content/2-edge/features/native-sidecars.md +++ b/linkerd.io/content/2-edge/features/native-sidecars.md @@ -18,8 +18,14 @@ sidecar containers in Kubernetes, including: 2. There are a variety of startup race conditions with meshed pods when init containers also need network access. -## Enabling native sidecars in Linkerd +As of Linkerd 2.20, native sidecars are enabled by default: the proxy is +injected as an init container with a `restartPolicy` of `Always`, rather than +as a regular container. -Native sidecars can be enabled by setting -`config.beta.linkerd.io/proxy-enable-native-sidecar` annotation at the level of -individual namespaces or workloads, or by setting it globally at install time. +## Disabling native sidecars in Linkerd + +If for any reason you want to disable this mode and have the proxy be injected +alongside regular containers, set the +`config.linkerd.io/proxy-enable-native-sidecar: false` annotation at the +namespace or workload level, or disable the mode globally by setting the Helm +chart value `proxy.nativeSidecar: false`. diff --git a/linkerd.io/content/2-edge/features/proxy-injection.md b/linkerd.io/content/2-edge/features/proxy-injection.md index db9422ec6f..3d0d730a36 100644 --- a/linkerd.io/content/2-edge/features/proxy-injection.md +++ b/linkerd.io/content/2-edge/features/proxy-injection.md @@ -36,7 +36,10 @@ For each pod, two containers are injected: that configures `iptables` to automatically forward all incoming and outgoing TCP traffic through the proxy. (Note that this container is not injected if the [Linkerd CNI Plugin](cni/) has been enabled.) -1. `linkerd-proxy`, the Linkerd data plane proxy itself. +1. `linkerd-proxy`, the Linkerd data plane proxy itself. As of Linkerd 2.20, + the proxy is injected by default as a + [native sidecar container](native-sidecars/), i.e. as an init container with + a `restartPolicy` of `Always`, rather than as a regular container. Note that simply adding the annotation to a resource with pre-existing pods will not automatically inject those pods. You will need to update the pods (e.g. with diff --git a/linkerd.io/content/2-edge/reference/architecture.md b/linkerd.io/content/2-edge/reference/architecture.md index 8dc18491ef..3b4fab06a8 100644 --- a/linkerd.io/content/2-edge/reference/architecture.md +++ b/linkerd.io/content/2-edge/reference/architecture.md @@ -60,10 +60,12 @@ containers to the pod, along with the relevant start-time configuration. ## Data plane The Linkerd data plane comprises ultralight _micro-proxies_ which are deployed -as sidecar containers inside application pods. These proxies transparently -intercept TCP connections to and from each pod, thanks to iptables rules put in -place by the [linkerd-init](#linkerd-init-container) (or, alternatively, by -Linkerd's [CNI plugin](../features/cni/)). +as sidecar containers inside application pods. As of Linkerd 2.20, the proxy +is deployed by default as a +[native sidecar container](../features/native-sidecars/). These proxies +transparently intercept TCP connections to and from each pod, thanks to +iptables rules put in place by the [linkerd-init](#linkerd-init-container) +(or, alternatively, by Linkerd's [CNI plugin](../features/cni/)). ### Proxy diff --git a/linkerd.io/content/2-edge/tasks/adding-your-service.md b/linkerd.io/content/2-edge/tasks/adding-your-service.md index 80797b0aea..65d2adb97f 100644 --- a/linkerd.io/content/2-edge/tasks/adding-your-service.md +++ b/linkerd.io/content/2-edge/tasks/adding-your-service.md @@ -62,18 +62,25 @@ kubectl get -n NAMESPACE deploy -o yaml | linkerd inject - | kubectl apply -f - To verify that your services have been added to the mesh, you can query Kubernetes for the list of containers in the pods and ensure that the proxy is -listed: +listed. As of Linkerd 2.20, the proxy runs by default as a +[native sidecar container](../features/native-sidecars/), so it appears among +the pod's init containers: ```bash -kubectl -n NAMESPACE get po -o jsonpath='{.items[0].spec.containers[*].name}' +kubectl -n NAMESPACE get po -o jsonpath='{.items[0].spec.initContainers[*].name}' ``` If everything was successful, you'll see `linkerd-proxy` in the output, e.g.: ```bash -linkerd-proxy CONTAINER +linkerd-init linkerd-proxy ``` +If you have +[disabled native sidecars](../features/native-sidecars/#disabling-native-sidecars-in-linkerd), +the proxy runs as a regular container instead, and will show up in +`{.items[0].spec.containers[*].name}`. + ## Handling MySQL, SMTP, and other non-HTTP protocols Linkerd's [protocol detection](../features/protocol-detection/) works by looking diff --git a/linkerd.io/content/2-edge/tasks/graceful-shutdown.md b/linkerd.io/content/2-edge/tasks/graceful-shutdown.md index bdc0809e43..753e4f0e45 100644 --- a/linkerd.io/content/2-edge/tasks/graceful-shutdown.md +++ b/linkerd.io/content/2-edge/tasks/graceful-shutdown.md @@ -66,12 +66,6 @@ signal. Linkerd offers a few options to configure pods and containers to gracefully shutdown. -- `--wait-before-seconds`: can be used as an install value (either through the - CLI or through Helm), or alternatively, through a - [configuration annotation](../reference/proxy-configuration/). This will add a - `preStop` hook to the proxy container to delay its handling of the TERM - signal. This will only work when the conditions described above are satisfied - (i.e container runtime sends the TERM signal) - `config.linkerd.io/shutdown-grace-period`: is an annotation that can be used on workloads to configure the graceful shutdown time for the _proxy_. If the period elapses before the proxy has had a chance to gracefully shut itself @@ -92,68 +86,26 @@ shutdown. shutdown, typically the entrypoint for containers need to be changed to linkerd-await. -Depending on the usecase, one option (or utility) might be preferred over the -other. To aid with some common cases, suggestions are given below on what to do -when confronted with slow updating clients and with job resources that will not -complete. - -## Slow Updating Clients - -Before Kubernetes terminates a pod, it first removes that pod from the endpoints -resource of any services that pod is a member of. This means that clients of -that service should stop sending traffic to the pod before it is terminated. -However, certain clients can be slow to receive the endpoints update and may -attempt to send requests to the terminating pod after that pod's proxy has -already received the TERM signal and begun graceful shutdown. Those requests -will fail. - -To mitigate this, use the `--wait-before-exit-seconds` flag with -`linkerd inject` to delay the Linkerd proxy's handling of the TERM signal for a -given number of seconds using a `preStop` hook. This delay gives slow clients -additional time to receive the endpoints update before beginning graceful -shutdown. To achieve max benefit from the option, the main container should have -its own `preStop` hook with the sleep command inside which has a smaller period -than is set for the proxy sidecar. And none of them must be bigger than -`terminationGracePeriodSeconds` configured for the entire pod. - -For example, - -```yaml -# application container -lifecycle: - preStop: - exec: - command: - - /bin/bash - - -c - - sleep 20 - -# for entire pod -terminationGracePeriodSeconds: 160 -``` - ## Graceful shutdown of Job and Cronjob Resources Pods which are part of Job or Cronjob resources will run until all of the -containers in the pod complete. However, the Linkerd proxy container runs -continuously until it receives a TERM signal. Since Kubernetes does not give the -proxy a means to know when the Cronjob has completed, by default, Job and -Cronjob pods which have been meshed will continue to run even once the main -container has completed. You can address this either by running Linkerd as a -native sidecar or by manually shutting down the proxy. - -### Native Sidecar - -If you use the `--set proxy.nativeSidecar=true` flag when installing Linkerd, -the Linkerd proxy will run as a -[sidecar container](https://kubernetes.io/docs/concepts/workloads/pods/sidecar-containers/) -and will automatically shutdown when the main containers in the pod terminate. -Native sidecars were added in Kubernetes v1.28 and are available by default in -Kubernetes v1.29. +containers in the pod complete. Since Linkerd 2.20 the proxy runs by default as +a [native sidecar container](../features/native-sidecars/), which automatically +shuts down when the main containers in the pod terminate, so meshed Jobs and +Cronjobs complete without any extra configuration. + +This is only an issue if you have [disabled native +sidecars](../features/native-sidecars/#disabling-native-sidecars-in-linkerd), +which is no longer the default. In that case the proxy runs as a regular +container that runs continuously until it receives a TERM signal, and since +Kubernetes does not give the proxy a means to know when the Job has completed, +meshed Job and Cronjob pods will continue to run even once the main container +has completed. You can address this by manually shutting down the proxy. ### Manual shutdown -Alternatively, you can issue a POST to the `/shutdown` endpoint on the proxy +If native sidecars are disabled, you can issue a POST to the `/shutdown` +endpoint on the proxy once the application completes (e.g. via `curl -X POST http://localhost:4191/shutdown`). This will terminate the proxy gracefully and allow the Job or Cronjob to complete. These shutdown requests diff --git a/linkerd.io/content/2-edge/tasks/grafana.md b/linkerd.io/content/2-edge/tasks/grafana.md index b37b01af71..37cb3d5cfa 100644 --- a/linkerd.io/content/2-edge/tasks/grafana.md +++ b/linkerd.io/content/2-edge/tasks/grafana.md @@ -58,11 +58,14 @@ instructions on how to easily import the same charts published on {{< note >}} Grafana's official Helm chart uses an initContainer to download Linkerd's -configuration and dashboards. If you use the CNI plugin, when you add grafana's -pod into the mesh its initContainer will run before the proxy is started and the -traffic cannot flow. You should either avoid meshing grafana's pod, skip -outbound port 443 via `config.linkerd.io/skip-outbound-ports: "443"` annotation -or run the container with the proxy's UID. See +configuration and dashboards. If you use the CNI plugin and have +[disabled native sidecars](../features/native-sidecars/#disabling-native-sidecars-in-linkerd) +(which are enabled by default as of Linkerd 2.20), when you add grafana's pod +into the mesh its initContainer will run before the proxy is started and the +traffic cannot flow. In that case you should either avoid meshing grafana's +pod, skip outbound port 443 via the +`config.linkerd.io/skip-outbound-ports: "443"` annotation, or run the container +with the proxy's UID. See [Allowing initContainer networking](../features/cni/#allowing-initcontainer-networking) {{< /note >}} From b8d907fed4baba5a03c986d60450cc08c3cc91f9 Mon Sep 17 00:00:00 2001 From: Alejandro Pedraza Date: Mon, 15 Jun 2026 12:25:13 -0500 Subject: [PATCH 2/2] @raykroeker's feedback --- linkerd.io/content/2-edge/tasks/graceful-shutdown.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/linkerd.io/content/2-edge/tasks/graceful-shutdown.md b/linkerd.io/content/2-edge/tasks/graceful-shutdown.md index 753e4f0e45..d51b9122fb 100644 --- a/linkerd.io/content/2-edge/tasks/graceful-shutdown.md +++ b/linkerd.io/content/2-edge/tasks/graceful-shutdown.md @@ -100,7 +100,9 @@ which is no longer the default. In that case the proxy runs as a regular container that runs continuously until it receives a TERM signal, and since Kubernetes does not give the proxy a means to know when the Job has completed, meshed Job and Cronjob pods will continue to run even once the main container -has completed. You can address this by manually shutting down the proxy. +has completed. You can address this by manually shutting down the proxy, after +the application container completes. This triggers a graceful shutdown allowing +meshed Job and Cronjob pods to complete. ### Manual shutdown