TT Lab
Get started
Learn Learning paths Courses

Istio Service Mesh

When the proxy leaves the pod: ambient components and its two layers

Continue in TT Lab

Goal

You render the ambient profile and compare its components with sidecar mode, and check how to choose the data plane by namespace label and what the analyzer catches when the two labels are layered. You generate a waypoint manifest, read its fields, and see for yourself why the application fails in this cluster. Finally you build a checklist that counts namespaces by mode.

Why it matters

Ambient is a design that detaches the proxy from the Pod and moves it to the node. What you gain is clear — with no proxy per Pod, resources drop, and you can add workloads to or remove them from the mesh without restarting them. In exchange, features split into two layers. What the node's L4 proxy alone can do goes only as far as mutual authentication and L4 authorization, and work that needs to see request contents, such as HTTP path-based routing or per-method authorization, requires a separate L7 proxy called a waypoint. So a migration plan starts not from "let us turn off the sidecar" but from "which of the features this namespace uses need L7?" And since the two modes coexist in one cluster during the switchover, counting in a machine-readable way which namespace is in which mode is far more trustworthy than human memory.

Steps

  1. Create /root/ist-ambient and save the output of istioctl manifest generate --set profile=ambient to /root/ist-ambient/ambient.yaml. Extract all the Deployments and DaemonSets in it and write them in /root/ist-ambient/ambient-workloads.tsv as <kind>|<이름> (the placeholders are the kind and the name), sorted.
  2. Also render the default profile and save it to /root/ist-ambient/default.yaml, compare the ServiceAccount names of the two renders, and write them in /root/ist-ambient/sa-diff.tsv as sorted lines of only-ambient\t<이름> and only-default\t<이름> (the placeholder is the name; do not write the ones present on both sides).
  3. From the step 1 render, extract only data.mesh of the ConfigMap named istio and save it to /root/ist-ambient/ambient-mesh.yaml. And write all the ConfigMap names contained in that render, one per line and sorted, in /root/ist-ambient/ambient-configmaps.txt.
  4. Create two namespaces — put the label istio-injection=enabled on shop-sidecar and the label istio.io/dataplane-mode=ambient on shop-ambient. And read the labels of the two namespaces from the cluster and write them in /root/ist-ambient/ns-labels.tsv as <네임스페이스>\t<라벨키>=<값> (the placeholders are the namespace, the label key, and the value), sorted.
  5. Create the namespace shop-both and put both istio-injection=enabled and istio.io/dataplane-mode=ambient on it. Save the output of istioctl analyze -n shop-both -o json to /root/ist-ambient/analyze-conflict.json — IST0123 must appear. Then remove only the sidecar-side label and save the output of the same command to /root/ist-ambient/analyze-fixed.json. This time there must be no IST0123.
  6. Save the output of istioctl waypoint generate --for service -n shop-ambient --name shop-waypoint to /root/ist-ambient/waypoint.yaml. And write the four things you read from it in /root/ist-ambient/waypoint-fields.tsv as four lines: apiVersion, gatewayClassName, port, and protocol.
  7. Also generate once with --for workload and save it to /root/ist-ambient/waypoint-workload.yaml, and write the value of metadata.labels."istio.io/waypoint-for" of the two files in /root/ist-ambient/waypoint-for.tsv as two lines, service and workload, in the format <파일이름>\t<값> (the placeholders are the file name and the value; use the name shop-waypoint-wl). Then try actually applying the waypoint.yaml from step 6 and save the result to /root/ist-ambient/waypoint-apply.txt.
  8. Create /root/ist-ambient/mode-report.sh so that it prints all the cluster's namespaces as <네임스페이스>\t<모드> (the placeholders are the namespace and the mode) in name order only to standard output — the mode is conflict if both labels are present, ambient if only the ambient label is present, sidecar if istio-injection is enabled, and none otherwise. Save the output to /root/ist-ambient/mode-report.txt.

Notes

Count what the ambient profile brings up

Create /root/ist-ambient and save the output of istioctl manifest generate --set profile=ambient to /root/ist-ambient/ambient.yaml. Extract all the Deployments and DaemonSets in it and write them in /root/ist-ambient/ambient-workloads.tsv as <kind>|<이름> (the placeholders are the kind and the name), sorted.

Instead of putting a proxy in every Pod, ambient lays down two things on each node — the side that intercepts traffic and the side that acts as the L4 proxy. Both come out as DaemonSets. When extracting from the render, you can filter by kind, as in yq -N e 'select(.kind=="DaemonSet") | .metadata.name'.

Compared with sidecar mode, two identities are added and one is removed

Also render the default profile and save it to /root/ist-ambient/default.yaml, compare the ServiceAccount names of the two renders, and write them in /root/ist-ambient/sa-diff.tsv as sorted lines of only-ambient\t<이름> and only-default\t<이름> (the placeholder is the name; do not write the ones present on both sides).

When components are added or removed, the service accounts those components use move with them. If you sort each of the two lists and compare with comm, the names present on only one side come out. It also shows here that ambient has no gateway by default.

What more is turned on in ambient's mesh configuration

From the step 1 render, extract only data.mesh of the ConfigMap named istio and save it to /root/ist-ambient/ambient-mesh.yaml. And write all the ConfigMap names contained in that render, one per line and sorted, in /root/ist-ambient/ambient-configmaps.txt.

In ambient, traffic between Pods passes through the node's L4 proxy and is delivered over a tunnel. The value that turns on that tunnel is in the proxy metadata, so look under defaultConfig.proxyMetadata. In the ConfigMap list there is one more than in the sidecar profile.

One line of namespace label chooses the data plane

Create two namespaces — put the label istio-injection=enabled on shop-sidecar and the label istio.io/dataplane-mode=ambient on shop-ambient. And read the labels of the two namespaces from the cluster and write them in /root/ist-ambient/ns-labels.tsv as <네임스페이스>\t<라벨키>=<값> (the placeholders are the namespace, the label key, and the value), sorted.

The two modes use different label keys. The sidecar side is the label the injection webhook looks at, and the ambient side is the label the node's CNI looks at. If you pipe kubectl get ns -o json into jq, you can pull the labels out as they are.

If you put both labels on, the behavior is undefined

Create the namespace shop-both and put both istio-injection=enabled and istio.io/dataplane-mode=ambient on it. Save the output of istioctl analyze -n shop-both -o json to /root/ist-ambient/analyze-conflict.json — IST0123 must appear. Then remove only the sidecar-side label and save the output of the same command to /root/ist-ambient/analyze-fixed.json. This time there must be no IST0123.

The two labels are read by different components — one by the injection webhook and one by the node's CNI. If both apply, it is undecided which data plane that Pod uses. To remove a label, attach a minus sign after the key.

If you need L7, put up a waypoint separately

Save the output of istioctl waypoint generate --for service -n shop-ambient --name shop-waypoint to /root/ist-ambient/waypoint.yaml. And write the four things you read from it in /root/ist-ambient/waypoint-fields.tsv as four lines: apiVersion, gatewayClassName, port, and protocol.

A waypoint is expressed not as an Istio-specific object but as a Gateway of the Gateway API — which gateway class it is is what makes it a waypoint. The listener's port and protocol are the tunnel that ambient uses between Pods, as it is.

What is the waypoint for, and why is it not applied here

Also generate once with --for workload and save it to /root/ist-ambient/waypoint-workload.yaml, and write the value of metadata.labels."istio.io/waypoint-for" of the two files in /root/ist-ambient/waypoint-for.tsv as two lines, service and workload, in the format <파일이름>\t<값> (the placeholders are the file name and the value; use the name shop-waypoint-wl). Then try actually applying the waypoint.yaml from step 6 and save the result to /root/ist-ambient/waypoint-apply.txt.

A waypoint can be put in front of a service or in front of a workload — one label tells that scope. The application does not succeed in this cluster. The error message itself tells you why.

A checklist that counts the cluster's namespaces by mode

Create /root/ist-ambient/mode-report.sh so that it prints all the cluster's namespaces as <네임스페이스>\t<모드> (the placeholders are the namespace and the mode) in name order only to standard output — the mode is conflict if both labels are present, ambient if only the ambient label is present, sidecar if istio-injection is enabled, and none otherwise. Save the output to /root/ist-ambient/mode-report.txt.

Get all the labels with a single kubectl get ns -o json and sort them out with jq. Label keys mix dots and slashes, so in jq it is safer to pull them out with brackets and quotes. The value of istio-injection can also be disabled, so you must count only the ones that are turned on.