Istio Installation for Divert
This guide is for Okteto administrators setting up Istio in the cluster. Developers do not need to install anything - once Istio is configured, Divert works transparently for all developers.
This guide covers two things:
- Inbound ingress — routing external user traffic through Istio instead of the default
okteto-nginxingress controller - In-cluster divert routing — using Istio VirtualServices and sidecars for header-based routing between namespaces
The Istio driver uses Istio's VirtualService for header-based routing and is designed for environments that already use Istio or prefer Istio-native service mesh capabilities.
This installation is only required when using the istio driver. If you're using the default nginx driver, do not install Istio - see Configure Divert for the distinction between drivers.
Prerequisites
- Kubernetes cluster with Okteto installed
kubectlconfigured with cluster admin accesshelmv3.x installed- Administrator/operator access (this is a one-time cluster setup)
Understanding Okteto's Ingress Controllers
Before configuring Istio, it helps to understand how Okteto's ingress controllers work:
| Controller | Ingress Class | Service Type | Purpose |
|---|---|---|---|
ingress-nginx | okteto-controlplane-nginx | LoadBalancer | The external-facing controller. Serves the Okteto control plane (API, Frontend, Buildkit, Registry) and forwards wildcard *.subdomain traffic to the user traffic controller |
okteto-nginx | okteto-nginx | ClusterIP | An internal controller dedicated to user/dev namespace ingress traffic |
Okteto runs two separate nginx controllers to isolate user traffic from control plane traffic. This prevents developer app deployments from disrupting control plane access during reconfigurations and updates, and vice versa (this is an nginx limitation).
When you enable Istio, you disable okteto-nginx so that Istio handles user ingress traffic instead. The ingress-nginx controller continues to serve the Okteto control plane and forwards wildcard user traffic to the Istio ingress gateway (via the ingress you create in Step 7).
If you want Istio (or another ingress controller) to handle all traffic including the Okteto control plane, see Using your own ingress controller below.
Configure Okteto for Istio
Before installing Istio, update your Okteto Helm values to disable the built-in nginx ingress and enable Istio integration:
# Disable the default okteto-nginx since we will enable Istio ingress mode
okteto-nginx:
enabled: false
# Enable VirtualService endpoints in the Okteto UI
virtualServices:
enabled: true
# Inject the Istio sidecar injection label on every namespace managed by Okteto
namespace:
labels:
istio-injection: enabled
okteto-nginx: enabled: false— Disables the built-in nginx ingress controller so Istio can handle ingressvirtualServices: enabled: true— Displays VirtualService endpoints in the Okteto UInamespace: labels: istio-injection: enabled— Instructs Istio to inject sidecars into every pod in Okteto-managed namespaces, ensuring all traffic goes through the Istio mesh
Apply the changes:
helm upgrade okteto okteto/okteto -f values.yaml
Install Istio
If your cluster already has Istio base CRDs, Istiod, and an ingress gateway running, you can skip Steps 1, 3, 4, 5, and 6. You only need to:
- Set your domain variable (Step 2)
- Configure the ingress to route wildcard traffic to your existing Istio ingress gateway service (Step 7) — update the
service.nameto match your existing gateway's service name - Verify the installation (Step 8)
Step 1: Add the Istio Helm Repository
helm repo add istio https://istio-release.storage.googleapis.com/charts
helm repo update
Step 2: Set Your Domain
Export the OKTETO_DOMAIN environment variable with the subdomain Helm value of your Okteto instance:
export OKTETO_DOMAIN=okteto.example.com
Step 3: Install Istio Base (CRDs)
helm install --namespace istio-system --create-namespace istio-base istio/base --wait
Step 4: Prepare the Istio Ingress Namespace
kubectl create namespace istio-ingress
kubectl label namespace istio-ingress istio-injection=enabled
Step 5: Install Istiod (Control Plane)
Create a istiod-helm-values.yaml file with the following configuration:
meshConfig:
outboundTrafficPolicy:
mode: "ALLOW_ANY" # Dev configuration only — not recommended for production
enableTracing: false
defaultConfig:
holdApplicationUntilProxyStarts: true
terminationDrainDuration: 5s
proxyMetadata:
ISTIO_META_DNS_CAPTURE: "true"
EXIT_ON_ZERO_ACTIVE_CONNECTIONS: "true"
pilot:
env:
PILOT_PUSH_THROTTLE: 20
PILOT_DEBOUNCE_AFTER: 500ms
autoscaleMin: 2
autoscaleMax: 4
istio_cni:
enabled: false
Install istiod:
helm install --namespace istio-system istiod istio/istiod --values istiod-helm-values.yaml --wait
Step 6: Install the Istio Ingress Gateway
Create a istio-ingress-helm-values.yaml file:
service:
type: NodePort
ports:
- port: 15021
targetPort: 15021
name: status-port
protocol: TCP
- port: 80
targetPort: 8080
name: http2
protocol: TCP
- port: 15443
targetPort: 15443
name: tls
protocol: TCP
autoscaling:
enabled: false
Install the gateway:
helm install --namespace istio-ingress istio-ingress istio/gateway --values istio-ingress-helm-values.yaml --wait
Step 7: Configure the Istio Ingress
Create a istio-ingress-config.yaml file to route wildcard user traffic from Okteto's control plane nginx to the Istio ingress gateway:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: istio-ingress
spec:
ingressClassName: okteto-controlplane-nginx
tls:
- hosts:
- '*.${OKTETO_DOMAIN}'
rules:
- host: '*.${OKTETO_DOMAIN}'
http:
paths:
- path: /
pathType: Prefix
backend:
service:
# This must match the Kubernetes Service name of your Istio
# ingress gateway. If you installed Istio using the steps above,
# this is "istio-ingress". If you're using an existing Istio
# installation, replace this with your gateway service name
# (e.g., "istio-ingressgateway").
name: istio-ingress
port:
number: 80
The backend.service.name must point to the Kubernetes Service fronting your Istio ingress gateway pods. If you are using an existing Istio installation, this is typically istio-ingressgateway in the istio-system namespace. Adjust the service name and apply the ingress resource to the namespace where the service lives.
Apply the configuration (using envsubst to substitute your domain):
envsubst < istio-ingress-config.yaml | kubectl apply -n istio-ingress -f -
Step 8: Verify Installation
Check that all Istio components are running:
kubectl get pods -n istio-system
kubectl get pods -n istio-ingress
All pods should be in Running state before continuing.
How Istio Enables Divert
Once configured by administrators, Istio works transparently for all developers. When a developer uses Divert with the Istio driver, Okteto:
- Creates or modifies VirtualServices to route traffic based on the
baggage: okteto-divert=<namespace>header - Clones the specified host VirtualServices to the developer's personal namespace for header injection
- The Istio sidecar propagates the baggage header through all downstream service calls
Developers don't need to install anything or change their workflow.
Traffic Flow with Istio
Request (no header)
│
▼
┌─────────────┐
│ Okteto │ ← nginx control plane
│ Ingress │
└──────┬──────┘
│
▼
┌─────────────┐
│ Istio │ ← Routes to Istio ingress gateway
│ Ingress │
└──────┬──────┘
│ (baggage header injected by VirtualService)
▼
┌─────────────┐
│ Istio │ ← Routes based on baggage header
│ Sidecar │
└──────┬──────┘
│
▼
┌─────────────┐
│ Service │ ← Your diverted service (personal namespace)
│ (personal) │
└──────┬──────┘
│ (header propagated automatically)
▼
┌─────────────┐
│ Istio │ ← Routes downstream call
│ Sidecar │
└──────┬──────┘
│
▼
┌─────────────┐
│ Service │ ← Shared service in staging
│ (staging) │
└─────────────┘
Network Policies Compatibility
If you have network policies enabled (networkPolicies.enabled: true), ensure your policies allow cross-namespace communication for Divert. Example configuration in your Okteto Helm values:
networkPolicies:
enabled: true
ingress:
- from:
- namespaceSelector:
matchLabels:
dev.okteto.com/okteto-managed: "true"
For complete network policy options, see the Helm Configuration reference.
Troubleshooting
Sidecar Not Injected
-
Verify the namespace has the Istio injection label:
kubectl get namespace <namespace> --show-labels -
Restart deployments to inject sidecars:
kubectl rollout restart deployment -n <namespace> -
Verify sidecar containers are present:
kubectl get pods -n <namespace> -o jsonpath='{.items[*].spec.containers[*].name}'
VirtualServices Not Created
- Verify
virtualServices.enabled: truein your Okteto Helm values - Check that Istio CRDs are installed:
kubectl get crd | grep istio - Check Okteto logs for errors related to VirtualService creation
Traffic Not Routing Correctly
- Verify the baggage header format:
baggage: okteto-divert=<namespace> - Check that the developer's
okteto.ymlusesdriver: istio - Test direct service communication:
kubectl exec -it <pod> -- curl -H "baggage: okteto-divert=<ns>" http://service/path - Check Istio proxy logs:
kubectl logs <pod> -c istio-proxy -n <namespace>
Ingress Not Working
- Verify the
istio-ingress-config.yamlwas applied correctly:kubectl get ingress -n istio-ingress - Confirm
OKTETO_DOMAINwas substituted correctly in the ingress manifest - Check that
okteto-nginxis disabled in your Okteto Helm values
Using Your Own Ingress Controller
The configuration above only disables okteto-nginx (the user traffic ingress controller) in favor of Istio. The ingress-nginx controller still handles control plane traffic (API, Frontend, Buildkit, Registry).
If you want to disable both nginx ingress controllers and use Istio (or another ingress controller) for all traffic, including the Okteto control plane:
ingress-nginx:
enabled: false
okteto-nginx:
enabled: false
defaultBackend:
enabled: false
When disabling both controllers, you must also configure:
ingress.oktetoIngressClass— the ingress class to use for all ingresses created during the Okteto installationingress.class— the ingress class to use for all ingresses created by Okteto for developer namespacesingress.ip— the cluster IP of your ingress controller
When disabling Okteto's nginx controllers, the following features are not available:
- Autowake Namespaces
- Error Pages
- Private Endpoints
Uninstalling Istio
If you need to remove Istio:
# Remove ingress configuration
kubectl delete ingress istio-ingress -n istio-ingress
# Uninstall Helm releases
helm uninstall istio-ingress -n istio-ingress
helm uninstall istiod -n istio-system
helm uninstall istio-base -n istio-system
# Remove namespaces
kubectl delete namespace istio-ingress
kubectl delete namespace istio-system
Re-enable the nginx driver in your Okteto Helm values:
okteto-nginx:
enabled: true
virtualServices:
enabled: false
namespace:
labels: {}
Then upgrade Okteto:
helm upgrade okteto okteto/okteto -f values.yaml
Next Steps
- Configure Divert - Overview of Divert configuration
- Using Divert - Developer implementation guide
- Divert with Istio Sample - Full working example
- Istio Documentation - Official Istio docs