Updating ambient mode components

This page describes how to update the Istio control plane, the Istio CNI plugin, and the ZTunnel proxy in ambient mode. All three components use the InPlace update strategy and must be updated in this exact order. Waypoint proxies are rolled out automatically after the control plane update; see Updating waypoint proxies for the related verification steps.

Installing ambient mode with a specific version

You can install the Istio control plane, the Istio CNI plugin, and the ZTunnel proxy in ambient mode with an explicitly pinned version, which lets you exercise the update procedure afterwards.

NOTE

This section exists so that you can walk through the update process from a known starting version. Skip it if the cluster already runs Istio in ambient mode. The installation steps mirror Installing Istio ambient mode, except that each resource pins spec.version to an older release.

Procedure

  1. Create the istio-cni, istio-system, and ztunnel namespaces, each labeled with istio-discovery=enabled so that the control plane discovers them:

    kubectl create namespace istio-cni
    kubectl create namespace istio-system
    kubectl create namespace ztunnel
    kubectl label namespace istio-cni istio-system ztunnel istio-discovery=enabled
  2. Create the IstioCNI resource with the starting version:

    cat <<EOF | kubectl apply -f -
    apiVersion: sailoperator.io/v1
    kind: IstioCNI
    metadata:
      name: default
    spec:
      version: v1.28.6
      namespace: istio-cni
      profile: ambient
      values:
        cni:
          cniConfDir: /etc/cni/multus/net.d
          excludeNamespaces:
            - istio-cni
            - kube-system
    EOF
    1. Pinning spec.version defines the version that the update procedure starts from.
  3. Wait for the Istio CNI pods to become ready:

    kubectl wait --for=condition=Ready istiocnis/default --timeout=3m
  4. Create the Istio resource with the same starting version:

    cat <<EOF | kubectl apply -f -
    apiVersion: sailoperator.io/v1
    kind: Istio
    metadata:
      name: default
    spec:
      version: v1.28.6
      namespace: istio-system
      profile: ambient
      updateStrategy:
        type: InPlace
      values:
        pilot:
          trustedZtunnelNamespace: ztunnel
        meshConfig:
          discoverySelectors:
            - matchLabels:
                istio-discovery: enabled
    EOF
    1. InPlace is the default strategy, so this field is optional; it is shown here to make the strategy explicit. Ambient mode supports no other strategy.
  5. Wait for the Istio control plane to become ready:

    kubectl wait --for=condition=Ready istios/default --timeout=3m
  6. Create the ZTunnel resource with the same starting version:

    cat <<EOF | kubectl apply -f -
    apiVersion: sailoperator.io/v1
    kind: ZTunnel
    metadata:
      name: default
    spec:
      version: v1.28.6
      namespace: ztunnel
      values:
        ztunnel:
          resources:
            requests:
              cpu: 200m
              memory: 512Mi
            limits:
              cpu: 2000m
              memory: 1024Mi
    EOF
    1. Unlike the installation guide, this example sets spec.version so that the ZTunnel update step below has an older version to move away from.
  7. Wait for the ZTunnel pods to become ready:

    kubectl wait --for=condition=Ready ztunnel/default --timeout=3m
  8. Set up the application workloads in the cluster. For instance, you can deploy the Bookinfo sample application into the bookinfo namespace. The following steps are a condensed version of Deploying the Bookinfo application in ambient mode.

    a. Create the bookinfo namespace and add the istio-discovery=enabled label so that the control plane discovers it:

    kubectl create namespace bookinfo
    kubectl label namespace bookinfo istio-discovery=enabled

    b. Deploy the Bookinfo application:

    kubectl apply -n bookinfo -f https://raw.githubusercontent.com/alauda-mesh/istio/refs/heads/istio-1.30/samples/bookinfo/platform/kube/bookinfo.yaml

    c. Deploy the per-version services of the Bookinfo application:

    kubectl apply -n bookinfo -f https://raw.githubusercontent.com/alauda-mesh/istio/refs/heads/istio-1.30/samples/bookinfo/platform/kube/bookinfo-versions.yaml

    d. Enroll all workloads of the namespace in the ambient mesh:

    kubectl label namespace bookinfo istio.io/dataplane-mode=ambient

Updating the components

Prerequisites

  • You are logged in to the Alauda Container Platform web console as cluster-admin.
  • You have installed the Alauda Container Platform Networking for Multus plugin, and kube-ovn must be v4.1.5 or later.
  • You have upgraded the Alauda Service Mesh Operator to version 2.1.2 or later, and the new target version is available in the Operator. For more information, see Understanding Operator updates and channels.
  • Istio is deployed in ambient mode. In this example, the Istio, IstioCNI, and ZTunnel resources are all named default.
  • The cluster runs a Kubernetes version that the target Istio version supports. Istio 1.30 supports Kubernetes 1.32 to 1.36, and Istio 1.28 supports Kubernetes 1.30 to 1.34, so a cluster on Kubernetes 1.30 or 1.31 must be upgraded before you update Istio to 1.30.
  • You have installed istioctl on your local machine.
  • Application workloads are enrolled in the ambient mesh. In this example, the Bookinfo application runs in the bookinfo namespace; see Deploying the Bookinfo application in ambient mode.

Updating the Istio control plane

  1. Change the version in the Istio resource. For example, to update to Istio 1.30.3, set the spec.version field to v1.30.3 by running the following command:

    kubectl patch istio default --type='merge' -p '{"spec":{"version":"v1.30.3"}}'

    The Operator replaces the running control plane with the new version. ZTunnel and any waypoint proxies reconnect to the new istiod instance automatically; the application pods keep running and do not need a restart.

  2. Wait for the control plane to become ready:

    kubectl wait --for=condition=Ready istios/default --timeout=3m
  3. Confirm that the control plane reports the new version:

    kubectl get istio default

    Example output

    NAME      NAMESPACE      PROFILE   REVISIONS   READY   IN USE   ACTIVE REVISION   STATUS    VERSION   AGE
    default   istio-system   ambient   1           1       0        default           Healthy   v1.30.3   12m

Updating the Istio CNI plugin

Update the Istio CNI plugin only after the control plane update has completed, because a CNI plugin at version 1.x supports a control plane at version 1.x or 1.x+1.

  1. Set the spec.version field of the IstioCNI resource to the same version as the control plane:

    kubectl patch istiocni default --type='merge' -p '{"spec":{"version":"v1.30.3"}}'
  2. Watch the istio-cni-node DaemonSet roll out:

    kubectl rollout status daemonset/istio-cni-node -n istio-cni
  3. Wait for the IstioCNI resource to report readiness:

    kubectl wait --for=condition=Ready istiocnis/default --timeout=5m
  4. Confirm that the CNI plugin reports the new version:

    kubectl get istiocni default

    Example output

    NAME      NAMESPACE   PROFILE   READY   STATUS    VERSION   AGE
    default   istio-cni   ambient   True    Healthy   v1.30.3   15m
NOTE

Updating the Istio CNI plugin to 1.30 changes two defaults for ambient workloads:

  • DNS capture is enabled. The Istio CNI reconciles the in-pod redirection rules of already enrolled workloads when it starts, so you do not have to restart them.
  • The Istio CNI agent now honors values.cni.excludeNamespaces. Enrolled workloads in an excluded namespace are removed from the mesh.

For details about the IstioCNI resource and its update behavior, see The Istio CNI update process.

Updating the ZTunnel proxy

Update the ZTunnel proxy last, after both the control plane and the CNI plugin run the new version.

WARNING

Replacing a ZTunnel pod can reset long-lived TCP connections on that node. If your workloads hold long-lived connections, review The ZTunnel update process before this step and choose an appropriate mitigation.

  1. Set the spec.version field of the ZTunnel resource to the same version as the control plane:

    kubectl patch ztunnel default --type='merge' -p '{"spec":{"version":"v1.30.3"}}'
  2. Watch the ZTunnel DaemonSet roll out:

    kubectl rollout status daemonset/ztunnel -n ztunnel
    NOTE

    The DaemonSet replaces ZTunnel pods node by node to keep mesh connectivity available, so the rollout can take several minutes on larger clusters.

  3. Wait for the ZTunnel resource to report readiness:

    kubectl wait --for=condition=Ready ztunnel/default --timeout=10m
  4. Confirm that the ZTunnel proxy reports the new version:

    kubectl get ztunnel default

    Example output

    NAME      NAMESPACE   READY   STATUS    VERSION   AGE
    default   ztunnel     True    Healthy   v1.30.3   18m
  5. Inspect the per-node ZTunnel pods:

    kubectl get pods -n ztunnel -o wide

    Example output

    NAME            READY   STATUS    RESTARTS   AGE     IP           NODE
    ztunnel-2b6pb   1/1     Running   0          2m11s   10.3.0.202   192.168.136.57
    ztunnel-2s7m7   1/1     Running   0          2m3s    10.3.0.203   192.168.143.119
    ztunnel-95g2q   1/1     Running   0          115s    10.3.0.204   192.168.141.97

Verifying ambient workloads

After all components run the new version, confirm that the workloads still participate in the mesh.

  1. Check that the application pods are running:

    kubectl get pods -n bookinfo

    Example output

    NAME                              READY   STATUS    RESTARTS   AGE
    details-v1-657cf9fcfb-r75r4       1/1     Running   0          25m
    productpage-v1-667466dfd9-k6ddq   1/1     Running   0          25m
    ratings-v1-5bdc95577b-s7n8w       1/1     Running   0          25m
    reviews-v1-8468d47c78-m7fww       1/1     Running   0          25m
    reviews-v2-869977f6f8-jklhm       1/1     Running   0          25m
    reviews-v3-7bcdd7dd74-zdc87       1/1     Running   0          25m
  2. Confirm that ZTunnel still proxies the workloads. Pods enrolled in the ambient mesh report the HBONE protocol:

    istioctl -n ztunnel ztunnel-config workloads

    Example output

    NAMESPACE    POD NAME                        ADDRESS    NODE            WAYPOINT PROTOCOL
    bookinfo     details-v1-657cf9fcfb-r75r4     10.3.0.192 192.168.141.97  None     HBONE
    bookinfo     productpage-v1-667466dfd9-k6ddq 10.3.0.197 192.168.141.97  None     HBONE
    bookinfo     ratings-v1-5bdc95577b-s7n8w     10.3.0.193 192.168.143.119 None     HBONE
    bookinfo     reviews-v1-8468d47c78-m7fww     10.3.0.194 192.168.143.119 None     HBONE
    bookinfo     reviews-v2-869977f6f8-jklhm     10.3.0.195 192.168.143.119 None     HBONE
    bookinfo     reviews-v3-7bcdd7dd74-zdc87     10.3.0.196 192.168.141.97  None     HBONE
  3. Test connectivity through the mesh by calling a service from another pod:

    kubectl exec "$(kubectl get pod -l app=ratings -n bookinfo \
      -o jsonpath='{.items[0].metadata.name}')" \
      -c ratings -n bookinfo \
      -- curl -sS productpage:9080/productpage | grep -o "<title>.*</title>"

    Example output

    <title>Simple Bookstore App</title>

If you deployed waypoint proxies, additionally verify them as described in Updating waypoint proxies.

Updating the Kiali tracing configuration

Starting with Istio 1.30, waypoint proxies report every trace span under the waypoint's own service name (for example waypoint.bookinfo) instead of the destination service name that Istio 1.28 used. This is an intentional upstream change that aligns Istio with the OpenTelemetry specification, where service.name identifies the producer of the span.

After updating to Istio 1.30 or later, this change has two consequences for tracing:

  • Kiali shows no traces for ambient workloads unless external_services.tracing.use_waypoint_name is set to true in the Kiali resource. With this setting, Kiali looks up traces by the waypoint name and uses the span tags (such as istio.destination_canonical_service) to attribute spans to the correct workloads. The setting has no effect on sidecar-mode workloads.
  • Traces recorded before the update stay under the old per-service names (for example productpage.bookinfo.svc.cluster.local), while new traces appear under waypoint.<namespace>. This discontinuity in trace queries is expected. In the Jaeger UI, select the waypoint.<namespace> service and narrow the results with the Operation dropdown or a tag filter such as istio.destination_canonical_service=<service>.

If Alauda Build of Kiali is installed with tracing integration (see Integrating distributed tracing platform with Alauda Build of Kiali), enable the setting:

  1. Patch the Kiali resource:

    kubectl -n istio-system patch kiali kiali --type=merge \
      -p '{"spec":{"external_services":{"tracing":{"use_waypoint_name":true}}}}'

    Example output

    kiali.kiali.io/kiali patched
  2. Wait for the Kiali Operator to reconcile the configuration and roll out the Kiali deployment:

    kubectl -n istio-system wait --for=condition=Successful kiali/kiali --timeout=3m
    kubectl -n istio-system rollout status deployment/kiali --timeout=3m
  3. In the Kiali UI, open the Traces tab of a workload in an ambient namespace and confirm that traces are displayed again.

Removing update resources from a development environment

After you finish verifying the update procedure in a development environment, remove the sample application and the mesh components to release the resources:

# Remove the Bookinfo namespace from the ambient data plane and delete it
kubectl label namespace bookinfo istio.io/dataplane-mode-
kubectl delete namespace bookinfo
# Remove the mesh components and their namespaces
kubectl delete istio/default istiocni/default ztunnel/default
kubectl delete ns/istio-system ns/istio-cni ns/ztunnel