Provisionando Instâncias EC2 na AWS com Ansible

Provisionando Instâncias EC2 na AWS com Ansible

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!

CURSOSCONSULTORIA    CONTATO

Anterior Qual o nível de maturidade DevOps da sua empresa?
Próxima Recrutamento e seleção rápida e certeira usando a Rankdone

About author

Você pode gostar também

DevOps

O que é DevOps?

DevOps é um termo criado para descrever um conjunto de práticas para integração entre as equipes de desenvolvimento de softwares, operações (infraestrutura ou sysadmin) e de apoio envolvidas (como controle

DevOps

Rundeck, bom para projetos DevOps

O Rundeck é uma aplicação java de código aberto que automatiza processos e rotinas nos mais variados ambientes, gerenciado via interface gráfica fica extremamente simples de verificar status de execuções,

DevOps

DevOps. Você vai conhecer e aplicar!

DevOps é fundado na construção de uma cultura de colaboração, visando a entrega de software de maneira mais rápida e confiável. Pode ser compreendido como uma filosofia de gestão, englobando