23 maio 2019

Automatizando processos e tarefas para deploy's e provisionamento de servidores

Recentemente na Operar, tivemos um tarefa bem comum para quem trabalha com desenvolvimento web ou áreas afins. Criar um servidor, configurar (servidor web, firewall, chaves públicas no molho de chaves e etc) e deixa-lo rodando e também documentar as configurações e processos. Fazer isso não é difícil, mas manter essas informações organizadas e com fácil acesso para outros colaboradores, não é nada simples apenas com scripts de automação e instruções em uma wiki interna, por exemplo.

Uma wiki interna para que outras pessoas possam consultar/alterar e fazer o seu trabalho, não é novo para alguns, entrentanto esse modelo abre espaço para duas pedras no caminho. A primeira é a queda de produtividade, pois por mais que tudo esteja bem documentado, ainda é necessário um trabalho extra para atualizar tal documento com as últimas alterações feitas, além de ter que fazer a tarefa em si. E o outro problema é a quebra do fluxo de trabalho, pois dependendo das alterações é necessário escrever instruções mais detalhadas e isso é cansativo, trabalhoso e manter isso ativo entre todos os membros pode levar um certo tempo e disciplina. Atualmente a cultura DevOps vem trazendo uma série de melhorias em nossos Workflows, ferramentas mais "friendly" (como os .env e YAML's da vida), diga-se de passagem. Ferramentas essas que além de tirar o trabalho das execuções e documentações manuais, nos permiti versionar suas configurações e usa-las como uma documentação do estado atual das coisas, tanto na infraestrutura como nos serviços/containers.

Infraestrutura como código e deploy também!

Dado tal cenário e uma pesquisada, encontrei uma ferramenta chamada Terraform que é uma espécie de construtor de infraestrutura. Com ele você declara as configurações necessárias (e suportadas pelo serviço de Cloud alvo) em um arquivo texto para depois aplicar as mundanças necessárias (ou plan como ele chama) no serviço provedor. Isso inclui desde a configuração do servidor até ferramentas que ajuda a compor a infra, como domínio, firewall, zona DNS e mais qualquer coisa que esteja disponível no seu provider.

Em um exemplo simples do Terraform em ação, crio um arquivo main.tr eu declaro um servidor na Digital Ocean que tem tamanho, região, nome e imagem de distribuição. E logo em mais a baixo, declaro também um domínio a ser criado no serviço de DNS da Digital Ocean e atrelo ao domínio o IP do servidor nomedado como all.

# main.tr

provider "digitalocean" {}

resource "digitalocean_droplet" "all" {
  image = "docker-18-04"
  name = "all"
  region = "fra1"
  size = "s-1vcpu-1gb"
}

resource "digitalocean_domain" "domain_name" {
  name = "domain.tld"
  ip_address = "${digitalocean_droplet.all.ipv4_address}"
}

O Terraform tem uma gama de possíbilidades para automatizar esses processos mais burocráticos. É possível com ele gerenciar até o ciclo de vida de containers, redes e volumes no Docker. Se o objetivo é usar Docker em produção, isso ajuda, você pode estabelecer logo de início uma rede padrão para sua aplicação, por exemplo.

Pós infra e tarefas cotidianas

Outra ferramenta ótima para automatizar processos, como instalação de pacotes, deploy da aplicação, orquestração, regras de permissões (Linux), entre outra infinidade de possíbilidades é o Ansible. Basicamente por meio de uma conexão SSH, ele executa as tarefas declaradas em um arquivo YAML. Junto com vários módulos incluidos nele, é possível deixar fluxo de trabalho bem mais produtivo e menos oneroso, basta organizar tudo certinho no playbook e ninguém sai sem deploy.

Os playbooks, seriam um conjuto de tarefas que irão ser executadas um determinado inventário (lista de servidores que irão receber a conexão e execução das tarefas). As tarefas podem ser aplicadas tanto para todos ou somente para alguns, além disso, ele também é escrito em YAML, assim como o inventário.

Vejamos um exemplo de um playbook que reinicia ou cria um container com um servidor web e já linka os volumes, e faz sempre pull dos commits de algum repositório git.

# playbook.yml

---
- hosts: all
  tasks:
    - name: Update last version -> GIT
      git:
      repo: 'https://gitlab.com/gutierri/webapp.git'
      dest:  /srv/webapp
      version: master

    - name: Container webapp -> NGINX
      docker_container:
      image: nginx:1.15
      name: webapp
      state: started
      restart: yes
      exposed_ports:
        - 80
      env_file: /var/tmp/webapp/webapp.env
      volumes:
        - "/srv/webapp:/usr/share/nginx/html:ro"

E aqui temos o inventário (também chamado de hosts) com os servidores alvo (webapp.local pode ser seu domínio ou IP e com conexões SSH devidamente configuradas préviamente).

# hosts.yml

all:
  hosts:
    webapp.local:

Bata tudo e junte em um Makefile!

Bem, temos um toolchain bem bacana que ajusta os serviços relacionados a infra e afins, e deploy da aplicação em um servidor web. Costumo manter a execução das tarefas o mais simples e "esperto" possível e dificilmente uma única ferramenta vai resolver todos os problemas, afim de diminuir, por exemplo, o número de diferentes comandos de ferramentas distintas que preciso lembrar. E o GNU Make meio que contorna isso, pois posso definir uma série de comandos agrupados ou não e nomea-los pra serem executados de uma vez, a partir daí é necessário lembrar e rodar apenas um único comando para executar tarefas mais objetivas (as mais comuns como: deploy release e status).


infra-deploy:
        terraform apply

infra-status:
        terraform plan

app-deploy:
        ansible-playbook -i hosts.yml playbook.yml

all:
        @echo "infra-deploy infra-status deploy"

.PHONY: infra-deploy infra-status deploy