Introdução
Este tutorial é uma tradução e atualização do post original "Kind cluster with Cilium and no kube-proxy" de Charles-Edouard Brétéché. Ele foi adaptado para funcionar com algumas mudanças mais recentes na configuração. Gostaria de agradecer a Charles-Edouard Brétéché por seu excelente trabalho e por compartilhar seus conhecimentos.
I would like to thank Charles-Edouard Brétéché for his excellent work and for sharing his knowledge.
Configurar um cluster Kubernetes com Kind (Kubernetes em Docker) é uma escolha popular para desenvolvimento e testes locais. O Kind cria um cluster Kubernetes executando contêineres Docker como nós. Neste tutorial, vamos configurar um cluster Kind com Cilium como a CNI (Interface de Rede de Contêineres) e sem kube-proxy.
Visão Geral do Kind
O Kind é uma maneira simples e eficaz de executar clusters Kubernetes locais compostos por vários nós.
Kind é uma ferramenta para executar clusters Kubernetes locais usando contêineres Docker como "nós". O Kind foi projetado principalmente para testar o próprio Kubernetes, mas também pode ser usado para desenvolvimento local ou CI (Integração Contínua).
O Kind vem com um CNI (Container Network Interface) padrão chamado kindnet. Este CNI simples cuida das noções básicas de rede, mas não suporta recursos avançados como NetworkPolicy.
Visão Geral do Cilium
Cilium é uma CNI moderna e avançada para Kubernetes, implementada sobre o eBPF, que foca em desempenho, segurança e observabilidade.
Cilium é um software de código aberto para fornecer, proteger e observar a conectividade de rede entre cargas de trabalho em contêineres — nativo da nuvem e alimentado pela revolucionária tecnologia do Kernel, eBPF.
NetworkPolicy padrão, bem como as mais avançadas CiliumNetworkPolicy e CiliumClusterwideNetworkPolicy, são suportadas. Ele oferece capacidades de múltiplos clusters, permite a observação das atividades de rede e muito mais.
Combinando Kind e Cilium
Felizmente, o Kind pode ser configurado para usar outra CNI além do kindnet. Neste artigo, vamos passar pelos passos necessários para usar o Cilium CNI em clusters alimentados pelo Kind.
Uma característica do Cilium é que ele pode substituir completamente o kube-proxy. Com a configuração correta, os clusters do Kind podem ser configurados para usar a Cilium CNI e funcionar com o kube-proxy
desativado.
Executar um cluster desse tipo localmente ajuda a configurar um ambiente local mais próximo de um cluster de produção real. Isso nos permite testar coisas que não poderiam ser testadas com o kindnet.
Um cluster sem CNI e com kube-proxy desativado
Ao criar um cluster Kind, é possível fornecer uma especificação do cluster com a configuração do cluster. A seção de rede permite configurar a CNI padrão do cluster e outros componentes do cluster.
Executar o comando abaixo irá iniciar um cluster sem kindnet e não instalará o kube-proxy:
Observação: Por experiência própria, pode ocorrer um erro ao tentar criar esse cluster se você não tiver uma máquina tão potente ou com pouco recurso disponível. É recomendado diminuir a quantidade de workers.
kind create cluster --config - <<EOF
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
networking:
disableDefaultCNI: true # não instala kindnet
kubeProxyMode: none # não executa kube-proxy
nodes:
- role: control-plane
- role: worker
- role: worker
- role: worker
EOF
Claro, esse cluster não será utilizável. Os nós permanecerão no estado NotReady
até que uma CNI seja instalada. Você pode verificar o status dos nodes executando o comando kubectl get nodes
:
NAME STATUS ROLES AGE VERSION
kind-control-plane NotReady control-plane,master 57s v1.27.3
kind-worker NotReady <none> 21s v1.27.3
kind-worker2 NotReady <none> 21s v1.27.3
kind-worker3 NotReady <none> 21s v1.27.3
Instalar Cilium
Instalar o Cilium no cluster criado anteriormente deve ajudar a tornar o cluster utilizável. No entanto, não será tão simples.
Como o kube-proxy
não está em execução, não é possível se comunicar com o API server usando o Kubernetes service dentro do cluster.
Observação: Caso não funcionem a instalação, é sempre bom verificar a documentação do Cilium.
Por enquanto, vamos instalar o Cilium e ver onde as coisas falham. O Cilium pode ser instalado com Helm e junto a uma configuração:
helm upgrade --install --namespace kube-system --repo https://helm.cilium.io cilium cilium --values - <<EOF
kubeProxyReplacement: true
hostServices:
enabled: false
externalIPs:
enabled: true
nodePort:
enabled: true
hostPort:
enabled: true
image:
pullPolicy: IfNotPresent
ipam:
mode: kubernetes
hubble:
enabled: true
relay:
enabled: true
EOF
Neste ponto, o Cilium deve começar a ser instalado no cluster:
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system cilium-6szjr 0/1 Running 0 7s
kube-system cilium-operator-6fb8dbd88c-2p4mv 1/1 Running 0 7s
kube-system cilium-operator-6fb8dbd88c-mdrg9 1/1 Running 0 7s
kube-system cilium-sw9d5 0/1 Running 0 7s
kube-system cilium-zxgfx 0/1 Running 0 7s
Infelizmente, os pods do cilium-operator e dos agents do Cilium nunca se tornarão Ready
e reiniciarão continuamente:
kube-system cilium-operator-6fb8dbd88c-2p4mv 0/1 Error 4 6m43s
kube-system cilium-operator-6fb8dbd88c-2p4mv 0/1 CrashLoopBackOff 4 6m50s
kube-system cilium-6szjr 0/1 Error 1 2m10s
kube-system cilium-zxgfx 0/1 Error 1 2m10s
kube-system cilium-sw9d5 0/1 Error 1 2m10s
kube-system cilium-6szjr 0/1 CrashLoopBackOff 1 2m12s
kube-system cilium-zxgfx 0/1 CrashLoopBackOff 1 2m12s
kube-system cilium-sw9d5 0/1 CrashLoopBackOff 1 2m12s
kube-system cilium-operator-6fb8dbd88c-mdrg9 1/1 Running 3 6m59s
kube-system cilium-dqknq 0/1 Error 1 2m10s
kube-system cilium-dqknq 0/1 CrashLoopBackOff 1 2m12s
Analisar os logs do operador ou dos agentes explicará o que está acontecendo:
level=info msg="Cilium Operator 1.11.1 76d34db 2022-01-18T15:52:51-08:00 go version go1.17.6 linux/amd64" subsys=cilium-operator-generic
level=info msg="Establishing connection to apiserver" host="https://10.96.0.1:443" subsys=k8s
level=info msg="Starting apiserver on address 127.0.0.1:9234" subsys=cilium-operator-api
level=info msg="Establishing connection to apiserver" host="https://10.96.0.1:443" subsys=k8s
level=error msg="Unable to contact k8s api-server" error="Get \"https://10.96.0.1:443/api/v1/namespaces/kube-system\": dial tcp 10.96.0.1:443: connect: connection refused" ipAddr="https://10.96.0.1:443" subsys=k8s
level=fatal msg="Unable to connect to Kubernetes apiserver" error="unable to create k8s client: unable to create k8s client: Get \"https://10.96.0.1:443/api/v1/namespaces/kube-system\": dial tcp 10.96.0.1:443: connect: connection refused" subsys=cilium-operator-generic
O operador e os agentes não conseguem se comunicar com o node control plane do Kubernetes. Isso ocorre porque o kube-proxy
não está instalado no cluster e, portanto, o Kubernetes service dentro do cluster não pode ser alcançado.
Configurar o endpoint do Kubernetes service para Cilium
Para resolver o problema anterior em que os pods do Cilium não conseguem se conectar ao API server do Kubernetes, precisamos configurar o API server do cluster para ouvir em um endereço IP que possa ser acessado pelos pods do Cilium.
O Kind executa os nodes do cluster em contêineres Docker em uma rede dedicada. Os contêineres em execução na rede do kind podem resolver os endereços IP de outros contêineres pelo nome.
Se observarmos os contêineres Docker iniciados pelo Kind com o comando docker ps
, deveríamos ver algo assim:
CONTAINER ID IMAGE NAMES
b4badebf3db8 kindest/node:v1.27.3 kind-worker3
195cfd2b59e7 kindest/node:v1.27.3 kind-worker
81de0b8dbf18 kindest/node:v1.27.3 kind-control-plane
9f4b82ee120b kindest/node:v1.27.3 kind-worker2
O contêiner kind-control-plane
é nosso nó mestre do Kubernetes e executa o API server (na porta 6443). Enquanto estivermos nos contêineres em execução na rede do kind, o nome kind-control-plane
deve ser resolvível. Podemos usá-lo para configurar o endpoint do API server do Kubernetes usado pelos pods do Cilium:
helm upgrade --install --namespace kube-system --repo https://helm.cilium.io cilium cilium --values - <<EOF
kubeProxyReplacement: true
k8sServiceHost: kind-control-plane # node mestre na rede do kind
k8sServicePort: 6443 # porta do API server
hostServices:
enabled: false
externalIPs:
enabled: true
nodePort:
enabled: true
hostPort:
enabled: true
image:
pullPolicy: IfNotPresent
ipam:
mode: kubernetes
hubble:
enabled: true
relay:
enabled: true
EOF
Após algum tempo, os pods do Cilium e os nodes do cluster devem se tornar Ready
.
Instalar um ingress controller
Neste ponto, o cluster deve estar em execução, utilizando Cilium CNI, sem kube-proxy
, e tudo deve funcionar conforme o esperado.
Para obter algo útil dele, agora devemos instalar um ingress controller e o Cilium Hubble UI para visualizar a rede no cluster.
Vamos instalar o ingress-nginx
e usar o nip.io para acessar o Hubble UI em execução dentro do cluster.
Isso requer configurar a especificação do cluster kind para expor portas adicionais do host e permitir que nosso ingress controller receba tráfego:
kind delete cluster && kind create cluster --config - <<EOF
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
networking:
disableDefaultCNI: true
kubeProxyMode: none
nodes:
- role: control-plane
kubeadmConfigPatches:
- |
kind: InitConfiguration
nodeRegistration:
kubeletExtraArgs:
node-labels: "ingress-ready=true"
extraPortMappings:
- containerPort: 80
hostPort: 80
listenAddress: 127.0.0.1
protocol: TCP
- containerPort: 443
hostPort: 443
listenAddress: 127.0.0.1
protocol: TCP
- role: worker
- role: worker
- role: worker
EOF
Você pode conferir a nova label atraves de kubectl get nodes --show-labels=true
NAME STATUS ROLES AGE VERSION LABELS
kind-control-plane Ready control-plane 13h v1.27.3 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,ingress-ready=true,kubernetes.io/arch=amd64,kubernetes.io/hostname=kind-control-plane,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node.kubernetes.io/exclude-from-external-load-balancers=
kind-worker Ready <none> 13h v1.27.3 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=kind-worker,kubernetes.io/os=linux
kind-worker2 Ready <none> 13h v1.27.3 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=kind-worker2,kubernetes.io/os=linux
kind-worker3 Ready <none> 13h v1.27.3 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=kind-worker3,kubernetes.io/os=linux
Instale o Cilium com o Hubble UI habilitado e acessível em ingress hubble-ui.127.0.0.1.nip.io:
helm upgrade --install --namespace kube-system --repo https://helm.cilium.io cilium cilium --values - <<EOF
kubeProxyReplacement: true
k8sServiceHost: kind-control-plane
k8sServicePort: 6443
hostServices:
enabled: false
externalIPs:
enabled: true
nodePort:
enabled: true
hostPort:
enabled: true
image:
pullPolicy: IfNotPresent
ipam:
mode: kubernetes
hubble:
enabled: true
relay:
enabled: true
ui:
enabled: true
ingress:
enabled: true
annotations:
kubernetes.io/ingress.class: nginx
hosts:
- hubble-ui.127.0.0.1.nip.io
EOF
Por fim, instale o ingress controller ingress-nginx
:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.1.1/deploy/static/provider/kind/deploy.yaml
Observação: Talvez seja necessário alterar as tolerations para garantir que o ingress controller seja agendado corretamente nos nós do cluster. Você pode fazer isso adicionando a seguinte configuração ao seu pod:
kubectl edit deploy -n ingress-nginx ingress-nginx-controller
tolerations:
- effect: NoSchedule
key: node-role.kubernetes.io/control-plane
operator: Equal
Após algum tempo:
- Os pods do Cilium devem ficar
Ready
- O ingress controller
ingress-nginx
deve ser escalonado no cluster - O Hubble UI deve ser acessível em http://hubble-ui.127.0.0.1.nip.io 🎉
Top comments (0)