Networking no Kubernetes sempre foi motivo de debates complexos, e de difíceis soluções. Esse assunto é capaz de fazer com que profissionais levem dias para entender e resolver problemas. Afinal, quem nunca teve problemas para entender como os pods se comunicam? Como um pod se comunica com outro através de um service? O que é um Ingress e como o usuário externo acessa um serviço no cluster? E network policies para aumentar a segurança do cluster? E o coredns então!? Que sofrimento!
Isto ocorre com frequência, pois ainda há a necessidade de aprimorar o background em redes ou o sistema operacional, conhecimentos essenciais para um profissional de TI atualmente. O mesmo ocorre com outros componentes, onde o desenvolvedor é quem sofre.
Mas com o constante crescimento dos projetos e cada vez mais deploys acontecendo, existe outro tema que vem trazendo muita dor de cabeça nos administradores de clusters em Kubernetes: a exaustão de IP’s do cluster. Quando falamos de alocação de IP, estamos abordando especificamente no que diz respeito à adoção e configuração de plugins de CNI (Container Network Interface), que é basicamente o componente que define a configuração de network para seus pods e containers. A CNCF define CNI da seguinte maneira:
“CNI (Container Network Interface), a Cloud Native Computing Foundation project, consists of a specification and libraries for writing plugins to configure network interfaces in Linux containers, along with a number of supported plugins. CNI concerns itself only with network connectivity of containers and removing allocated resources when the container is deleted. Because of this focus, CNI has a wide range of support and the specification is simple to implement.”
Hoje no mercado existem diversos projetos que criam plugins CNI e que podem ser utilizados no seu cluster de Kubernetes, abaixo cito alguns que já utilizei e testei:
• Calico CNI Plugin
• Flannel
• Weave Net
E como isso funciona na AWS?
A vantagem de adotar clouds públicas, especialmente a AWS, é que você não precisa se preocupar em instalar estes plugins, pois seu cluster os possui nativamente com um plugin de CNI. No caso do Amazon EKS, a AWS implementa seu próprio plugin de CNI para funcionar em conjunto com seu principal componente de rede: a VPC.
O plugin de CNI da AWS é chamado vpc-cni e pode ser explorado no repositório público que a AWS mantém no GitHub. O endereço é: https://github.com/aws/amazon-vpc-cni-k8s.
O vpc-cni é basicamente um plugin que atua por meio de APIs da AWS, criando ENI, alocando IP’s e orquestrando isso com a criação de pods. É de extrema importância relembrar que a ENI é atrelada a uma instância do seu cluster e que as instâncias têm limites de ENI e a quantidade de IP’s por ENI. A relação tipo de instância x quantidade de ENI pode ser conferida aqui:
https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-eni.html#AvailableIpPerENI
A imagem abaixo ilustra o fluxo do vpc-cni dentro de um nó do seu cluster:
E o problema de exaustão de IP?
Antes de abordarmos esse tema, é importante lembrar que o dimensionamento correto de suas subnets deve sempre ser levado em consideração durante a definição de sua arquitetura.
Bem, começamos a ingressar na complexidade do funcionamento do vpc-cni que pode causar a exaustão de IP’s dentro da sua subnet, principalmente na hora que você mais precisa: o momento de escalar rapidamente.
O que acontece por debaixo dos panos, é que o vpc-cni não é instalado sozinho com a missão de prover IP’s pros seus pods. A AWS também faz a instalação do L-IPAM (ipamd), que tem um papel extremamente importante no seu cluster: alocar IP’s secundários na ENI do nó com a finalidade de manter IP’s quentes (WARM-POOL) para serem alocados rapidamente quando um pod precisar ser criado.
Imagine o seguinte cenário: você tem um cluster que tem 1 pod rodando e rapidamente precisa criar mais 10 novos para escalar seu serviço. Quais seriam os possíveis comportamentos?
1. Caso o L-IPAM (ipamd) (instalado no pod aws-node) não existisse em seu cluster, o seu nó teria que fazer uma chamada de API para a AWS para alocar um novo IP secundário naquela ENI e disponibilizar para seu POD. O ponto é que com 10 pods, isso pode até ir bem, mas imagine com 100, 1000 pods? A API de chamada para a AWS poderia sofrer throttling ou até mesmo falhar, assim você teria problemas na criação de novos pods.
2. Como o L-IPAM (ipamd) (instalado no pod aws-node ) existe no seu cluster, então já existe um pool de IP’s secundários e que podem ser atribuídos imediatamente para os seus novos pods, tornando o fluxo mais rápido e resiliente.
Vamos ver na prática como isso funciona e como a AWS trabalha:
Criamos um cluster simples com 2 subnets públicas e 1 nó com uma EC2 m5.2xlarge apenas para efeito de análise. Este tipo de instância suporta 4 ENI’s e 15 IP’s alocados em cada ENI.
Após o cluster criado, a AWS instala alguns componentes dela, que criam pods, o que consequentemente consome IP. Vamos a análise:
Subnet
Antes de criar o “computer nodegroup” no EKS, eu criei 2 subnets num /24, o que me dá 250 IP’s disponíveis para uso na AWS, conforme imagem abaixo.
ATENÇÃO: A AWS aloca alguns IP’s da sua VPC para uso interno, confira aqui.
Nodegroup criado
Conforme informado acima, foi criado um nodegroup com apenas 1 instância EC2 m5.2xlarge e os IP’s disponíveis para uso baixaram de 250 para 220. E aí você deve se perguntar, mas porquê? É isso que vamos explicar agora. Abaixo deixamos uma sequência de imagens para demonstrar o consumo de IP’s que o EKS alocou, mesmo sem recursos em uso.
Node group criado.
30 IP’s consumidos.
Apenas 4 pods deployados.
E onde estão esses IP’s?
Lembra que anteriormente falamos do papel o L-IPAM (ipamd) de alocar IP’s adicionais em uma ENI para ajudar no rápido provisionamento de pods? Pois é, ele é o motivo pelo qual foram consumidos 30 IP’s da subnet mesmo sem recursos deployados. Se formos ao painel da AWS e procurarmos pela instância que faz parte do nodegroup, veremos que o L-IPAM (ipamd) alocou uma série de IP’s secundários em nossa ENI, o que causa um super provisionamento de IP’s da subnet e um potencial risco de exaustão de IP na subnet.
IP’s provisionados pelo L-IPAM
ATENÇÃO: vale a pena ressaltar que isso não é 100% ruim, em um cenário que você tem pods pequenos e precisa os escalar rapidamente, ter IP’s alocados para o nó pode ser uma excelente estratégia. Só é preciso cuidado.
E como a exaustão de IP ocorre?
Imagine que você precisa subir mais nós de EC2 no mesmo cluster, pois seus pods são grandes e precisam de mais recursos. Isto pode levar a uma rápida exaustão de IP, pois se cada nó subir alocando 30 IP’s da subnet, os novos nós não terão mais IP’s para alocar na subnet.
O exemplo relatado acima é um caso comum do que chamamos de “fragmentação de IP’s em ENI’s”, pois o L-IPAM (ipamd) vai alocar um número X de IP’s para aquela ENI e só vai utiliza 2 ou 3, fazendo com que uma grande quantidade de IP não seja utilizado, porém está alocado.
Vejam este exemplo que está no próprio repositório do GitHub da AWS demonstrando IP’s não utilizados:
IP’s não utilizados por ENI
E como resolver de imediato?
O primeiro pensamento seria mudar o tipo da instância, de modo manter um número menor de WARM-POOL, mas isso poderia te trazer outros problemas. A tabela abaixo demonstra a relação entre IPs, memória RAM, ECU (Unidade de CPU usada pela AWS) para alguns tipos de instâncias:
* ECU estimado para alguns tipos de instâncias
Notem que dependendo do seu tipo de aplicação, perfil consumo de recursos de pods, pode ser mais eficiente (econômico) usar determinados tipos de instância. Utilize o projeto Kubernetes Instance Calculator para verificar a melhor relação custo x benefício de instância para utilizar.
Mas agora chegamos em um estágio interessante em que aparece o questionamento: como provisionar meus nós de forma que o L-IPAM (ipamd) não seja um problema e sim uma solução?
Ainda bem que a AWS pensou nisso e nos dá a opção de gerenciar estes recursos em nossos nós e configurar conforme nossa necessidade. Basicamente existe um parâmetro que podemos alterar em nosso cluster e que fará com que o gerenciamento e alocação de IP’s seja mais otimizado. Vamos falar dele:
WARM_IP_TARGET
Este parâmetro especifica o número de endereços IP livres que o L-IPAM (ipamd) deve tentar manter disponíveis para atribuição de pod no nó, ou seja, ele sempre vai manter o número de IP’s anexados a ENI utilizando a seguinte lógica: IP’s utilizados + IP’s definidos no parâmetro WARM_IP_TARGET.
Qual valor colocar no WARM_IP_TARGET?
Este não é um número mágico que eu vou poder te falar o quanto utilizar, pois isso varia muito de acordo com as necessidades de cada arquitetura. No caso abaixo vamos imaginar que precisamos deixar apenas 5 IP’s quentes no L-IPAM (ipamd) pois sabemos que nosso nó só suporta mais 5 pods da nossa aplicação.
ATENÇÃO: O comando abaixo vai fazer com que o pod “aws-node” (deployado através de um DaemonSet) do seu cluster reinicie, o que pode gerar indisponibilidade da sua aplicação por alguns segundos.
Execute o seguinte comando:
kubectl set env ds aws-node -n kube-system WARM_IP_TARGET=5
Após o comando executar e o pod reiniciar, observem como ficou a alocação de IP’s.
241 IP’s livres na subnet
Menos IP’s alocados na ENI do nó do cluster
Após a execução deste comando o ideal é drenar os nós para que o EKS refaça a distribuição de pods e otimize mais ainda o uso das suas ENI, pois o scheduler vai distribuir os pods entre os nós e utilizar melhor os IP’s disponíveis.
Outras possíveis soluções
• Utilizar instâncias menores que vão consumir menos IP’s nas ENI
• Instalar outro plugin de CNI
• Reconfigurar seus deployments para utilizarem o máximo de recursos disponível em um nó.
Espero que tenham gostado do artigo e deixem seus comentários em caso de dúvidas. Abaixo deixo nossos contatos
https://twitter.com/FlavioRescia
https://linkedin.com/in/FlavioRescia
https://twitter.com/LeoCDamascena
https://www.linkedin.com/in/leandrodamascena/
https://github.com/leandrodamascena
Referências
1. AWS VPC CNI: Pod networking (CNI) — Amazon EKS
2. amazon-vpc-cni-k8s/eni-and-ip-target.md at master · aws/amazon-vpc-cni-k8s (github.com)