DevSecOps

10 ago, 2018

Cluster de Docker Swarm com Ansible

Publicidade

Fala, pessoal!

Neste artigo vamos mostrar como é possível realizar a configuração de um cluster de Docker Swarm com três managers e um Worker utilizando Ansible. Para quem ainda não possui familiaridade com as nomenclaturas do Docker, Manager é o papel responsável por gerenciar o cluster de Docker Swarm, já o Worker é o responsável por hospedar os containers.

Mas o que é o Ansible? Basicamente é uma ferramenta de automatização de tarefas, que é muito utilizada para provisionamento e configuração de servidores, muito semelhante a Chef e Puppet. Você pode ver mais detalhes dela em nosso outro artigo que detalha mais sobre o Ansible:

Para esse artigo vamos utilizar cinco máquinas virtuais, sendo:

  • Três Ubuntus 16.04 que serão utilizados como Managers
  • Um Ubuntu 16.04 que será utilizado como Worker
  • Um Ubuntu 16.04 que estará com o Ansible instalado

Nosso principal objetivo é realizar a configuração de nossos servidores de forma declarativa através do Ansible e disparar os Playbooks de configuração de nossos servidores.

Vamos iniciar fazendo a instalação do Ansible em nosso servidor que será o responsável por conectar nos outros quatro servidores. Como o Ansible conecta através de ssh nas máquinas, não é preciso realizar a instalação de agentes nas máquinas de destino.

O único requisito é ter o acesso ssh liberado para a máquina que irá executar o Ansible. No momento da criação desse artigo, a versão mais recente do Ansible é a 2.5, então vamos utilizá-la. Na máquina que estamos utilizando para servir como Ansible, você irá executar os seguintes comandos:

sudo apt-get update
sudo apt-get install software-properties-common
sudo apt-add-repository ppa:ansible/ansible
sudo apt-get update
sudo apt-get install ansible

Após a execução desses comandos, você estará com o Ansible instalado em sua máquina. O Ansible cria o diretório /etc/ansible/, e dentro deste diretório temos o arquivo ansible.cfg, que é o responsável por gerenciar algumas configurações como métodos de conexões, portas, protocolo, entre outras configurações. Alguns exemplos de configurações que muitas vezes são alteradas no ansible.cfg:

remote_port = 22
sudo_user = root
host_key_checking = False
# SSH timeout
timeout = 10

Esse foi um exemplo simples de alteração – você pode acessar o arquivo e verificar todas as opções de mudança. Vamos continuar realizando a nossa configuração. Criar o diretório que conterá as nossas configurações para os servidores:

mkdir /home/exemplopost
mkdir /home/exemplopost/roles
mkdir /home/exemplopost/group_vars
cd /home/exemplopost
touch /home/exemplopost/hosts
touch /home/exemplopost/main.yml

Esses são os diretórios base que utilizamos em um projeto com Ansible, é uma nomenclatura padrão com quem trabalha com Ansible. Dentro de “Roles” é onde vamos colocar os nossos “Playbooks” responsáveis pela configuração dos servidores, onde segmentamos por funcionalidades, “group_vars” é onde colocamos os nossos templates de variáveis que utilizamos dentro dos nossos Playbooks.

Ainda temos os arquivos “hosts”, onde estão as informações dos servidores que vamos conectar e também o arquivo “main.yml“, que é o início da execução do nosso Ansible, onde estará descrito as Roles que serão executadas e quais os hosts que serão usados. Vamos iniciar adicionando os nossos hosts no arquivo hosts.

vim /home/exemplopost/hosts

[docker_swarm_manager]
MANAGER1 ansible_ssh_host=10.10.10.2 ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass=ExemploPost
MANAGER2 ansible_ssh_host=10.10.10.3 ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass=ExemploPost
MANAGER3 ansible_ssh_host=10.10.10.4 ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass=ExemploPost
[docker_swarm_worker]
WORKER1 ansible_ssh_host=10.10.10.5 ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass=ExemploPost

Esse é o conteúdo do nosso arquivo de hosts; dentro deles temos dois grupos de máquinas: um que chamamos de “docker_swarm_manager” e “docker_swarm_worker”. Com a criação de grupos conseguimos definir que determinado grupo irá executar Roles X e outro grupo irá executar Roles Y, visto que, nesse caso, Managers e Workers possuem diferentes configurações. Vamos criar uma hierarquia de diretórios e arquivos conforme a imagem abaixo:

Agora vamos editar o arquivo /home/exemplopost/roles/docker/tasks/main.yml:

---
  - name: Realizando apt-get update
    apt:
     update_cache: yes
  - name: Modificando hostname
    shell: hostname {{ inventory_hostname }}

  - name: Instalando a versão mais recente do Docker
    shell: curl -sS https://get.docker.com | sh

  - name: Reiniciar serviço do Docker
    systemd:
     state: restarted
     enabled: yes
     daemon_reload: yes
     name: docker

Com isso, temos todos os passos que são comuns em todos os servidores de Manager e Worker. Agora vamos realizar a configuração dos Managers:

Abra o arquivo /home/exemplopost/roles/manager/tasks/main.yml:

---
  - name: Verifica se o Docker Swarm está habilitado
    shell: docker info
    changed_when: False
    register: docker_info

  - name: Cria o cluster no primeiro servidor
    shell: docker swarm init --advertise-addr {{ docker_swarm_manager_ip }}:{{ docker_swarm_manager_port }}
    when: "docker_info.stdout.find('Swarm: active') == -1 and inventory_hostname == groups['docker_swarm_manager'][0]"

  - name: Armazena o token de manager
    shell: docker swarm join-token -q manager
    changed_when: False
    register: docker_manager_token
    delegate_to: "{{ groups['docker_swarm_manager'][0] }}"
    when: "docker_info.stdout.find('Swarm: active') == -1"
 
  - name: Adiciona os outros swarms Managers no cluster.
    shell: docker swarm join --token "{{ docker_manager_token.stdout }}" {{ docker_swarm_manager_ip}}:{{ docker_swarm_manager_port }} 
    changed_when: False
    when: "docker_info.stdout.find('Swarm: active') == -1
     and docker_info.stdout.find('Swarm: pending') == -1
     and 'docker_swarm_manager' in group_names
     and inventory_hostname != groups['docker_swarm_manager'][0]"

Após criar o cluster e adicionar os servidores de Managers, vamos adicionar o nosso Worker. Para isso, editaremos /home/exemplopost/roles/worker/tasks/main.yml:

---
  - name: Verifica se o Docker Swarm está habilitado.
    shell: docker info
    changed_when: False
    register: docker_info

  - name: Pega o token do worker.
    shell: docker swarm join-token -q worker
    changed_when: False
    register: docker_worker_token
    delegate_to: "{{ groups['docker_swarm_manager'][0] }}"
    when: "docker_info.stdout.find('Swarm: active') == -1"

  - name: Adiciona o servidor de Worker no cluster.
    shell: docker swarm join --token "{{ docker_worker_token.stdout }}" {{ docker_swarm_manager_ip}}:{{ docker_swarm_manager_port }}
    changed_when: False
    when: "docker_info.stdout.find('Swarm: active') == -1
           and docker_info.stdout.find('Swarm: pending') == -1"

Os playbooks acima são os responsáveis pela criação do cluster de Docker Swarm. Agora criaremos as variáveis que serão utilizadas.

/home/exemplopost/group_vars/all

---
  docker_swarm_manager_ip: "10.10.10.2"
  docker_swarm_manager_port: "2377"

Vamos agora definir o nosso arquivo main para chamar as roles a serem executadas. Para isso, criaremos o arquivo em /home/exemplopost/main.yml.

---
 - name: Configurando Managers
   hosts: docker_swarm_manager

   roles:
     - docker
     - manager

 - name: Configurando Workers
   hosts: docker_swarm_worker
   roles:
    - docker
    - worker

Agora, sim; criamos todos os arquivos necessários para rodar o nosso playbook. Feito isso, basta você executar o comando:

 ansible-playbook -i hosts main.yml

E teremos o nosso cluster de Docker Swarm configurado e funcionando. Fizemos uma configuração simples que funciona muito bem para um ambiente de testes.

Espero que esse artigo tenha sido útil para vocês, e gostaria que deixassem aqui em baixo algum comentário ou dúvidas para que cada vez mais possamos melhorar o nosso conteúdo para simplificar para todos.

Por hoje era isso, pessoal. Um grande abraço e muito obrigado!