Desenvolvido por Mateus Muller, esse projeto é uma reprodução para conhecer algumas ferramentas como: Terraform, Ansible, Drone CI, Docker, Kubernetes e AWS.
Inicialmente 3 instâncias são configuradas pelo Terraform, com grupo de segurança e um par de chaves. O estado da aplicação(TF.state) será armazenado em um bucket na S3.
Logo em seguida a instalação e configuração do cluster é definida no site.yml e executada pelo Ansible.
Com tudo pronto, uma imagem é construida para ser executada pelo Drone CI, ele será responsavel por rodar todas as configurações definidas pelo Terraform e Ansible, tendo como resultado um cluster kubernetes.
Para desenvolver este projeto, eu usei as aulas disponiveis no youtube. Porém algumas configurações mudaram, e alguns ajustes foram feitos:
O primeiro desafio que encontrei foi na listagem dos hosts, o projeto original usa um script(ec2.py
) para listar e informar para o playbook os hosts das maquinas criadas pelo Terraform na AWS. Porém recentemente foi disponibilzado o plugin de inventário que traz informações detalhadas de cada instância criada. Por questões de adaptação eu resolvi usar o plugin ao ínves do script.
Para isso instalei o plugin:
ansible-galaxy collection install amazon.aws
E em seguida instalei os seus requesitos: boto3
e botocore
em uma imagem docker.
Logo em seguida criei o arquivo de configuração do ansible(ansible.cfg
):
[defaults]
inventory = ./ansible_plugins
host_key_checking = False
pipelining = True
log_path = /var/log/ansible
roles_path = ./roles
forks = 1000
Criei o arquivo de configuração do plugin no arquivo: ./ansible_plugins/get_groups_instances_tag_k8s_aws_ec2
sendo escolha do nome, livre, mas o sufixo deve ser _aws_ec2.yml
. O arquivo contém as seguintes informações:
plugin: aws_ec2
regions:
- us-east-1
keyed_groups:
- key: tags.type
- key: tags.name
filters:
instance-state-name: running
compose:
ansible_host: public_ip_address
strict_permissions: False
Para ver o resultado da listagem basta executar:
ansible-inventory --graph
O resultado será algo parecido com isso:
@all:
|--@_k8s:
| |--ec2-<Ip da maquina aqui>.compute-1.amazonaws.com
| |--ec2-<Ip da maquina aqui>.compute-1.amazonaws.com
| |--ec2-<Ip da maquina aqui>.compute-1.amazonaws.com
|--@_master:
| |--ec2-<Ip da maquina aqui>.compute-1.amazonaws.com
|--@_worker:
| |--ec2-<Ip da maquina aqui>.compute-1.amazonaws.com
| |--ec2-<Ip da maquina aqui>.compute-1.amazonaws.com
|--@aws_ec2:
| |--ec2-<Ip da maquina aqui>.compute-1.amazonaws.com
| |--ec2-<Ip da maquina aqui>.compute-1.amazonaws.com
| |--ec2-<Ip da maquina aqui>.compute-1.amazonaws.com
|--@ungrouped:
Para mais detalhes sobre cada instância use: ansible-inventory --list --yaml
O keyed_groups
configurado dentro do arquivo get_groups_instances_tag_k8s_aws_ec2
traz os hosts separados por grupos, sendo assim, basta colocar o nome de cada grupo como host em seu arquivo principal:
- name: Install k8s and docker packages
become: yes
hosts: _k8s # => @_k8s
roles:
- docker
- k8s-all
...
Com essa configuraçõe é importante lembrar que o comando para iniciar deve ser alterado, o nova instrução para iniciar o playbook é:
ansible-playbook && \
--u ubuntu && \
--ssh-common-args='-o StrictHostKeyChecking=no' && \
--private-key ~/.ssh/id_rsa site.yml&& \
Você pode conferir com mais detalhes em: clarusway.com e faun.pub
Depois de ter configurado o ansible com as instancias criadas pelo terraform, encontramos um alguns problemas na incialização do clustes. O serviço kubelete
não estava iniciando. Depois de um tempo observando percebi que o serviço não incia antes de configurar o plano de controle do Kubernetes(kubectl init
), mas que era possivel ativar-lo em seguida.
Então para resolver esse problema encontrei na documentação oficial um modelo de configuração(kubeadm-config.yaml
) para que o kubelete
podesse funcionar normalmente:
# kubeadm-config.yaml
kind: ClusterConfiguration
apiVersion: kubeadm.k8s.io/v1beta3
kubernetesVersion: v1.21.0
---
kind: KubeletConfiguration
apiVersion: kubelet.config.k8s.io/v1beta1
cgroupDriver: systemd
Para funcionar, é necessário enviar esse arquivo de configuração para cada instância. Para fazer isso adicionanmos mais um passo no arquivos de tarefas:
- name: Copy Remote-To-Server (kubeadm-config.yaml)
synchronize:
src: ./kubeadm-config.yaml
dest: /home/ubuntu
ATENÇÃO!
Para enviar o arquivo para cada instância, é obrigatório que o rysnc
esteja adicionado em seu Dockerfile para fazer a instalação! Caso o contrario você vai encontrar uma mensagem semelhante a essa em seu pipeline:
Failed to find required executable rsync in paths:
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
Logo em seguida basta iniciar passando esse arquivo como parametro de configuração:
kubeadm init --config kubeadm-config.yaml
A instalação do pod network estava com problemas, e para resolver usei uma versão mais recente trocando o link do calico:
kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml