> For the complete documentation index, see [llms.txt](https://academy.cegedim.cloud/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://academy.cegedim.cloud/compute/containers-k8s/k8s-features/gateway-api/gateway-api-istio.md).

# Istio

Getting started with Istio on cegedim.cloud — sidecar and ambient mesh modes

Istio supports Gateway API as its primary ingress and traffic management model. It can be used as the sole ingress stack (chosen at cluster creation) or installed additionally on clusters using NGF or Traefik.

This guide covers both operating modes: **sidecar** and **ambient**. Use the comparison table below to choose the right mode for your workload.

## Sidecar mode vs Ambient mode

|                                      | Sidecar                                                         | Ambient                                                    |
| ------------------------------------ | --------------------------------------------------------------- | ---------------------------------------------------------- |
| Proxy location                       | Injected as a container **inside** each pod                     | Runs as a **node-level** ztunnel, outside pods             |
| Enrollment                           | `istio-injection=enabled` label on namespace, pods must restart | `istio.io/dataplane-mode=ambient` label, no restart needed |
| L7 traffic management                | Built-in — sidecar handles it directly                          | Requires a **waypoint proxy**                              |
| Resource overhead                    | Per-pod CPU/memory for each Envoy sidecar                       | Shared ztunnel per node                                    |
| `VirtualService` / `DestinationRule` | Native                                                          | Via waypoint only                                          |
| Gateway API CRDs required            | No                                                              | Yes                                                        |

## What the platform provides

You do not need to install or configure anything at the cluster level. The following are deployed and managed by the platform team:

| Component            | Namespace       | Role                            | Mode         |
| -------------------- | --------------- | ------------------------------- | ------------ |
| Istiod               | `istio-system`  | Control plane                   | Both         |
| istio-ingressgateway | `istio-ingress` | North-south ingress entry point | Both         |
| Istio CNI            | `istio-system`  | Ambient pod enrollment          | Ambient only |
| ztunnel              | `istio-system`  | L4 mTLS / node-level proxy      | Ambient only |

Each cegedim.cloud cluster is fronted by an **F5 BigIP** load balancer that handles wildcard DNS (`*.{{ cluster-name }}.ccs.cegedim.cloud`), TLS termination, and L4 forwarding to the `istio-ingressgateway` pods. Replace `{{ cluster-name }}` with your actual cluster name (e.g. `prod-paris`, `staging-lyon`) in all examples below.

***

## Sidecar Mode

In sidecar mode, an Envoy proxy container is injected alongside each of your application pods. It handles mTLS, observability, and L7 traffic management directly — no additional waypoint proxy is needed.

### Step 1 — Observability addons (optional)

Deploy Prometheus and Kiali for metrics and topology visualization:

```bash
kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.30/samples/addons/prometheus.yaml
kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.30/samples/addons/kiali.yaml
```

Expose Kiali via the platform ingress gateway:

```bash
cat <<EOF | kubectl apply -f -
apiVersion: networking.istio.io/v1
kind: Gateway
metadata:
  name: cgdm-kiali
  namespace: istio-ingress
spec:
  selector:
    app: istio-ingressgateway
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - "kiali.{{ cluster-name }}.ccs.cegedim.cloud"
---
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: cgdm-kiali
  namespace: istio-ingress
spec:
  hosts:
  - "kiali.{{ cluster-name }}.ccs.cegedim.cloud"
  gateways:
  - cgdm-kiali
  http:
  - route:
    - destination:
        host: kiali.istio-system.svc.cluster.local
        port:
          number: 20001
EOF
```

Kiali will be available at `https://kiali.{{ cluster-name }}.ccs.cegedim.cloud`.

### Step 2 — Enable sidecar injection

Label your namespace to enable automatic Envoy sidecar injection:

```bash
kubectl label namespace default istio-injection=enabled
```

Verify:

```bash
kubectl get namespace default --show-labels
```

Expected output includes `istio-injection=enabled`.

{% hint style="warning" %}
Unlike ambient mode, **existing pods must be restarted** to get the sidecar injected. The label only takes effect for newly created pods.
{% endhint %}

### Step 3 — Deploy your application

```bash
kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.30/samples/bookinfo/platform/kube/bookinfo.yaml
```

Verify all pods are running with **2 containers** each (app + Envoy sidecar):

```bash
kubectl get pods
```

Expected output shows `2/2` READY for each pod:

```
NAME                              READY   STATUS    RESTARTS   AGE
details-v1-xxx                    2/2     Running   0          ...
productpage-v1-xxx                2/2     Running   0          ...
ratings-v1-xxx                    2/2     Running   0          ...
reviews-v1-xxx                    2/2     Running   0          ...
```

### Step 4 — Wire ingress from the platform gateway

```bash
cat <<EOF | kubectl apply -f -
apiVersion: networking.istio.io/v1
kind: Gateway
metadata:
  name: cgdm-bookinfo
  namespace: istio-ingress
spec:
  selector:
    app: istio-ingressgateway
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - "bookinfo.{{ cluster-name }}.ccs.cegedim.cloud"
---
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: cgdm-bookinfo
  namespace: istio-ingress
spec:
  hosts:
  - "bookinfo.{{ cluster-name }}.ccs.cegedim.cloud"
  gateways:
  - cgdm-bookinfo
  http:
  - route:
    - destination:
        host: productpage.default.svc.cluster.local
        port:
          number: 9080
EOF
```

The full ingress flow:

```
https://bookinfo.{{ cluster-name }}.ccs.cegedim.cloud
  → BigIP (TLS termination)
  → istio-ingressgateway (DaemonSet, istio-ingress)
  → productpage.default.svc.cluster.local:9080
```

### Step 5 — Verify

```bash
curl https://bookinfo.{{ cluster-name }}.ccs.cegedim.cloud/productpage
```

### Step 6 — Observability with Kiali

Access `https://kiali.{{ cluster-name }}.ccs.cegedim.cloud`, navigate to **Graph** and select the `default` namespace to see live traffic between services.

Generate continuous traffic to populate the graph:

```bash
while true; do curl -sSI -o /dev/null https://bookinfo.{{ cluster-name }}.ccs.cegedim.cloud/productpage; done
```

### Step 7 — L7 traffic management

In sidecar mode, L7 traffic management is built-in — the Envoy sidecar handles routing directly. No waypoint proxy is needed.

**Define subsets with DestinationRule:**

```bash
cat <<EOF | kubectl apply -f -
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
  name: reviews
spec:
  host: reviews
  subsets:
  - name: v1
    labels:
      version: v1
  - name: v2
    labels:
      version: v2
  - name: v3
    labels:
      version: v3
EOF
```

**Traffic split with VirtualService** — 90% to `reviews-v1`, 10% to `reviews-v3`:

```bash
cat <<EOF | kubectl apply -f -
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
  - reviews
  http:
  - route:
    - destination:
        host: reviews
        subset: v1
      weight: 90
    - destination:
        host: reviews
        subset: v3
      weight: 10
EOF
```

Verify in Kiali — the **Graph** view will show weighted traffic flowing to each version.

### Clean up — Sidecar mode

```bash
# Step 7 — Traffic management
kubectl delete virtualservice reviews
kubectl delete destinationrule reviews

# Step 4 — Ingress wiring
kubectl delete gateway.networking.istio.io cgdm-bookinfo -n istio-ingress
kubectl delete virtualservice cgdm-bookinfo -n istio-ingress

# Step 3 — Application
kubectl delete -f https://raw.githubusercontent.com/istio/istio/release-1.30/samples/bookinfo/platform/kube/bookinfo.yaml

# Step 2 — Disable sidecar injection
kubectl label namespace default istio-injection-

# Step 1 — Observability addons
kubectl delete gateway.networking.istio.io cgdm-kiali -n istio-ingress
kubectl delete virtualservice cgdm-kiali -n istio-ingress
kubectl delete -f https://raw.githubusercontent.com/istio/istio/release-1.30/samples/addons/kiali.yaml
kubectl delete -f https://raw.githubusercontent.com/istio/istio/release-1.30/samples/addons/prometheus.yaml
```

***

## Ambient Mode

In ambient mode, there are no sidecar containers. A node-level **ztunnel** handles L4 mTLS transparently for all enrolled pods — no pod restart is required. L7 traffic management requires deploying an optional **waypoint proxy** per namespace.

### Step 1 — Prerequisites

**Gateway API CRDs** (experimental channel) are required for ambient mesh:

```bash
kubectl get crd gateways.gateway.networking.k8s.io &> /dev/null || \
  kubectl apply --server-side -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.5.1/experimental-install.yaml
```

**Observability addons** (optional):

```bash
kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.30/samples/addons/prometheus.yaml
kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.30/samples/addons/kiali.yaml
```

Expose Kiali:

```bash
cat <<EOF | kubectl apply -f -
apiVersion: networking.istio.io/v1
kind: Gateway
metadata:
  name: cgdm-kiali
  namespace: istio-ingress
spec:
  selector:
    app: istio-ingressgateway
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - "kiali.{{ cluster-name }}.ccs.cegedim.cloud"
---
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: cgdm-kiali
  namespace: istio-ingress
spec:
  hosts:
  - "kiali.{{ cluster-name }}.ccs.cegedim.cloud"
  gateways:
  - cgdm-kiali
  http:
  - route:
    - destination:
        host: kiali.istio-system.svc.cluster.local
        port:
          number: 20001
EOF
```

Kiali will be available at `https://kiali.{{ cluster-name }}.ccs.cegedim.cloud`.

### Step 2 — Enroll your namespace

Label your namespace to join the ambient mesh. ztunnel will automatically intercept all pod traffic with mTLS:

```bash
kubectl label namespace default istio.io/dataplane-mode=ambient
```

Verify:

```bash
kubectl get namespace default --show-labels
```

Expected output includes `istio.io/dataplane-mode=ambient`.

{% hint style="info" %}
Existing pods do **not** need to be restarted. ztunnel picks them up immediately.
{% endhint %}

### Step 3 — Deploy your application

No sidecar annotations required:

```bash
kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.30/samples/bookinfo/platform/kube/bookinfo.yaml
```

Verify all pods are running:

```bash
kubectl get pods
```

### Step 4 — Expose your application via Gateway API

Create a `Gateway` resource in your application namespace. Istiod will auto-provision a dedicated gateway pod and service for it:

```bash
cat <<EOF | kubectl apply -f -
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: bookinfo-gateway
  annotations:
    networking.istio.io/service-type: ClusterIP
spec:
  gatewayClassName: istio
  listeners:
  - name: http
    port: 80
    protocol: HTTP
    allowedRoutes:
      namespaces:
        from: Same
EOF
```

Then create an `HTTPRoute`:

```bash
cat <<EOF | kubectl apply -f -
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: bookinfo
spec:
  parentRefs:
  - name: bookinfo-gateway
  rules:
  - matches:
    - path:
        type: Exact
        value: /productpage
    - path:
        type: PathPrefix
        value: /static
    - path:
        type: Exact
        value: /login
    - path:
        type: Exact
        value: /logout
    - path:
        type: PathPrefix
        value: /api/v1/products
    backendRefs:
    - name: productpage
      port: 9080
EOF
```

{% hint style="info" %}
The auto-provisioned gateway service will be named `bookinfo-gateway-istio` in the `default` namespace.
{% endhint %}

### Step 5 — Wire ingress from the platform gateway

Submit the following manifest to the platform team (or apply it yourself if you have access to the `istio-ingress` namespace):

```bash
cat <<EOF | kubectl apply -f -
apiVersion: networking.istio.io/v1
kind: Gateway
metadata:
  name: cgdm-bookinfo
  namespace: istio-ingress
spec:
  selector:
    app: istio-ingressgateway
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - "bookinfo.{{ cluster-name }}.ccs.cegedim.cloud"
---
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: cgdm-bookinfo
  namespace: istio-ingress
spec:
  hosts:
  - "bookinfo.{{ cluster-name }}.ccs.cegedim.cloud"
  gateways:
  - cgdm-bookinfo
  http:
  - route:
    - destination:
        host: bookinfo-gateway-istio.default.svc.cluster.local
        port:
          number: 80
EOF
```

The full ingress flow:

```
https://bookinfo.{{ cluster-name }}.ccs.cegedim.cloud
  → BigIP (TLS termination)
  → istio-ingressgateway (DaemonSet, istio-ingress)
  → bookinfo-gateway-istio.default.svc.cluster.local
  → productpage:9080
```

{% hint style="info" %}
**Alternative — dedicated ingress path:** Set `networking.istio.io/service-type: NodePort` on your `Gateway` resource (Step 4) and ask the platform team to create a dedicated BigIP virtual server for it. This gives your application a fully independent ingress path without going through the shared `istio-ingressgateway`.
{% endhint %}

### Step 6 — Verify

```bash
curl https://bookinfo.{{ cluster-name }}.ccs.cegedim.cloud/productpage
```

### Step 7 — Observability with Kiali

Access `https://kiali.{{ cluster-name }}.ccs.cegedim.cloud`, navigate to **Graph** and select the `default` namespace.

Generate continuous traffic to populate the graph:

```bash
while true; do curl -sSI -o /dev/null https://bookinfo.{{ cluster-name }}.ccs.cegedim.cloud/productpage; done
```

### Step 8 — L7 traffic management with waypoint

By default, ztunnel handles only L4 traffic (mTLS, TCP). For L7 features (traffic splitting, header routing, retries), deploy a **waypoint proxy** in your namespace.

**Deploy the waypoint:**

```bash
istioctl waypoint apply --namespace default --enroll-namespace
```

Verify:

```bash
kubectl get deployment waypoint -n default
kubectl get namespace default --show-labels | grep use-waypoint
```

**Deploy per-version services** (required for traffic splitting):

```bash
kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.30/samples/bookinfo/platform/kube/bookinfo-versions.yaml
```

**Traffic split with HTTPRoute** — point `parentRefs` to the Service (not a Gateway). The waypoint intercepts and applies the routing rules:

```bash
cat <<EOF | kubectl apply -f -
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: reviews
spec:
  parentRefs:
  - group: ""
    kind: Service
    name: reviews
    port: 9080
  rules:
  - backendRefs:
    - name: reviews-v1
      port: 9080
      weight: 90
    - name: reviews-v3
      port: 9080
      weight: 10
EOF
```

Verify in Kiali — the **Graph** view will show weighted traffic flowing to each version.

### Clean up — Ambient mode

```bash
# Step 8 — Traffic management
kubectl delete httproute reviews
kubectl delete -f https://raw.githubusercontent.com/istio/istio/release-1.30/samples/bookinfo/platform/kube/bookinfo-versions.yaml
istioctl waypoint delete waypoint --namespace default
kubectl label namespace default istio.io/use-waypoint-

# Step 5 — Ingress wiring
kubectl delete gateway.networking.istio.io cgdm-bookinfo -n istio-ingress
kubectl delete virtualservice cgdm-bookinfo -n istio-ingress

# Steps 3 & 4 — Application and gateway
kubectl delete httproute bookinfo
kubectl delete gateway bookinfo-gateway
kubectl delete -f https://raw.githubusercontent.com/istio/istio/release-1.30/samples/bookinfo/platform/kube/bookinfo.yaml

# Step 2 — Namespace enrollment
kubectl label namespace default istio.io/dataplane-mode-

# Step 1 — Observability addons
kubectl delete gateway.networking.istio.io cgdm-kiali -n istio-ingress
kubectl delete virtualservice cgdm-kiali -n istio-ingress
kubectl delete -f https://raw.githubusercontent.com/istio/istio/release-1.30/samples/addons/kiali.yaml
kubectl delete -f https://raw.githubusercontent.com/istio/istio/release-1.30/samples/addons/prometheus.yaml
```

## Further Reading

{% embed url="<https://istio.io/latest/docs/setup/getting-started/>" %}

{% embed url="<https://istio.io/latest/docs/ambient/getting-started/>" %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://academy.cegedim.cloud/compute/containers-k8s/k8s-features/gateway-api/gateway-api-istio.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
