Checklist: como automatizar deploys no Linux com Ansible

Por Equipe Técnica AviraHost · 17 min de leitura · Atualizado em · Ansible, automação, deploy, Linux, AviraHost, DevOps, AlmaLinux · 0

Automatizar deploys no Linux com Ansible significa usar Playbooks YAML para orquestrar, de forma repetível e auditável, todas as etapas de publicação de uma aplicação — do pull do repositório à reinicialização do serviço — sem intervenção manual. Para montar seu checklist completo, siga estes passos:

  1. Instalar o Ansible no nó de controle e configurar acesso SSH aos servidores de destino.
  2. Criar o arquivo de inventário com os hosts de produção e staging.
  3. Escrever o Playbook principal com as tarefas de deploy (pull, build, migrate, reload).
  4. Organizar tarefas em Roles reutilizáveis para separar responsabilidades.
  5. Testar com --check --diff antes de aplicar em produção.
  6. Configurar pipeline de rollback com symlinks versionados.

Pré-requisitos para automatizar deploys com Ansible no Linux

  • Nó de controle: qualquer máquina Linux com Python 3.9+ e Ansible 2.16+ instalado (Ubuntu 24.04 LTS, Debian 12 ou Rocky Linux 9 funcionam bem).
  • Servidores de destino: Python 3 instalado (pacote python3); sem necessidade de agente Ansible.
  • Acesso SSH: chave pública do nó de controle adicionada ao ~/.ssh/authorized_keys do usuário remoto (preferencialmente um usuário dedicado, não root).
  • Permissões sudo: o usuário remoto deve ter permissão de sudo sem senha para os comandos necessários (reiniciar serviços, por exemplo).
  • Git instalado nos servidores de destino para operações de pull do repositório.
  • Conhecimento básico de YAML e familiaridade com a estrutura de diretórios do Ansible.

Como instalar e configurar o Ansible para deploys automatizados

A automação de deploys com Ansible começa pela instalação correta do nó de controle. No Ubuntu 24.04 LTS, o repositório oficial da Ansible garante a versão mais recente:

sudo apt update
sudo apt install -y software-properties-common
sudo add-apt-repository --yes --update ppa:ansible/ansible
sudo apt install -y ansible
ansible --version
ansible [core 2.16.x]
  config file = /etc/ansible/ansible.cfg
  python version = 3.12.x
  jinja version = 3.1.x

No Rocky Linux 9 ou AlmaLinux 9, use o repositório EPEL:

sudo dnf install -y epel-release
sudo dnf install -y ansible
ansible --version

Após a instalação, configure o arquivo global /etc/ansible/ansible.cfg ou crie um local no diretório do projeto:

[defaults]
inventory = ./inventory/hosts.ini
remote_user = deploy
private_key_file = ~/.ssh/id_ed25519
host_key_checking = False
retry_files_enabled = False

[privilege_escalation]
become = True
become_method = sudo
become_user = root

Teste a conectividade com todos os hosts antes de qualquer deploy:

ansible all -m ping
web01 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
web02 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

Se você ainda está configurando o acesso SSH ao seu VPS, consulte o guia Acessando servidores VPS Linux da AviraHost para os primeiros passos de conexão.

Estrutura do inventário e organização de ambientes

O arquivo de inventário é o mapa de infraestrutura do Ansible — ele define quais servidores recebem cada conjunto de tarefas. Para deploys profissionais, separe os ambientes em grupos distintos:

[staging]
staging01 ansible_host=192.168.1.10

[production]
web01 ansible_host=203.0.113.10
web02 ansible_host=203.0.113.11

[production:vars]
app_env=production
app_dir=/var/www/minha-app
[email protected]:empresa/minha-app.git
app_branch=main
nginx_service=nginx

[staging:vars]
app_env=staging
app_dir=/var/www/minha-app-staging
app_branch=develop

Para inventários dinâmicos (quando os IPs mudam com frequência, como em ambientes cloud), o Ansible suporta scripts Python ou plugins nativos. Para a maioria dos cenários com VPS fixos, o inventário estático acima é suficiente e mais fácil de auditar.

Organize o projeto completo seguindo a estrutura recomendada pela Ansible Galaxy:

deploy-project/
├── ansible.cfg
├── inventory/
│   └── hosts.ini
├── group_vars/
│   ├── all.yml
│   ├── production.yml
│   └── staging.yml
├── roles/
│   ├── deploy/
│   │   ├── tasks/
│   │   │   └── main.yml
│   │   ├── handlers/
│   │   │   └── main.yml
│   │   └── templates/
│   │       └── app.conf.j2
│   └── rollback/
│       └── tasks/
│           └── main.yml
└── site.yml

Escrevendo o Playbook de deploy com Ansible

O Playbook de deploy é o coração da automação — ele orquestra cada etapa da publicação de forma idempotente, garantindo que rodar duas vezes produza o mesmo resultado que rodar uma vez. Crie o arquivo site.yml:

---
- name: Deploy da aplicação em produção
  hosts: production
  serial: 1
  gather_facts: true

  roles:
    - deploy

Agora crie o arquivo de tarefas principal em roles/deploy/tasks/main.yml:

---
- name: Garantir que o diretório de releases existe
  file:
    path: "{{ app_dir }}/releases"
    state: directory
    owner: "{{ remote_user }}"
    mode: "0755"

- name: Registrar timestamp do release
  command: date +%Y%m%d%H%M%S
  register: release_timestamp
  changed_when: false

- name: Definir caminho do release atual
  set_fact:
    release_path: "{{ app_dir }}/releases/{{ release_timestamp.stdout }}"

- name: Clonar repositório na versão correta
  git:
    repo: "{{ app_repo }}"
    dest: "{{ release_path }}"
    version: "{{ app_branch }}"
    depth: 1
    accept_hostkey: true

- name: Instalar dependências (exemplo: Node.js)
  command: npm ci --production
  args:
    chdir: "{{ release_path }}"
  environment:
    NODE_ENV: "{{ app_env }}"

- name: Copiar arquivo de configuração de ambiente
  template:
    src: app.conf.j2
    dest: "{{ release_path }}/.env"
    mode: "0640"

- name: Executar migrações de banco de dados
  command: ./bin/migrate.sh
  args:
    chdir: "{{ release_path }}"
  when: app_env == "production"

- name: Atualizar symlink current para o novo release
  file:
    src: "{{ release_path }}"
    dest: "{{ app_dir }}/current"
    state: link

- name: Manter apenas os 5 releases mais recentes
  shell: |
    ls -dt {{ app_dir }}/releases/*/ | tail -n +6 | xargs rm -rf
  changed_when: false

- name: Reiniciar o serviço da aplicação
  notify: restart app service

Crie o handler em roles/deploy/handlers/main.yml:

---
- name: restart app service
  systemd:
    name: minha-app
    state: restarted
    daemon_reload: true

Atenção: a tarefa de migração de banco de dados é potencialmente destrutiva. Sempre faça backup antes de executar o Playbook em produção. Consulte as Dicas de Otimização de Servidores Linux para boas práticas de manutenção antes de deploys críticos.

Configurando o Playbook de rollback com symlinks versionados

A estratégia de rollback com Ansible usa a estrutura de releases versionados criada no deploy — basta redirecionar o symlink current para a versão anterior sem necessidade de novo upload. Crie roles/rollback/tasks/main.yml:

---
- name: Listar releases disponíveis
  find:
    paths: "{{ app_dir }}/releases"
    file_type: directory
  register: available_releases

- name: Ordenar releases por data de modificação
  set_fact:
    sorted_releases: "{{ available_releases.files | sort(attribute='mtime', reverse=True) | map(attribute='path') | list }}"

- name: Verificar se existe release anterior
  fail:
    msg: "Não há release anterior disponível para rollback."
  when: sorted_releases | length < 2

- name: Definir release anterior
  set_fact:
    previous_release: "{{ sorted_releases[1] }}"

- name: Redirecionar symlink para release anterior
  file:
    src: "{{ previous_release }}"
    dest: "{{ app_dir }}/current"
    state: link

- name: Reiniciar serviço após rollback
  systemd:
    name: minha-app
    state: restarted

Para executar o rollback em emergência:

ansible-playbook -i inventory/hosts.ini rollback.yml --limit production
PLAY [Rollback da aplicação] ***********************************

TASK [rollback : Redirecionar symlink para release anterior] ***
changed: [web01]
changed: [web02]

PLAY RECAP *****************************************************
web01 : ok=5  changed=2  unreachable=0  failed=0
web02 : ok=5  changed=2  unreachable=0  failed=0

Testando Playbooks com dry-run antes de aplicar em produção

O modo de verificação do Ansible permite simular toda a execução sem alterar nenhum arquivo ou serviço no servidor remoto — essencial antes de qualquer deploy em produção. Use sempre as flags --check e --diff juntas:

ansible-playbook -i inventory/hosts.ini site.yml --check --diff --limit staging
TASK [deploy : Atualizar symlink current para o novo release] ***
--- before
+++ after
@@ -1,4 +1,4 @@
 {
-    "path": "/var/www/minha-app/current -> /var/www/minha-app/releases/20240315120000"
+    "path": "/var/www/minha-app/current -> /var/www/minha-app/releases/20240316093045"
 }

PLAY RECAP *****************************************************
staging01 : ok=8  changed=3  unreachable=0  failed=0  skipped=0

Algumas tarefas que dependem de resultados anteriores (como o timestamp do release) podem reportar skipped no modo --check — isso é comportamento esperado. Valide sempre em staging antes de promover para produção.

Para verificar a sintaxe do Playbook sem executar nada:

ansible-playbook site.yml --syntax-check
playbook: site.yml

Para listar todas as tarefas que seriam executadas, sem rodar nenhuma:

ansible-playbook site.yml --list-tasks

Automatizando deploys em múltiplos VPS com controle de paralelismo

O Ansible executa tarefas em paralelo por padrão em todos os hosts do inventário — o que pode causar downtime total se todos os servidores reiniciarem ao mesmo tempo. A diretiva serial no Playbook controla o deploy gradual (rolling deploy):

---
- name: Deploy gradual em produção
  hosts: production
  serial: 1
  max_fail_percentage: 0

  roles:
    - deploy

Com serial: 1, o Ansible processa um servidor por vez. Com serial: "50%", processa metade dos hosts simultaneamente. A diretiva max_fail_percentage: 0 interrompe o deploy imediatamente se qualquer host falhar, evitando que o problema se propague.

Para deploys com health check entre cada servidor:

- name: Verificar saúde da aplicação após deploy
  uri:
    url: "http://{{ ansible_host }}/health"
    status_code: 200
    timeout: 30
  retries: 5
  delay: 10
  register: health_check
  until: health_check.status == 200

Esse padrão garante que o próximo servidor só receba o deploy após o anterior estar respondendo corretamente — fundamental para ambientes de alta disponibilidade.

Problemas comuns e como resolver

Sintoma: erro "Python not found" ao executar o Playbook

Causa: o servidor de destino não tem Python 3 instalado ou o Ansible está procurando no caminho errado. Em distribuições minimalistas como Debian 12 slim, o Python pode não estar presente por padrão.
Solução: adicione a variável ansible_python_interpreter no inventário ou instale o Python manualmente antes do primeiro Playbook. No inventário: web01 ansible_host=x.x.x.x ansible_python_interpreter=/usr/bin/python3. Para instalar: ansible all -m raw -a "apt-get install -y python3" (o módulo raw não requer Python).

Sintoma: tarefa "git clone" falha com "Host key verification failed"

Causa: o servidor de destino nunca se conectou ao host Git (GitHub, GitLab) e a chave do host não está no known_hosts do usuário remoto.
Solução: adicione accept_hostkey: true no módulo git do Playbook (já incluído no exemplo acima) ou pré-popule o known_hosts com uma tarefa dedicada: ansible all -m known_hosts -a "name=github.com key={{ lookup('pipe', 'ssh-keyscan github.com') }}".

Sintoma: handler "restart app service" não é executado

Causa: handlers só são disparados ao final do Play, e apenas se a tarefa que os notifica reportar changed: true. Se a tarefa anterior não alterou nada (idempotência), o handler não é chamado.
Solução: force a notificação explícita com changed_when: true na tarefa de atualização do symlink, ou use meta: flush_handlers para executar handlers imediatamente após um ponto específico do Playbook.

Sintoma: deploy falha com "sudo: no tty present and no askpass program specified"

Causa: o usuário remoto requer senha para sudo, mas o Ansible não tem como fornecê-la de forma interativa.
Solução: configure o sudoers no servidor de destino para permitir sudo sem senha para o usuário de deploy: adicione a linha deploy ALL=(ALL) NOPASSWD: ALL no arquivo /etc/sudoers.d/deploy. Use visudo para editar com validação de sintaxe.

Sintoma: Playbook demora muito em ambientes com muitos hosts

Causa: o fator de fork padrão do Ansible é 5, o que limita o paralelismo em inventários grandes.
Solução: aumente o valor de forks no ansible.cfg: forks = 20. Ative também o pipelining para reduzir o número de conexões SSH por tarefa: pipelining = True na seção [ssh_connection].

Perguntas frequentes sobre Ansible para deploys no Linux

O Ansible precisa de agente instalado nos servidores remotos?

Não. O Ansible opera sem agente (agentless), usando apenas SSH e Python no servidor remoto. Basta que o servidor de destino tenha Python 3 instalado e que a chave SSH do nó de controle esteja autorizada no arquivo authorized_keys do usuário remoto. Essa arquitetura simplifica enormemente a gestão de infraestrutura, pois não há processos adicionais rodando nos servidores de destino.

Qual a diferença entre um Playbook e um Role no Ansible?

Um Playbook é um arquivo YAML que descreve uma sequência de tarefas a executar em hosts específicos — é o ponto de entrada da automação. Um Role é uma estrutura de diretórios que organiza tarefas, variáveis, templates e handlers reutilizáveis, permitindo compartilhar e versionar configurações entre projetos diferentes. Pense no Playbook como o roteiro e no Role como um módulo reutilizável que o roteiro chama.

Como testar um Playbook Ansible sem aplicar mudanças reais no servidor?

Use o modo dry-run com a flag --check ao executar o comando ansible-playbook. Combine com --diff para visualizar exatamente quais linhas de arquivos seriam alteradas. Nenhuma mudança é aplicada ao servidor durante essa execução — é a forma mais segura de validar um Playbook antes de promovê-lo para produção.

É possível usar Ansible para fazer rollback de um deploy?

Sim. A prática mais comum é manter versões anteriores em diretórios numerados no servidor e usar um symlink apontando para a versão ativa. O Playbook de rollback simplesmente redireciona o symlink para a versão anterior e reinicia o serviço, sem necessidade de novo upload de arquivos. Essa abordagem torna o rollback quase instantâneo, independentemente do tamanho da aplicação.

Ansible funciona bem para gerenciar múltiplos VPS simultaneamente?

Sim. O Ansible executa tarefas em paralelo em múltiplos hosts definidos no arquivo de inventário. É possível controlar o grau de paralelismo com a diretiva serial no Playbook, útil para deploys graduais que evitam downtime total em ambientes com vários servidores. Aumentar o valor de forks no ansible.cfg também melhora a performance em inventários grandes.

Conclusão

  • Comece pelo inventário e conectividade SSH: valide com ansible all -m ping antes de escrever qualquer Playbook — problemas de acesso são a causa número um de falhas em deploys automatizados.
  • Adote a estrutura de Roles desde o início: mesmo para projetos pequenos, separar tarefas em Roles facilita a manutenção, o reuso e a colaboração em equipe à medida que a infraestrutura cresce.
  • Nunca pule o dry-run em produção: execute sempre --check --diff em staging antes de aplicar em produção, e mantenha pelo menos 5 releases versionados para garantir rollback rápido em caso de falha.

Leia também

Precisa de ajuda com automação de deploys no seu servidor?

Ter uma infraestrutura Linux estável e bem configurada é o primeiro passo para que o Ansible funcione de forma confiável. Os planos de VPS da AviraHost oferecem acesso root completo, suporte a chaves SSH e Python 3 pré-instalado, prontos para receber seus Playbooks.

Conheça os planos de VPS da AviraHost


Esta resposta foi útil?