Istio Ambient Mode
Signadot works with Istio ambient mode. This page covers two setups that route sandbox requests from ambient workloads: a single ambient namespace, and a cluster that mixes ambient and sidecar namespaces.
In ambient mode, pods run without a sidecar. Each node runs ztunnel, a proxy that carries traffic at layer 4 and never reads HTTP headers. Layer 7 routing happens only in a waypoint, a proxy attached to the destination Service or its namespace.
Signadot's sandbox routes are layer 7 rules: they match the routing key in the
baggage or tracestate header. For requests from ambient workloads, a
waypoint applies them.
How Routing Works in Ambient Mode
With sidecars, the caller's Envoy proxy applies routes before the request leaves the pod (see Istio). In ambient mode, the caller has no Envoy. ztunnel sends the request to the destination's waypoint, and the waypoint reads the routing key and picks the sandbox fork or the baseline.
Service A Pod (ambient)
│
Main Container
│
↓
Node ztunnel (L4 only, no header checks)
│
↓
Service B Waypoint ───────────────┐ ┌─────────────┐
(Routing decision here) ⚡ ├───▶│ Sandbox │
│ │ Fork B │
│ │ (match) │
│ └─────────────┘
│ ┌─────────────┐
└───▶│ Baseline │
│ Service B │
│ (default) │
└─────────────┘
If Service B has no waypoint, ztunnel sends the request straight to a baseline pod. Nothing reads the routing key, and the request reaches the baseline. This is also true when Service B's own pods run sidecars.
Requirements
-
Istio in ambient mode, with the Gateway API CRDs installed. Waypoints are Gateway API resources.
-
A waypoint for every forked Service that ambient workloads call. Attach it to the Service's namespace, or to the Service itself, with the
istio.io/use-waypointlabel. -
A route object for every forked Service, either:
- an HTTPRoute whose
parentRefsincludes the Service. This requiresistio.gatewayAPI.enabled: truein the operator's Helm values. - a VirtualService whose
hostsincludes the Service's hostname.
Unless the baseline runs the DevMesh sidecar, a forked Service without a route object leaves the sandbox Not Ready with reason
RoutingNotReady. - an HTTPRoute whose
For new ambient setups, use HTTPRoutes. Istio considers VirtualService support in ambient mode alpha, and doesn't support mixing VirtualServices with Gateway API routes. Existing VirtualServices still work once the Service has a waypoint.
Set Up Routing in an Ambient Namespace
The steps below use a Service my-svc on port 8080 in the ambient namespace
my-ns.
1. Install the operator with Istio and Gateway API routing
# values.yaml
istio:
enabled: true
gatewayAPI:
enabled: true
Leave istio.operator.podLabels at its default. Operator pods then run with
an Istio sidecar, so requests the operator sends to your services, such as
preview URL requests, route the same way as other sidecar callers. See
Operator pods in ambient mode.
2. Add a waypoint to the namespace
istioctl waypoint apply -n my-ns --enroll-namespace
This creates a waypoint named waypoint in my-ns and labels the namespace
with istio.io/use-waypoint=waypoint, so every Service in the namespace uses
it. If the command times out before it labels the namespace, add the label
yourself:
kubectl label namespace my-ns istio.io/use-waypoint=waypoint
3. Give the Service a route
- HTTPRoute (recommended)
- VirtualService
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: my-svc
namespace: my-ns
spec:
parentRefs:
- group: ""
kind: Service
name: my-svc
port: 8080
rules:
- backendRefs:
- name: my-svc
port: 8080
A parentRefs entry of kind Service attaches the route to service-to-service
traffic for my-svc. An HTTPRoute attached only to a Gateway covers requests
that enter through that Gateway, not requests between services. See
Gateway API,
including its limitations.
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: my-svc
namespace: my-ns
spec:
hosts:
- my-svc.my-ns.svc.cluster.local
http:
- name: default
route:
- destination:
host: my-svc.my-ns.svc.cluster.local
4. Create a sandbox and send a request from an ambient pod
name: my-sandbox
spec:
cluster: my-cluster
forks:
- forkOf:
kind: Deployment
namespace: my-ns
name: my-svc
customizations:
env:
- name: VERSION
value: sandbox
signadot sandbox apply -f my-sandbox.yaml
ROUTING_KEY=$(signadot sandbox get my-sandbox -o json | jq -r .routingKey)
kubectl -n my-ns exec deploy/client -- \
curl -s -H "baggage: sd-routing-key=$ROUTING_KEY" \
http://my-svc.my-ns.svc.cluster.local:8080/
Replace deploy/client with any workload in an ambient namespace that has
curl. The response
should come from the sandbox fork. Without the baggage header, the same
request reaches the baseline.
Clusters with Sidecar and Ambient Namespaces
Clusters that are moving to ambient often have both. Take an orders Service
in the sidecar namespace shop, called by sidecar workloads and by a
checkout workload in an ambient namespace. While orders has no waypoint:
- Requests from sidecar workloads that carry the sandbox's routing key reach the fork.
- The same requests from
checkoutreach the baseline.checkouthas no sidecar, andordershas no waypoint, so nothing applies the route.
Add a waypoint to shop and attach it to orders:
istioctl waypoint apply -n shop
kubectl label service orders -n shop istio.io/use-waypoint=waypoint
Requests from checkout then reach the fork, and requests from sidecar
workloads still do. To cover every Service in shop at once, label the
namespace instead of the Service.
The pattern for mixed clusters: give a Service a waypoint if any ambient workload calls it, whether its own pods run with sidecars or in ambient mode.
Check that a Service Has a Waypoint
Sandbox status doesn't check for waypoints, so a sandbox can show Ready while requests from ambient workloads reach the baseline. To check a forked Service, list the Services ztunnel knows about in its namespace:
istioctl ztunnel-config services --service-namespace shop
NAMESPACE SERVICE NAME SERVICE VIP WAYPOINT ENDPOINTS
shop orders 10.96.146.194 waypoint 1/1
shop payments 10.96.125.182 None 1/1
A WAYPOINT value of None means requests from ambient workloads to that
Service skip sandbox routing. In this example, a sandbox that forks payments
only receives requests from sidecar callers.
Operator Pods in Ambient Mode
The operator chart puts operator pods (such as the ones serving preview URLs and
signadot local connect traffic) on the mesh with an Istio sidecar. That is the
recommended setting for ambient clusters, including clusters with both sidecar
and ambient namespaces.
You can move operator pods to ambient mode with istio.operator.podLabels (see
Istio Custom Labels).
If you do, those pods become ambient callers. Requests they send, such as
preview URL requests and requests from local workloads, then reach a sandbox
fork only when the destination Service has a waypoint.