Questo articolo prosegue il mio post precedente, in cui ho esposto la mia opinione su Istio Ambient Mesh confrontandolo con il tradizionale modello di Data Plane basato su sidecar.
Qui vedremo come installare e utilizzare Istio Ambient Mesh su un cluster Google Kubernetes Engine in esecuzione su Google Cloud Platform.
Nota: Istio Ambient Mesh è ancora in fase alpha e non andrebbe utilizzato in ambienti di produzione fino al passaggio alla General Availability (GA).
Prerequisiti
- Il cluster deve eseguire una versione supportata di Kubernetes (1.25, 1.26, 1.27, 1.28, 1.29).
- Sul cluster deve essere abilitata la CNI (Container Network Interface). Sui cluster GKE la GKE CNI è abilitata per impostazione predefinita. Dataplane v2 al momento non è supportato.
- Almeno 3 nodi e 4 vCPU per nodo. Ogni z-tunnel riserva 500mCPU e 2Gi di memoria, senza contare gli altri componenti: meglio quindi prevedere vCPU e memoria in abbondanza.
- Prerequisiti della piattaforma
- Prerequisiti specifici per GKE
Nota: questa installazione non funziona sui cluster GKE Autopilot, perché Dataplane v2 non è opzionale, anche se è possibile abilitare le capability NET_ADMIN e NET_RAW.
Importante: problemi di compatibilità con DataPlane v2
Istio Ambient Mesh richiede l'installazione del plugin Istio CNI, che sostituisce le funzioni del container istio-init (il quale richiede le capability NET_ADMIN e NET_RAW) senza che chi esegue il deployment debba disporre di permessi RBAC elevati per il provisioning di container privilegiati.
La documentazione di Istio CNI contiene il seguente disclaimer.
Nota: il plugin Istio CNI funziona come plugin CNI concatenato ed è pensato per essere usato insieme a un altro plugin CNI, come PTP o Calico. Per i dettagli si veda la compatibilità con altri plugin CNI.
È qui che la situazione si complica. Il Data Plane GKE legacy (oggi quello predefinito) si basa sulla GKE CNI (Calico CNI se è abilitata Network Policy) e sfrutta kube-proxy e iptables per instradare il traffico all'interno del cluster.
Il più recente GKE Data Plane v2 (destinato a diventare lo standard di fatto e l'opzione predefinita) è invece, di fatto, una versione gestita di Cilium CNI: utilizza un eBPF Data Plane che sostituisce i kube-proxy con moderni programmi eBPF per un networking più performante.
Questo articolo di Solo.io spiega come configurare Cilium CNI per non interferire con Istio. Vale però solo per il modello sidecar di Istio e in ogni caso non si applica a Dataplane V2, perché si tratta di un componente gestito da GCP la cui configurazione è immutabile.
DataPlane V2 utilizza effettivamente un dispositivo veth, ma forse i due insiemi di programmi eBPF non sono compatibili tra loro. Se conosce il motivo, lo scriva pure nei commenti: mi farebbe piacere saperlo.

Per questo motivo, nella nostra implementazione dobbiamo disabilitare Dataplane v2, in modo da poter installare correttamente il componente Istio CNI.
Mi auguro che prima o poi Dataplane v2 venga supportato, dato che a breve diventerà la modalità Data Plane predefinita per i cluster GKE.
Configurazione del cluster
In questo esempio creiamo un cluster GKE di base con nodi privati e un endpoint master pubblico.
Ecco il comando che useremo per distribuire il cluster nella rete VPC predefinita. Può adattare le variabili come preferisce, purché Dataplane v2 resti disabilitato.
In un ambiente reale conviene utilizzare nodi più grandi con molti pod ciascuno, per sfruttare al meglio la configurazione.
export PROJECT_ID=`gcloud config get-value project` && \
export M_TYPE=e2-standard-4 && \
export ZONE=us-central1-a && \
export CLUSTER_NAME=ambient-mesh-cluster && \
gcloud services enable container.googleapis.com && \
gcloud container clusters create $CLUSTER_NAME \
--project $PROJECT_ID \
--cluster-version "latest" \
--release-channel "regular" \
--location $ZONE \
--machine-type $M_TYPE \
--image-type "COS_CONTAINERD" \
--num-nodes "3" \
--enable-private-nodes \
--master-ipv4-cidr "172.16.0.0/28" \
--enable-ip-alias \
--no-enable-master-authorized-networks \
--network "projects/$PROJECT_ID/global/networks/default" \
--subnetwork "projects/$PROJECT_ID/regions/us-central1/subnetworks/default"
Una volta creato il cluster, GCP genera in automatico le regole firewall necessarie per consentire la comunicazione tra il master del control plane e i nodi.

Come si vede, sono consentite le porte TCP 443 (HTTPS) e 10250 (Kubelet); questa regola, però, non apre la porta 15017, necessaria al webhook di validazione della discovery di Pilot (il componente del Control Plane di Istio).
Se utilizza un cluster GKE privato (come in questo caso), occorre creare una regola firewall che consenta il traffico dal master sulla porta 15017. Per prima cosa, recuperi l'intervallo di IP sorgente del master e i tag di rete della regola firewall:
gcloud compute firewall-rules list --filter="name~gke-${CLUSTER_NAME}-[0-9a-z]*-master" --format="table(targetTags, sourceRanges.list())"
Quindi, sulla base dell'intervallo di IP sorgente e dei tag di rete restituiti, crei una nuova regola firewall che consenta il traffico dal master sulla porta TCP 15017:
gcloud compute firewall-rules create <firewall-rule-name> --network <VPC-name> --source-ranges=<CIDR_RANGE> --direction=INGRESS --target-tags=<TAG> --allow tcp:15017
Verifichi inoltre che Cloud NAT sia configurato nella VPC in cui è distribuito il cluster, in modo che i pod sui nodi GKE privati possano raggiungere internet.
Download e installazione di Istio in modalità Ambient
Scarichi l'ultima versione di Istio:
curl -L https://istio.io/downloadIstio | sh -
Si sposti nella directory di Istio e aggiunga il client Istioctl al PATH:
cd istio-1.20.3/
export PATH=$PWD/bin:$PATH
Si autentichi e si colleghi al cluster GKE (verifichi di disporre dei permessi IAM necessari per la connessione e per i deployment sul cluster):
gcloud container clusters get-credentials ${CLUSTER_NAME} --zone ${ZONE} --project ${PROJECT_ID}
Installi le CRD di Kubernetes Gateway:
$ kubectl get crd gateways.gateway.networking.k8s.io &> /dev/null || \
{ kubectl kustomize "github.com/kubernetes-sigs/gateway-api/config/crd/experimental?ref=v1.0.0" | kubectl apply -f -; }
Installi Istio in modalità ambient:
istioctl install --set profile=ambient --set "components.ingressGateways[0].enabled=true" --set "components.ingressGateways[0].name=istio-ingressgateway" --skip-confirmation
Dovrebbe vedere installati correttamente i 5 componenti seguenti, in particolare la CNI e lo z-tunnel.

Verifichi che i componenti siano installati e pronti controllando i pod e i DaemonSet nel namespace istio-system.

kubectl get pod -n istio-system

kubectl get ds -n istio-system

kubectl get ds -n kube-system
Distribuire le applicazioni su Istio Ambient Mesh
Uno dei punti di forza di Istio è che non richiede alcuna modifica alle applicazioni. Distribuiremo qui la classica applicazione di esempio bookinfo di Istio così com'è e la aggiungeremo alla mesh solo dopo il deployment.
Il codice dell'applicazione bookinfo si trova nella stessa directory in cui ha installato Istio.
kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml
Distribuisca altre 2 applicazioni (client curl) che useremo per simulare traffico verso l'ambiente mesh.
kubectl apply -f samples/sleep/sleep.yaml
kubectl apply -f samples/sleep/notsleep.yaml
Distribuisca un ingress gateway per accedere all'app Bookinfo da internet.
kubectl apply -export GATEWAY_HOST=$(kubectl get service/istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}' -n istio-system)l
Recuperi gli endpoint interno ed esterno del servizio istio-ingressgateway. Invieremo traffico a entrambi per osservare sia quello interno alla mesh sia quello proveniente dall'esterno del cluster.
export GATEWAY_HOST_EXT=$(kubectl get service/istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}' -n istio-system)
export GATEWAY_HOST_INT=istio-ingressgateway.istio-system

visualizzato dal browser
La Mesh in azione
Distribuisca un'installazione di esempio di Prometheus e Kiali per monitorare e visualizzare il traffico.
kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.20/samples/addons/prometheus.yaml
kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.20/samples/addons/kiali.yaml
Modifichi il file del servizio Kiali per esporlo a internet e poterlo aprire dal browser.
kubectl patch svc kiali -n istio-system -p '{"spec": {"type": "LoadBalancer"}}'
Una volta assegnato un IP esterno al servizio Kiali, lo apra nel browser. Per ora i dati sono limitati, perché le applicazioni non fanno ancora parte della mesh.

Aggiunga le applicazioni Bookinfo del namespace default all'Ambient Mesh applicando una label al namespace.
kubectl label namespace default istio.io/dataplane-mode=ambient
Le applicazioni entrano così a far parte della mesh in modo trasparente, senza alcuna interruzione. Inviamo un po' di traffico dai nostri client curl e vediamo la mesh all'opera.
curl http://$GATEWAY_HOST_EXT/productpage
#Traffic from user to external gateway endpoint
kubectl exec deploy/sleep -- curl -s "http://$GATEWAY_HOST_INT/productpage"
#Traffic from pod to internal gateway endpoint
kubectl exec deploy/sleep -- curl -s http://productpage:9080/
#Traffic from pod to svc (directly)
kubectl exec deploy/notsleep -- curl -s http://productpage:9080/
#Traffic from pod to svc (directly)
Controlli di nuovo il grafo di Kiali: dovrebbe ora essere popolato di dati che mostrano comunicazioni protette in mTLS, oltre ad altre informazioni di telemetria utili.

Applicare policy di autorizzazione L7
Ora che l'overlay sicuro è in piedi, può applicare facilmente le policy di autorizzazione L4 proprio come farebbe con Istio in modalità tradizionale.
Questo overlay sicuro, però, non consente di sfruttare il filtraggio L7. Per farlo occorre distribuire un waypoint proxy basato su Envoy per il servizio productpage.
Il proxy viene applicato al service account: nel caso del servizio productpage, il service account è bookinfo-productpage.
Distribuisca un waypoint proxy per il servizio productpage:
istioctl x waypoint apply --service-account bookinfo-productpage
In questo modo viene distribuito un waypoint proxy per qualsiasi servizio che utilizzi il service account bookinfo-productpage.


Tutto il traffico diretto al servizio productpage dovrà ora passare attraverso il proxy L7, che scala automaticamente in base al carico.
Creiamo una AuthorizationPolicy L7 che consenta esplicitamente ai service account sleep e gateway di eseguire GET sul servizio productpage, vietando ogni altra operazione.
export GATEWAY_SERVICE_ACCOUNT=ns/istio-system/sa/istio-ingressgateway-service-account
kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: productpage-viewer
namespace: default
spec:
targetRef:
kind: Gateway
group: gateway.networking.k8s.io
name: bookinfo-productpage
action: ALLOW
rules:
- from:
- source:
principals:
- cluster.local/ns/default/sa/sleep
- cluster.local/$GATEWAY_SERVICE_ACCOUNT
to:
- operation:
methods: ["GET"]
EOF
Verifichi la policy in azione:
# this should fail with an RBAC error because it is not a GET operation
kubectl exec deploy/sleep -- curl -s "http://$GATEWAY_HOST/productpage" -X DELETE
# Output should be 'RBAC: access denied'
# this should fail with an RBAC error because the identity is not allowed
kubectl exec deploy/notsleep -- curl -s http://productpage:9080/
# Output should be 'RBAC: access denied'
# this should continue to work
kubectl exec deploy/sleep -- curl -s http://productpage:9080/ | grep -o "<title>.*</title>"
# Output should be '<title>Simple Bookstore App</title>'
Pulizia
Esegua i comandi seguenti per disinstallare Istio e i suoi componenti:
istioctl x waypoint delete --all
istioctl uninstall -y --purge
kubectl delete namespace istio-system
Elimini il cluster GKE:
gcloud container clusters delete $CLUSTER_NAME --zone $ZONE
È davvero notevole come le funzionalità L4 e L7 siano state modularizzate per garantire flessibilità ed efficienza.
Mi incuriosisce in particolare osservarne i benefici su larga scala e mi piacerebbe vedere Ambient Mesh all'opera in un ambiente di produzione reale.
Spero che l'articolo le sia stato utile e interessante. Non esiti a condividere opinioni e feedback nei commenti.