Pular para o conteúdo principal

EKS - eksctl

https://tf-eks-workshop.workshop.aws/> https://aws.amazon.com/pt/eks/>

O Amazon Elastic Kubernetes Service (EKS) é o kubernetes as a service da AWS.

Um bom lugar para aprender alguns recursos é fazer o workshop do eks

Tanto o EKS quanto o kOps utilizam instâncias EC2 para a força computacional. Para usar clusters pequenos ou temporários talvez o kOps tenha suas vantagens principalmente em relação a custos, pois você poderia usar instâncias spot, mas para clusters de alta carga, usar o EKS pode ser mais lucrativo.

Mais uma lembrança é que utilizar o EKS te garante o suporte do time da AWS que está também empenhado em corrigir falhas de segurança que você teria que fazer por conta própria usando o kOps.

O EKS oferece uma ferramenta CLI, eksctl, para gerenciar e criar cluster na AWS de forma rápida e simples como o kOps.

Também é possível subir um cluster EKS utilizando o Terraform como faremos por aqui, mas também utilizaremos uma amostra do eksctl. Além disso pode ser usado o console da AWS e o CloudFormation, que não é muito interessante na minha opinião.

Recomendo aprender primeiro via eksctl, pois um bom estudo dessa CLI trará conhecimento primeiro sobre o EKS e tudo que podemos fazer, para depois com esse conhecimento aplicá-lo no Terraform.

Para acompanhar a evolução do eks https://github.com/aws/containers-roadmap/issues

Vantagens e Desvantagens

Uma vantagem do EKS é que ele atualiza os control plane (masters), sem tempo de inatividade, que é um grande diferencial em sistemas críticos. No caso do kOps você deve verificar e monitorar o processo de atualização e corrigir manualmente os problemas que acompanham essa operação.

O kOps suporta muitos CNIs diferentes, já o EKS somente o VPC CNI. Isso significa que você pode integrar o cluster Kubernetes às redes existentes por meio da rede nativa da AWS.

EKS não dá acesso aos masters, ou seja, não podemos controlar o API Server, Controller Manager, etcd, Scheduler. Isso significa que não podemos fazer várias coisas como mostrado abaixo, já o kOps te dá toda a liberdade de fazer o que quiser. A AWS está trabalhando para que algumas coisas sejam possíveis, talvez no futuro veremos um melhor controle do cluster.

  • Sinalizadores OIDC personalizados
  • Configuração de HPA
  • CRI personalizado
  • etc

O uso do EKS garante alta disponibilidade para o etcd e masters, e isso você não precisa se preocupar, o que é o pior caso na gerência de um cluster Kubernetes.

A própria AWS aplica patches de segurança automaticamente para os masters.

Integração com outros serviços da AWS.

A portabilidade é um outro fator que deve ser levado em conta. Já no caso do kOps é relativamente mais fácil criar um cluster em outra cloud. Mas você vai realmente operar em multi-cloud? A AWS oferece o EKS Distro que pode ser usado para instalar o Kubernetes em bare metal, VMs ou EC2. Um fator de desvantagem é que o uso do EKS limita você a produtos relacionados à AWS.

Dependendo do domínio de Kubernetes do seu time é realmente interessante utilizar o EKS uma vez que muitas coisas são gerenciadas para você, tornando sua entrega mais confiável e demandando menos tempo para outras atividades.

Uma vantagem que vejo é poder deployar um Kubernetes com suporte ao AWS Fargate. Isso significa não ter nós workers e todo container do Kubernetes estará no Fargate podendo ser escalado à vontade sem limites, mas com algumas limitações.

eksctl

https://eksctl.io/

O eksctl não é um cli da AWS, ele foi criado pela Weaveworks em golang. Apesar dessa ferramenta não ser da AWS é a ferramenta oficial e recomendada pela própria AWS para criação do cluster. Por baixo do capô ele utiliza o cloudformation.

Instalação

Para outras instalação diferentes do linux conferir a página https://docs.aws.amazon.com/eks/latest/userguide/eksctl.html

curl --silent --location "https://github.com/weaveworks/eksctl/releases/latest/download/eksctl_$(uname -s)_amd64.tar.gz" | tar xz -C /tmp
sudo mv /tmp/eksctl /usr/local/bin
sudo chmod +x /usr/local/bin/eksctl
eksctl version

Requisitos

Criando o cluster com eksctl

Leia tudo antes de aplicar...Se vc executar o comando

eksctl create cluster

Por default ele cria o seguinte de acordo com a documentação:

  • Um nome auto gerado = fabulous-mushroom-XXXXXXX
  • 2 m5.large para os nós workers
  • Vai utilizar como base de ami desses workers o EKS AMI
  • Na região us-west-2
  • Vai criar um vpc dedicada para isso.

Podemos criar um arquivo yaml de configuração que ele irá ler e preencher automagicamente todos os campos da cli como. O parâmetro -f de file o path do arquivo de configuração. Crie o arquivo como o yaml abaixo.

É seguida a mesma estrutura dos manifestos do k8s se prestar atenção.

apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
name: company-cluster
region: us-east-2

nodeGroups:
- name: ng-1
instanceType: m5.large
desiredCapacity: 1
- name: ng-2
instanceType: t3.large
desiredCapacity: 1

Existem vários exemplo aqui https://github.com/weaveworks/eksctl/tree/main/examples com tudo que é possível declarar. Para permitir o acesso SSH aos workers nodes, eksctl importa ~/.ssh/id_rsa.pub por padrão, para usar uma chave pública SSH diferente, por exemplo my_eks_node_id.pub aponte a chave correta com a flag --ssh-access --ssh-public-key=my_eks_node_id.pub.

Vou usar a minha mesmo para facilitar

eksctl create cluster -f cluster.yaml

Recomendo fortemente ao invés de passar os parametros pela cli colocar tudo no arquivo yaml para saber o que de fato foi feito e caso venha a mexer no futuro somente alterar o arquivo.

Observe a saída e veja o que ele está criando e veja a utilização do cloudformation em ação.

Uma desvantagem que eu vejo nesse yaml é que se quisermos usar alguns recursos específicos já criados, precisamos apontar o ID e no uso do terraforms podemos pegar esses ids de forma muito mais tranquila, pois ficam amazenados nos states.

Observe ao final da instalação uma saída parecida com essa.

1H6XYJF5VZCPU" to auth ConfigMap
2022-08-08 11:28:24 [ℹ] nodegroup "ng-2" has 0 node(s)
2022-08-08 11:28:24 [ℹ] waiting for at least 1 node(s) to become ready in "ng-2"
2022-08-08 11:29:18 [ℹ] nodegroup "ng-2" has 1 node(s)
2022-08-08 11:29:18 [ℹ] node "ip-192-168-55-204.us-east-2.compute.internal" is ready
2022-08-08 11:29:22 [ℹ] kubectl command should work with "/home/david/.kube/config", try 'kubectl get nodes'
2022-08-08 11:29:22 [✔] EKS cluster "my-company-lab" in "us-east-2" region is ready

O próprio eksctl adiciona ao seu .kube/config as informações de acesso ao cluster para uso do kubectl.

Depois de finalizado, confirme o cluster com

❯ eksctl get cluster
NAME REGION EKSCTL CREATED
my-company-lab us-east-2 True

Agora no kubectl....

Se vc não tiver o kubectl vc deve começar novamente o estudo do kubernetes pois ele é a cli necessária. Acorda pra vida.

Observe também que vc pode trocar o contexto do seu kubectl para apontar para esse cluster quando executar o kubectl na sua máquina.

kubectl config set-context [email protected]@my-company-lab.us-east-2.eksctl.io

#### Veja que ele só mostra os workers
❯ kubectl get nodes
NAME STATUS ROLES AGE VERSION
ip-192-168-48-238.us-east-2.compute.internal Ready <none> 29m v1.22.9-eks-810597c
ip-192-168-55-204.us-east-2.compute.internal Ready <none> 29m v1.22.9-eks-810597c

❯ kubectl get namespaces
NAME STATUS AGE
default Active 48m
kube-node-lease Active 48m
kube-public Active 48m
kube-system Active 48m

❯ kubectl get pods --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system aws-node-gmtgb 1/1 Running 0 26m
kube-system aws-node-rslfx 1/1 Running 0 26m
kube-system coredns-5db97b446d-dnnwj 1/1 Running 0 36m
kube-system coredns-5db97b446d-lcr4p 1/1 Running 0 36m
kube-system kube-proxy-2sj68 1/1 Running 0 26m
kube-system kube-proxy-74ftr 1/1 Running 0 26m

Pronto... agora vc só de sair utilizando! Mas veja no console da AWS as coisas criadas.

Agora vamos atualizar esse cluster para ter um suporte ao fargate também. Utilize o mesmo cluster.yaml e adiciona ao final o yaml abaixo. No caso para não perder o arquivo anterior coloquei clusterfargate.yaml

fargateProfiles:
- name: fp-default
selectors:
# All workloads in the "default" Kubernetes namespace will be
# scheduled onto Fargate:
- namespace: default
# All workloads in the "kube-system" Kubernetes namespace will be
# scheduled onto Fargate:
- namespace: kube-system
- name: fp-dev
selectors:
# All workloads in the "dev" Kubernetes namespace matching the following
# label selectors will be scheduled onto Fargate:
- namespace: dev
labels:
env: dev
checks: passed

Um detalhe importante é que o upgrade do cluster só é feito baseado na versão se fosse declado em metadata a tag version: "1.21". Para qualquer outro recursos ou addon é feito novamente um create que no caso ele cria as diferenças. Utilizar o fargate ao invés de criar nodes é uma ótima ideia para diminuir custo e não ter um cluster fechado ou esperar um provisionamento de uma máquina para suportar mais pods.

❯ eksctl create fargateprofile -f clusterfargate.yaml
2022-08-08 16:01:45 [] creating Fargate profile "fp-default" on EKS cluster "my-company-lab"
2022-08-08 16:03:55 [] created Fargate profile "fp-default" on EKS cluster "my-company-lab"
W0808 16:03:56.987291 462617 warnings.go:70] spec.template.spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[0].matchExpressions[0].key: beta.kubernetes.io/os is deprecated since v1.14; use "kubernetes.io/os" instead
W0808 16:03:56.987317 462617 warnings.go:70] spec.template.spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[0].matchExpressions[1].key: beta.kubernetes.io/arch is deprecated since v1.14; use "kubernetes.io/arch" instead
2022-08-08 16:03:56 [] "coredns" is now schedulable onto Fargate
2022-08-08 16:05:01 [] "coredns" is now scheduled onto Fargate
2022-08-08 16:05:02 [] "coredns" pods are now scheduled onto Fargate

Se vc entendeu isso podemos eliminar o nodes agora criados.

❯ eksctl delete nodegroup -f clusterfargate.yaml --approve
2022-08-08 16:14:28 [] comparing 2 nodegroups defined in the given config ("clusterfargate.yaml") against remote state
2022-08-08 16:14:28 [] 2 nodegroups (ng-1, ng-2) were included (based on the include/exclude rules)
2022-08-08 16:14:30 [] will drain 2 nodegroup(s) in cluster "my-company-lab"
2022-08-08 16:14:30 [] starting parallel draining, max in-flight of 1
2022-08-08 16:14:31 [] cordon node "ip-192-168-55-204.us-east-2.compute.internal"
2022-08-08 16:14:31 [] cordon node "ip-192-168-48-238.us-east-2.compute.internal"
2022-08-08 16:14:32 [] drained all nodes: [ip-192-168-55-204.us-east-2.compute.internal]
2022-08-08 16:14:33 [] drained all nodes: [ip-192-168-48-238.us-east-2.compute.internal]
2022-08-08 16:14:33 [] will delete 2 nodegroups from cluster "my-company-lab"
2022-08-08 16:14:33 [] 1 task: {
2 parallel tasks: { delete nodegroup "ng-1" [async], delete nodegroup "ng-2" [async]
} }2022-08-08 16:14:34 [] will delete stack "eksctl-my-company-lab-nodegroup-ng-2"
2022-08-08 16:14:34 [] will delete stack "eksctl-my-company-lab-nodegroup-ng-1"
2022-08-08 16:14:34 [] will delete 2 nodegroups from auth ConfigMap in cluster "my-company-lab"
2022-08-08 16:14:34 [] removing identity "arn:aws:iam::513498712583:role/eksctl-my-company-lab-nodegroup-n-NodeInstanceRole-LY2XR5HQ37N2" from auth ConfigMap (username = "system:node:{{EC2PrivateDNSName}}", groups = ["system:bootstrappers" "system:nodes"])
2022-08-08 16:14:34 [] removing identity "arn:aws:iam::513498712583:role/eksctl-my-company-lab-nodegroup-n-NodeInstanceRole-1H6XYJF5VZCPU" from auth ConfigMap (username = "system:node:{{EC2PrivateDNSName}}", groups = ["system:bootstrappers" "system:nodes"])
2022-08-08 16:14:35 [] deleted 2 nodegroup(s) from cluster "my-company-lab"

~/p/p/study-kubernetes/I/EKS develop +43 !1 ?4
❯ kubectl get nodes
NAME STATUS ROLES AGE VERSION
fargate-ip-192-168-153-220.us-east-2.compute.internal Ready <none> 10m v1.22.6-eks-14c7a48
fargate-ip-192-168-173-179.us-east-2.compute.internal Ready <none> 10m v1.22.6-eks-14c7a48
ip-192-168-48-238.us-east-2.compute.internal Ready,SchedulingDisabled <none> 4h46m v1.22.9-eks-810597c
ip-192-168-55-204.us-east-2.compute.internal Ready,SchedulingDisabled <none> 4h46m v1.22.9-eks-810597c

Se vc observar bem deletamos um recurso que estava definido no clusterfargate.yaml. Nesse caso vc pode deletar de nodes depois que deletar o recurso.

Esse é o diferencial do EKS, não ter workers nodes se vc não quiser, porém há um pecado nisso! Voce perde algumas outras funcionalidade do k8s como DaemonSet que é super importante é várias coisas como logs, observability, service mesh, etc. O EKS já te tira algumas poderes e ainda quer perder esse?

Para voltar ao padrão crie novamente os nodegroups e delete o fargate.

eksctl create nodegroup -f clusterfargate.yaml
eksctl delete fargateprofile fp-default -f clusterfargate.yaml

E temos novamente o nosso cluster.yaml sendo o ideal.

Configuração padrão

Por default se não for declarado nada extra no seu arquivo de configuração o eksctl criará:

  • Usará a região declarada na variável AWS_DEFAULT_REGION
  • 2 nodes workers m5.large em gerenciado pelo eks
  • 1 vpc dedicada com cidr 192.168.0.0/16 divida em:
    • 3 subnet publicas /19
    • 3 subnets privadas /19
    • 2 subnetes reservadas /19
  • security group permitindo acesso dos control planes das portas 1025 até 65535
  • Usará ami do amazon linux
  • Docker como container runtime
  • VPC CNI para criação das redes do kubernetes
  • Não irá permitir o ssh
  • Já automaticamente injetará o kubeconfig no ~/.kube/config
  • Expoe a api do kubernetes para acesso externo 0.0.0.0

Se não for passado a configuração da máquina, ele usará m5.large, cuidado.

eksctl create cluster

Melhorias a considerar na configuração do cluster

Mas ainda podemos melhorar bem o nosso cluster yaml. Podemos definir mais coisas interessantes do nosso cluster. Basta ver o schema do arquivo em https://eksctl.io/usage/schema/.

Kubelet and System CPU and Memory Reservations

-Evitar que um host utilize todo o seu sistema computacional é uma boa prática. Por exemplo podemos reservar um valor X de cpu e Y de memória para garantir uma boa saúde dos daemons rodando no sistema operacional do node como por exemplo sshd, ou algum daemon que roda no host. Um host m5 large por exemplo tem 4 cpu e 8gb de ram. Podemos garantir 200m cpu e 200mb de memória. Do mesmo modo se vc vai deployar outros tops do sistema kubernetes como daemonset poderá fazer uso de recursos para o kubelet, nesse caso um istio para service mesh e prometheus. Vamos reservar 300m cpu e 300m de memória. O que ficará disponíbel é 3.5 cpu 7.5 gb de ram para o kubelet consumir com pods extras.

Se vc deployar máquinas pequenas demais em cada uma das máquinas terá esse recurso reservado, nos mesmos grupos de nodes, logo é necessário encontrar o ponto ótimo para o seu sistema. Isso demanda tempo e conhecimento se a aplicação usa mais cpu, mais memória, mais disco, etc.

Outra situação a se pensar é ter grupo de nodes para dev e master separado. É uma questão de avaliação?

O yaml que defini o cluster nos dá a possibilidade de garantir um recurso mínimo para o kubelet rodar nos workers. É boa prática definir esse recurso.

Isso é valido para qualquer uma instalação do kubernetes.

nodeGroups:
- name: ng-prod
...
kubeletExtraConfig:
kubeReserved: # Servervado para o K8s
cpu: "300m"
memory: "300Mi"
ephemeral-storage: "1Gi"
kubeReservedCgroup: "/kube-reserved"
systemReserved: Servervado para os serviços do SO
cpu: "200m"
memory: "300Mi"
ephemeral-storage: "1Gi"
evictionHard: # Irá dropar Alguma coisa quando chegar nessa zona de segurança
memory.available: "200Mi"
nodefs.available: "10%"
featureGates: # Irá fazer a rotação do certificado
RotateKubeletServerCertificate: true

Container runtime

https://eksctl.io/usage/container-runtime/

Por padrão é utilizado o docker como container runtime. Podemo mudar para containerd, mas sómente é suportado no amazonlinux por enquanto.

nodeGroups:
- name: ng-prod
containerRuntime: containerd
amiFamily: AmazonLinux2

Utilizando Network Já existente

https://eksctl.io/usage/nodegroup-with-custom-subnet/ Se vc já tive subnetes em alguma vpc definida com subnets por exemplo, vc pode utilizá-las para os nodes. Claro que antes vc precisará criar sua vpc com subnetes, router tables, gateways, etc. Um dos males de utilizar o eksctl é precisamos ter em mão todos os ids dos recursos que vamos usar, o que no terraforms poderíamos referenciar como variável.

...
vpc:
id: "vpc-084b9d7f2268d6efb"
subnets:
private:
us-east-2a:
id: "subnet-072ecc930bef61184"
us-east-2b:
id: "subnet-0b9d4740c3c22e2a9"
us-east-2c:
id: "subnet-077f9c28eabd811f4"
public:
us-east-2a:
id: "subnet-0bb20396ea932dab8"
us-east-2b:
id: "subnet-0f4a45706812b497d"
us-east-2c:
id: "subnet-0c2607e0d4556233b"
nodeGroups:
...

Definir labels e tags

No kuberentes utilizamos labels para saber onde vamos deployar os recursos. Quanto mais labels tivermos, mais opção teremos para filtrar. Tudo o que é necessário passar para o seu conhecimento futuro é bom passar. Por outro lado as tags são labels dos recursos da aws para filtrar os recursos usando a api da amazon.

nodeGroups:
- name: ng-prod
```...
tags: # AWS
team: devops
enviroment: production
nodegroup_role: eks-role-worker
price: on-demand
labels: # k8s
# Sempre colocar esse padrão. api/valor
alpha.eksctl.io/so-type: linux
alpha.eksctl.io/cloud: aws
alpha.eksctl.io/environment: production

Limites de auto scale e volume

https://aws.amazon.com/pt/blogs/aws-brasil/boas-praticas-de-utilizacao-de-instancias-spot-no-amazon-eks/ Podemos colocar limites máximo e mínimos para que o cluster seja auto escalado quando faltar recursos. Também é interessante a quantidade desejada.

nodeGroups:
- name: ng-prod
containerRuntime: containerd
amiFamily: AmazonLinux2
desiredCapacity: 1
minSize: 1
maxSize: 2
...

Instancias Spot

https://eksctl.io/usage/spot-instances/

Como funciona uma instancia spot? Quando vc definir que vc irá usar spot, vc consegue pegar máquinas a um preço mais barato, mas quando a aws precisa da máquina ela finaliza os seus recursos. Ou seja, não é conveniente colocar instancias spot em situações que o serviço não pode parar ou seria interessante ajustar uma estratégia para isso. Vale a pena uma leitura mais aprofundada no link acima. A configuracão abaixo no caso permite pegar instancias definidas e ele escolherá a que tem o menor preço por padrão.

nodeGroups:
- name: ng-prod
containerRuntime: containerd
amiFamily: AmazonLinux2
desiredCapacity: 1
minSize: 1
maxSize: 2
volumeSize: 20
instancesDistribution:
instanceTypes: ["t3.small", "t3.medium"]

SSH nos nodes

Para entrar nos nodes, podemos passar a chave publica para que seja colocado diretamente no .ssh/autorized_keys do host. Também já podemos para os ids do security groups (criado anteriormente) que essa essas instancias vão estar caso exista.

nodeGroups:
- name: ng-prod-v2
containerRuntime: containerd
amiFamily: AmazonLinux2
....

ssh:
allow: true
publicKeyPath: ~/.ssh/id_rsa.pub # Esse é o padrão
#sourceSecurityGroupIds: ["sg-00241fbb12c607007"]

Cloudwatch

Voce pode pegar métricas e loos do seu cluster usando o cloudwatch se quiser, mas existem meio melhores para isso com outros recursos do kubernetes.

cloudWatch:
clusterLogging:
enableTypes: ["*"] #=all
# pode ser api, audit, authenticator, controllerManager ou scheduler.

EKS e IAM

https://eksctl.io/usage/iamserviceaccounts/

O eks permite mapear roles do IAM para conta de serviço do eks. Dessa maneira é possível gerenciar permmissão através do iam para o nosso cluster. Isso fornece gerenciamento de permissões refinado para aplicativos executados no EKS e usam outros serviços da AWS. Podem ser aplicativos que usam S3, quaisquer outros serviços de dados (RDS, MQ, STS, DynamoDB) ou componentes do Kubernetes, como o controlador do AWS Load Balancer ou ExternalDNS. O eksctl pode criar, através do OIDC (OpenID Connnect Provider), roles e contas de serviço usando políticas pré estabelecidas. O OIDC não vem habilitado por padrão.

Se a entrada abaixo já tiver presente no cluster.yaml estará habilitado caso contrário coloque e aplique novamente a configuração do cluster.

iam:
withOIDC: true
❯ eksctl utils associate-iam-oidc-provider --region=us-east-2 --cluster=my-company-lab --approve
2022-08-08 14:44:20 [] will create IAM Open ID Connect provider for cluster "my-company-lab" in "us-east-2"
2022-08-08 14:44:21 [] created IAM Open ID Connect provider for cluster "my-company-lab" in "us-east-2"

Extra

Essa parte não mas refere-se a uma documentação de instalação, mas um recruso que vi durante o estudo chamado external-dns. É um serviço que cria automaticamente os dns para os serviços do kuberentes associando a um domínio existente.

IAM Dominio no EKS com o dns external

https://github.com/kubernetes-sigs/external-dns/blob/master/docs/tutorials/aws.md

próximo passo seria ter um dns para esse cluster. Para esses passos é necessário ter um route53 com uma zona definida. Esse dns será colocado para todos os nossos os nosso serviços criado.

Faça pelo console mesmo é mais façil ou se quise fazer pela awscli

route53 create

route53 define

ou pelo cli da aws

aws route53 create-hosted-zone --name "eks.puziol.com.br" --caller-reference "dominio de teste do eks "

Agora vamos dar ao nosso cluster uma role e nela colocar as permissões para que ele possa mexer nos recursos da aws. Mas primeiro crie uma police com o seguinte conteúdo. Faça via console mesmo, é mais fácil!

Vai em IAM>Policy>Create

policy

Policy Finish

Agora vamos criar uma serviceAccount. Podemos também fazer pelo config ou direto comando. Se for fazer pelo config adicione também o serviceAccount e a arn da police que criamos acima.

iam:
withOIDC: true
serviceAccounts:
- metadata:
name: external-dns
namespace: default
attachPolicyARNs:
- "arn:aws:iam::729792403128:policy/external-dns-policy"

Agora aplica

❯ eksctl create iamserviceaccount -f clusterfinal.yaml --approve
2022-08-12 04:17:48 [] 1 existing iamserviceaccount(s) (kube-system/aws-node) will be excluded
2022-08-12 04:17:48 [] 1 iamserviceaccount (default/external-dns) was included (based on the include/exclude rules)
2022-08-12 04:17:48 [!] serviceaccounts that exist in Kubernetes will be excluded, use --override-existing-serviceaccounts to override
2022-08-12 04:17:48 [] 1 task: {
2 sequential sub-tasks: {
create IAM role for serviceaccount "default/external-dns",
create serviceaccount "default/external-dns",
} }2022-08-12 04:17:48 [] building iamserviceaccount stack "eksctl-eks-cluster-addon-iamserviceaccount-default-external-dns"
2022-08-12 04:17:49 [] deploying stack "eksctl-eks-cluster-addon-iamserviceaccount-default-external-dns"
2022-08-12 04:17:49 [] waiting for CloudFormation stack "eksctl-eks-cluster-addon-iamserviceaccount-default-external-dns"
2022-08-12 04:18:20 [] waiting for CloudFormation stack "eksctl-eks-cluster-addon-iamserviceaccount-default-external-dns"
2022-08-12 04:18:20 [] created serviceaccount "default/external-dns"


❯ eksctl get iamserviceaccount --cluster eks-cluster
NAMESPACE NAME ROLE ARN
default external-dns arn:aws:iam::729792403128:role/eksctl-eks-cluster-addon-iamserviceaccount-d-Role1-1AJN0ML7N8R9M
kube-system aws-node arn:aws:iam::729792403128:role/eksctl-eks-cluster-addon-iamserviceaccount-k-Role1-Q3JUX8WCJ94H

ou poderia ser feito também direto pelo comando.

❯ eksctl create iamserviceaccount --name external-dns --namespace default --cluster my-company-lab --attach-policy-arn arn:aws:iam::729792403128:policy/external-dns-policy --approve

Observe as saída e veja que através do cloudformatino ele criou um role com a policy definida. Faça o exercício de procurar no IAM da aws o que ele criou.

Também é criado um sa dentro do k8s e no annotations dela é passado qual a role ele vai pegar no nosso iam.

❯ kubectl get serviceaccounts
NAME SECRETS AGE
default 1 38h
external-dns 1 12m

❯ k describe sa external-dns
Name: external-dns
Namespace: default
Labels: app.kubernetes.io/managed-by=eksctl
# abaixo a role que ele vai pegar
Annotations: eks.amazonaws.com/role-arn: arn:aws:iam::729792403128:role/eksctl-eks-cluster-addon-iamserviceaccount-d-Role1-1AJN0ML7N8R9M
Image pull secrets: <none>
Mountable secrets: external-dns-token-4tlkh
Tokens: external-dns-token-4tlkh
Events: <none>

Podemos agora fazer o deploy do external dns. Confira toda documentação do external-dns no repositório.

Nesse caso use o external-dns.yaml para fazer o deploy. É necessário corrigir dentro desse arquivo alguns valores para os seus. É necessário alterar os valore abaixo para a sua configuração de cluster e hostedzone.

- name: external-dns
image: k8s.gcr.io/external-dns/external-dns:v0.11.0
args:
- --source=service
- --source=ingress
- --domain-filter=eks.puziol.com.br #<coloque o seu>
- --provider=aws
- --policy=upsert-only # would prevent ExternalDNS from deleting any records, omit to enable full synchronization
- --aws-zone-type=public # only look at public hosted zones (valid values are public, private or no value for both)
- --registry=txt
- --txt-owner-id=Z05850441MQF8SO0CIDDV # <coloque o seu hosted zone aqui>
env:
- name: AWS_DEFAULT_REGION
value: us-east-2 # <altere para a sua região>

❯ kubectl create -f external-dns.yaml
clusterrole.rbac.authorization.k8s.io/external-dns created
clusterrolebinding.rbac.authorization.k8s.io/external-dns-viewer created
deployment.apps/external-dns created
Error from server (AlreadyExists): error when creating "external-dns.yaml": serviceaccounts "external-dns" already exists

❯ kubectl get pods
NAME READY STATUS RESTARTS AGE
external-dns-6bdcb445cc-jc5x9 1/1 Running 0 28s

❯ kubectl logs -f external-dns-6bdcb445cc-jc5x9
...
time="2022-08-12T08:34:57Z" level=info msg="All records are already up to date"

Se vc ver ao fim do log a mensagem acima, significa que tudo funcionou.

Obseve que o service account já tinha sido criado, logo ele não criou novamente.

GitLab Com Helm

O gitlab já vem com o cert manager integrado, logo o deploy do certmanager iria atrapalhar inicialmente e ter que fazer configurações maiores no gitlab.

Vamos fazer uma instalação do gitlab diretamente pelo help para testar.

❯ helm repo add gitlab https://charts.gitlab.io/
❯ helm repo update
❯ helm upgrade --install gitlab gitlab/gitlab --timeout 600s --set global.hosts.domain=eks.puziol.com.br --set certmanager-issuer.email=[email protected]

Só esperar e conferir a máquina gitlab.eks.puziol.com.br

Considerações finais

A experiência com o eksctl é boa e funcional, mas ao mesmo tempo perdemos o controle do que de fato está provisionado. Muitas vezes vemos em nosso arquivo de configuração algo declarado que não está deployado de fato.

Outra coisa que me incomodou é que somente um comando eksctl delete cluster <nome do cluster>poe abaixo tudo de uma vez sem nenhum tipo de proteção, somente a conta que possuí a permissão.

Outro detalhe é ter que buscar no console todo os ids dos recursos que vc ja possui ou até mesmo ter que criar recursos na manualmente como as políticas que usamos. É necessário o uso do console ou utilizar o aws cli. Dessa maneira seria muito mais interessante deployar utilizando bons módulos da comunidade usando terraforms.