Domine o Ansible: Aprenda a provisionar e configurar sua infraestrutura na nuvem
Introdução
O Ansible é uma ferramenta extremamente poderosa, podendo fazer todo a orquestração da sua infraestrutura. Porém, o que mais me chama atenção nele, é que podemos provisionar todo nosso ambiente na nuvem primeiramente e já configurá-lo em seguida.
Aqui vou demonstrar como conseguimos provisionar a seguinte infraestrutura e configurá-la com apenas uma playbook.
Iremos provisionar 4 instâncias, uma que será nosso LoadBalancer (LB01), duas que serão nossos servidores web (APP01 e APP02) e por fim o nosso banco de dados (Database).
Sem mais delongas vamos provisionar nosso ambiente:
Pré-requisitos:
Ansible, Python 2.7, Pip, Pip modules (boto, botocore), EC2 Key Pair, AWS Access key e Secret Key
Começamos baixando nossos arquivos
git clone https://github.com/guilhermewolf/aws-loadbalancer-ansible.git
Vamos editar dois arquivos
group_vars/all.yml
│
└──key_name: lb-ansible
Altere o nome da chave com a que você criou na AWS
inventory/hosts
│
└──ansible_ssh_private_key_file= ~/lb-ansible.pem
Altere para o local onde está a chave na sua máquina
Vamos colocar nossas credenciais da AWS como variáveis de ambiente
export AWS_ACCESS_KEY_ID=#SUA ACESSKEY#
export AWS_SECRET_ACCESS_KEY=#SUA SECRET KEY#
All set, let’s go!
ansible-playbook playbook.yml
Agora veja toda a infraestrutura ser provisionada diante de seus olhos.
Mas como tudo isso funciona?
O Ansible precisa primeiramente de uma relação de confiança tanto com a AWS quanto com as máquinas que foram provisionadas, por isso provemos para ele as credenciais da AWS e a chave privada que criamos para as instâncias. O Ansible precisa de um inventário, que é composto pelo endereço IP das máquinas das quais ele irá configurar, porém nossa playbook primeiramente irá criar as máquinas e só depois de criadas teremos os IP’s delas, precisamos então criar um inventário que seja dinâmico – por nossa sorte o próprio Ansible oferece um script em Python no Github para facilitar nossa vida, onde ele acessa a AWS pelas credenciais que oferecemos via variável de ambiente e lista nossas instâncias e seus devidos IP’s.
Essa é a estrutura de diretórios da nossa playbook.
.
├── group_vars
├── inventory
├── playbooks
└── roles
├── apache2
├── aws
├── demo_app
├── mysql
└── nginx
O arquivo playboook.yml contêm 8 etapas, em cada etapa ele irá chamar alguma role que está dentro do diretório roles.
Nossa playbook se inicia chamando o diretório roles/aws e criando as instâncias na AWS com o módulo ec2_instance, para o módulo oferecemos alguns itens, as credenciais da AWS, um nome para a máquina, a chave que ela irá usar, o security group, tipo da instância, id da imagem a ser usada e a região que ela irá ficar.
- name: Provision Loadbalancer
ec2_instance:
aws_access_key: "{{ aws_access_key }}"
aws_secret_key: "{{ aws_secret_key }}"
name: lb01
key_name: "{{ key_name }}"
security_group: "{{ security_group }}"
instance_type: "{{ instance_type }}"
image_id: "{{ image }}"
wait: true
state: running
region: "{{ region }}"
Fazemos isso para as 4 máquinas, porém nosso inventário iniciou na playbook sem nenhum IP dentro dele, pois as máquinas ainda não existiam, agora precisamos atualizar nosso inventário para receber esses IP’s
- name: refresh_inventory
hosts: localhost
gather_facts: False
tasks:
- meta: refresh_inventory
Agora com nosso inventário populado aguardamos nossas máquinas ficarem 100% provisionadas, iremos fazer isso aguardando que o Ansible consiga fazer uma conexão SSH nelas.
- name: Wait vms go up
hosts: all
user: ubuntu
gather_facts: False
tasks:
- wait_for_connection:
timeout: 300
Quando as máquinas são provisionadas na AWS um script é chamado pelo CloudInit para fazer uma configuração inicial das máquinas, adicionando alguns pacotes essenciais para a máquinas, nós precisamos garantir que esse script tenha encerrado a sua execução antes de começarmos a configurar as máquinas
- name: Wait for cloud init to finish
hosts: cluster
gather_facts: False
become: yes
tasks:
- cloud_init_data_facts:
filter: status
register: res
until: "res.cloud_init_data_facts.status.v1.stage is defined and not res.cloud_init_data_facts.status.v1.stage"
retries: 50
delay: 5
Após concluir esse estágio, daremos início as configurações das máquinas. Primeiramente, vamos atualizar a lista de pacotes disponíveis nos repositórios:
- hosts: all
become: true
user: ubuntu
gather_facts: true
tasks:
- name: update apt cache
apt: update_cache=yes cache_valid_time=86400
Agora vamos configurar cada máquina individualmente, começaremos pela database, dentro de nossa estrutura de diretórios temos a seguinte pasta:
roles
├── apache2
│ ├── handlers
│ ├── tasks
│ └── tests
├── aws
│ └── tasks
├── demo_app
│ ├── files
│ ├── handlers
│ ├── tasks
│ ├── templates
│ └── tests
├── mysql
│ ├── handlers
│ ├── tasks
│ └── tests
└── nginx
├── defaults
├── handlers
├── tasks
├── templates
└── test
Dentro de cada pasta das roles temos algumas outras dentro, a mais importante delas é a tasks, que será onde encontramos quais etapas de configurações serão feitas em nossas máquinas.
A pasta handlers contém ações a serem executadas caso sejam chamadas no arquivo main.yml dentro da pasta tasks (como por exemplo o comando systemctl restart caso alguma configuração seja feita).
Na pasta files podemos deixar arquivos que desejamos enviar para as máquinas remotas, em nosso exemplo temos os arquivos de configuração e o site em python. No arquivo main.yml dentro de tasks passamos o diretório do nosso arquivo e o destino dele na máquina remota.
- name: copy demo app source
copy: src=demo/app/ dest=/var/www/demo mode=0755
Dentro de templates podemos encontrar arquivos com o formato .j2 que é uma linguagem de templates para o python. Podemos criar arquivos de configurações para ele e ao invés de colocarmos os valores específicos que precisaremos, deixamos variáveis que o Ansible utiliza para serem populadas na hora de escrever o arquivo na máquina remota. Como é o caso em roles/demo_app/templates/demo.wsgi.j2
import os
os.environ['DATABASE_URI'] = 'mysql://{{ db_user }}:{{ db_pass }}@{{ groups.database[0] }}/{{ db_name }}'
Passamos as variáveis dbuser, dbpass e dbname para serem escritas no arquivo, assim podemos alterar apenas as variáveis que o Ansible utiliza no arquivo groupvars e todo nosso parque será provisionado corretamente.
Explore essa playbook e a utilize para criar suas futuras playbooks. Ela irá servir tanto para aprender a configurar seu parque de máquinas, tanto para aprender a provisionamento de instâncias na AWS.
Até mais pessoal!
About author
Você pode gostar também
Por que aprender Python? Descubra os motivos e vantagens
Dizem que se alguém quer trabalhar no Google, o caminho mais simples é aprender Python. Será este o único motivo? De fato, a linguagem Python é intensivamente usada pelo Google.
Descubra como o Skaffold pode otimizar seu trabalho com Kubernetes
Olá pessoal! A ideia para este post surgiu quando me deparei com o problema, que todos que trabalham ou vão trabalhar com Kubernetes enfrentam: a necessidade de a cada simples
Como versionar sua infraestrutura com Terraform e GitLab
Deixando um pouco o assunto sobre Corona Vírus de lado, chegamos ao penúltimo post da nossa série de postagens sobre Terraform. Aqui iremos falar sobre como versionar sua infraestrutura utilizando