Esta é a continuação do meu post anterior, em que compartilhei minha opinião sobre o Istio Ambient Mesh e o comparei com o modelo tradicional de Data Plane baseado em sidecar.
Neste artigo, vou mostrar como instalar e usar o Istio Ambient Mesh em um cluster do Google Kubernetes Engine rodando no Google Cloud Platform.
Observação: o Istio Ambient Mesh ainda está em alpha e não deve ser usado em produção até chegar à disponibilidade geral (GA).
Pré-requisitos
- O cluster precisa estar rodando uma versão suportada do Kubernetes (1.25, 1.26, 1.27, 1.28, 1.29).
- O CNI (Container Network Interface) precisa estar habilitado no cluster. Clusters GKE já vêm com o GKE CNI habilitado por padrão. O Dataplane v2 não é suportado no momento.
- No mínimo 3 nós e 4 vCPUs por nó. Cada z-tunnel reserva 500mCPU e 2Gi de memória — e isso sem contar os outros componentes, então é melhor ter vCPU e memória de sobra.
- Pré-requisitos da plataforma
- Pré-requisitos específicos do GKE
Observação: esta instalação não funciona em clusters GKE Autopilot, já que o Dataplane v2 não é opcional, embora seja possível habilitar as capacidades NET_ADMIN e NET_RAW .
Importante: problemas de compatibilidade com o DataPlane v2
O Istio Ambient Mesh exige a instalação do plugin Istio CNI, que substitui a função do container istio-init (que precisa das capacidades NET_ADMIN e NET_RAW) sem que os usuários responsáveis pelo deploy precisem de permissões RBAC elevadas para provisionar containers privilegiados desse tipo.
A documentação do Istio CNI traz o seguinte aviso.
Observação: o plugin Istio CNI funciona como um plugin CNI encadeado e foi feito para ser usado em conjunto com outro plugin CNI, como o PTP ou o Calico. Veja compatibilidade com outros plugins CNI para mais detalhes.
É aqui que a coisa começa a complicar. O Data Plane legado do GKE (atualmente o padrão) usa o GKE CNI (Calico CNI quando a Network Policy está habilitada), apoiando-se em kube-proxies e iptables para rotear o tráfego dentro do cluster.
Já o GKE Data Plane v2, mais recente (e que será o padrão de fato no futuro), é basicamente uma versão gerenciada do Cilium CNI, que usa um Data Plane eBPF para substituir os kube-proxies por programas eBPF modernos e oferecer uma rede aprimorada.
Este artigo da Solo.io explica como configurar o Cilium CNI para que ele não quebre o Istio. Mas isso só vale para o modelo sidecar do Istio e, de qualquer forma, não funciona com o Dataplane V2, porque ele é um componente gerenciado pelo GCP cuja configuração é imutável.
O DataPlane V2 também usa um dispositivo veth, mas talvez os programas eBPF simplesmente não sejam compatíveis entre si. Se você souber o motivo, vou adorar ler nos comentários.

Por isso, precisamos desabilitar o Dataplane v2 na nossa implementação para que o componente Istio CNI possa ser instalado com sucesso.
Espero que o Dataplane v2 venha a ser suportado em breve, já que será o modo padrão de Data Plane para clusters GKE em um futuro próximo.
Configurando o cluster
Neste exemplo, vou criar um cluster GKE básico com nós privados e endpoint mestre público.
Este é o comando que estou usando para implantar o cluster na rede VPC padrão. Você pode ajustar as variáveis como preferir, mas certifique-se de manter o Dataplane v2 desabilitado.
Em ambientes reais, vale a pena usar nós maiores com vários pods por nó para tirar o máximo proveito disso.
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"
Quando o cluster é criado, o GCP cria automaticamente regras de firewall para você, permitindo que o control plane mestre se comunique com os nós.

Dá para ver que as portas TCP 443 (HTTPS) e 10250 (Kubelet) estão liberadas, mas essa regra não abre a porta 15017, necessária para o webhook de validação de descoberta do Pilot (componente do Istio Control Plane).
Se você usa um cluster GKE privado (como é o meu caso), é preciso criar uma regra de firewall para permitir tráfego do mestre na porta 15017. Primeiro, obtenha o intervalo de IP de origem do mestre e as tags de rede da regra de firewall:
gcloud compute firewall-rules list --filter="name~gke-${CLUSTER_NAME}-[0-9a-z]*-master" --format="table(targetTags, sourceRanges.list())"
Depois, com o intervalo de IP de origem e as tags de rede retornados pelo comando anterior, crie uma nova regra de firewall para permitir tráfego do mestre na 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
Garanta também que o Cloud NAT esteja configurado na VPC onde o cluster está implantado, para que os pods nos nós privados do GKE tenham acesso à internet.
Baixando e instalando o Istio em modo Ambient
Baixe a versão mais recente do Istio:
curl -L https://istio.io/downloadIstio | sh -
Acesse o diretório do Istio e adicione o cliente istioctl ao seu PATH:
cd istio-1.20.3/
export PATH=$PWD/bin:$PATH
Autentique-se e conecte-se ao seu cluster GKE (verifique se você tem permissões IAM suficientes para conectar e fazer deploys no cluster)
gcloud container clusters get-credentials ${CLUSTER_NAME} --zone ${ZONE} --project ${PROJECT_ID}
Instale as CRDs do 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 -; }
Instale o Istio em modo ambient
istioctl install --set profile=ambient --set "components.ingressGateways[0].enabled=true" --set "components.ingressGateways[0].name=istio-ingressgateway" --skip-confirmation
Você deve ver os 5 componentes a seguir instalados com sucesso, em especial o CNI e o z-tunnel.

Confira se os componentes estão instalados e prontos verificando os pods e DaemonSets no namespace istio-system.

kubectl get pod -n istio-system

kubectl get ds -n istio-system

kubectl get ds -n kube-system
Implantando aplicações no Istio Ambient Mesh
Uma das coisas legais do Istio é que você não precisa mexer nas suas aplicações. Vamos implantar o clássico aplicativo de exemplo bookinfo do Istio do jeito que ele é e, depois, adicioná-lo ao mesh após o deploy.
Você vai encontrar o código do aplicativo bookinfo no mesmo diretório onde instalou o Istio.
kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml
Implante mais 2 aplicações (clientes curl) que usaremos para simular tráfego no ambiente do mesh.
kubectl apply -f samples/sleep/sleep.yaml
kubectl apply -f samples/sleep/notsleep.yaml
Implante um ingress gateway para acessar o aplicativo Bookinfo pela internet.
kubectl apply -export GATEWAY_HOST=$(kubectl get service/istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}' -n istio-system)l
Obtenha os endpoints interno e externo do serviço istio-ingressgateway. Vamos enviar tráfego para os dois para visualizar tanto o tráfego dentro do mesh quanto o tráfego externo, vindo de fora do 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

visualizado pelo navegador
Vendo o Mesh em ação
Implante uma instalação de exemplo do Prometheus e do Kiali para monitorar e visualizar o tráfego, respectivamente.
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
Modifique o arquivo de serviço do Kiali para expô-lo à internet, assim você consegue visualizá-lo pelo navegador.
kubectl patch svc kiali -n istio-system -p '{"spec": {"type": "LoadBalancer"}}'
Abra no navegador assim que um IP externo for provisionado para o serviço Kiali. Por enquanto temos poucos dados, já que nossas aplicações ainda não fazem parte do mesh.

Adicione as aplicações Bookinfo do namespace default ao Ambient Mesh aplicando uma label ao namespace.
kubectl label namespace default istio.io/dataplane-mode=ambient
As aplicações agora fazem parte do mesh de forma transparente, sem nenhuma interrupção. Vamos enviar tráfego para essas aplicações a partir dos nossos clientes curl e ver o mesh em ação.
curl http://$GATEWAY_HOST_EXT/productpage
#Tráfego do usuário para o endpoint do gateway externo
kubectl exec deploy/sleep -- curl -s "http://$GATEWAY_HOST_INT/productpage"
#Tráfego do pod para o endpoint do gateway interno
kubectl exec deploy/sleep -- curl -s http://productpage:9080/
#Tráfego do pod para o svc (diretamente)
kubectl exec deploy/notsleep -- curl -s http://productpage:9080/
#Tráfego do pod para o svc (diretamente)
Confira o gráfico do Kiali de novo. Agora ele já deve estar populado, com dados mostrando comunicações protegidas com mTLS e outras informações úteis de telemetria.

Aplicando políticas de autorização L7
Agora que a sobreposição segura está em vigor, você pode aplicar políticas de autorização L4 com facilidade, da mesma forma que faria com o Istio padrão.
No entanto, essa sobreposição segura não permite usar filtragem L7. Para isso, precisamos implantar um waypoint proxy baseado em Envoy para o serviço productpage.
O proxy é aplicado à service account, então no caso do serviço productpage a service account é bookinfo-productpage.
Implante um waypoint proxy para o serviço productpage:
istioctl x waypoint apply --service-account bookinfo-productpage
Isso implanta um waypoint proxy para qualquer serviço que use a service account bookinfo-productpage.


Todo tráfego destinado ao serviço productpage vai passar pelo proxy L7, que escala automaticamente conforme o uso
Vamos criar uma AuthorizationPolicy L7 para permitir explicitamente que as service accounts sleep e do gateway façam GET no serviço productpage, mas nenhuma outra operação.
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
Teste a política em ação:
# isto deve falhar com um erro de RBAC porque não é uma operação GET
kubectl exec deploy/sleep -- curl -s "http://$GATEWAY_HOST/productpage" -X DELETE
# A saída deve ser 'RBAC: access denied'
# isto deve falhar com um erro de RBAC porque a identidade não é permitida
kubectl exec deploy/notsleep -- curl -s http://productpage:9080/
# A saída deve ser 'RBAC: access denied'
# isto deve continuar funcionando
kubectl exec deploy/sleep -- curl -s http://productpage:9080/ | grep -o "<title>.*</title>"
# A saída deve ser '<title>Simple Bookstore App</title>'
Limpeza
Execute os comandos a seguir para desinstalar o Istio e seus componentes
istioctl x waypoint delete --all
istioctl uninstall -y --purge
kubectl delete namespace istio-system
Excluir o cluster GKE
gcloud container clusters delete $CLUSTER_NAME --zone $ZONE
É bem legal ver como as funcionalidades L4 e L7 foram modularizadas em prol de mais flexibilidade e eficiência.
Tenho um interesse especial em observar os benefícios em escala e adoraria ver o Ambient Mesh rodando em um ambiente de produção real.
Espero que você tenha curtido este artigo e o achado útil. Fique à vontade para compartilhar suas opiniões e feedback nos comentários.