Translate

terça-feira, 26 de novembro de 2024

Ansible : Quando um Programador Descobre que Automatizar 500 Servidores Manualmente é um Problema de Lógica — e Também de Sanidade

 

Bellacosa Mainframe apresenta o ansible

☕ Um Café no Bellacosa Mainframe

Ansible sem Mistérios para Programadores COBOL

Quando um Programador Descobre que Automatizar 500 Servidores Manualmente é um Problema de Lógica — e Também de Sanidade

No começo, havia o operador.

Depois veio o administrador de sistemas.

Em seguida, surgiu o programador COBOL, carregando um JCL debaixo do braço, uma caneca de café na mão e a saudável desconfiança de quem já viu um simples espaço em branco causar um desastre em produção.

Então alguém apresentou o Ansible.

— Com isso você pode administrar centenas de máquinas ao mesmo tempo.

O programador COBOL olhou para a tela, viu um arquivo YAML cheio de espaços e perguntou:

— E onde está a coluna 7?

Foi assim que começou esta viagem.

Este artigo é um guia para programadores COBOL iniciantes que desejam entender Ansible sem precisar abandonar tudo o que já aprenderam sobre lógica, processamento em lote, organização de programas, controle operacional e sobrevivência corporativa.

O Ansible pode parecer uma tecnologia completamente diferente do mainframe. Entretanto, quando observamos com cuidado, encontramos conceitos familiares:

  • inventários lembram catálogos de recursos;

  • Playbooks lembram JCLs ou procedimentos operacionais;

  • Roles lembram PROCs reutilizáveis;

  • módulos lembram programas utilitários;

  • variáveis lembram símbolos de JCL;

  • Handlers lembram rotinas executadas somente quando uma condição ocorre;

  • pipelines lembram cadeias de JOBs;

  • idempotência lembra uma operação projetada para não destruir o ambiente ao ser executada novamente.

A principal diferença é que o Ansible foi criado para administrar ambientes distribuídos: Linux, Windows, redes, Cloud, contêineres, APIs e até IBM Z.

Pegue sua toalha, sua caneca e, principalmente, não entre em pânico.


1. O que é Ansible?

Ansible é uma plataforma de automação de tecnologia da informação.

Ele pode ser usado para:

  • configurar servidores;

  • instalar softwares;

  • criar usuários;

  • publicar aplicações;

  • alterar arquivos;

  • administrar serviços;

  • executar comandos;

  • provisionar infraestrutura;

  • automatizar redes;

  • integrar ambientes de Cloud;

  • organizar pipelines;

  • executar operações em z/OS.

Em termos simples, o Ansible permite descrever aquilo que você deseja que aconteça em um ambiente.

Por exemplo:

Quero que o Nginx esteja instalado, iniciado e configurado para subir automaticamente.

Em vez de acessar manualmente cada servidor, o Ansible executa a operação em todas as máquinas definidas.

Considere uma empresa com 300 servidores Linux.

Sem automação, alguém poderia tentar:

Conectar no servidor 1
Instalar o pacote
Copiar o arquivo
Reiniciar o serviço

Conectar no servidor 2
Instalar o pacote
Copiar o arquivo
Reiniciar o serviço

Conectar no servidor 3...

No servidor 137, provavelmente surgiria uma interrupção, uma reunião, uma emergência ou um café particularmente interessante. A partir desse ponto, ninguém teria certeza de quais servidores foram atualizados.

Com Ansible, descrevemos a operação uma vez:

---
- name: Configurar servidores web
  hosts: webservers
  become: true

  tasks:
    - name: Garantir que o Nginx esteja instalado
      ansible.builtin.package:
        name: nginx
        state: present

    - name: Garantir que o Nginx esteja iniciado
      ansible.builtin.service:
        name: nginx
        state: started
        enabled: true

O Ansible se conecta aos servidores, verifica a situação atual e executa apenas as mudanças necessárias.

Essa última parte é fundamental.


2. A ideia de estado desejado

Um script tradicional costuma dizer:

Execute este comando.

O Ansible normalmente diz:

Garanta que o recurso esteja neste estado.

Compare os dois exemplos.

Script imperativo

apt install nginx -y
systemctl start nginx
systemctl enable nginx

O script ordena ações.

Playbook declarativo

- name: Garantir que o Nginx esteja instalado
  ansible.builtin.apt:
    name: nginx
    state: present

- name: Garantir que o Nginx esteja iniciado e habilitado
  ansible.builtin.service:
    name: nginx
    state: started
    enabled: true

O Playbook descreve o resultado desejado.

Essa é uma das bases da chamada Infrastructure as Code, ou infraestrutura como código.

A configuração do ambiente deixa de existir apenas na memória do administrador e passa a ser representada por arquivos versionados, revisáveis e executáveis.

Em outras palavras, a documentação começa a trabalhar.

Uma raridade tão impressionante quanto encontrar uma impressora corporativa que funcione na primeira tentativa.


3. Agentless: o Ansible não exige um agente permanente

Uma das principais características do Ansible é sua arquitetura normalmente classificada como agentless.

Isso significa que, na maioria dos casos, não é necessário instalar um agente dedicado em cada máquina administrada.

O Ansible utiliza mecanismos já existentes.

Em Linux e Unix, geralmente:

SSH

Em Windows:

WinRM
PowerShell

Em equipamentos de rede:

SSH
APIs
NETCONF
HTTPAPI
CLI

Em z/OS, dependendo da Collection e da operação:

SSH
ZOAU
APIs
z/OSMF

O computador de onde o Ansible é executado recebe o nome de Control Node.

As máquinas administradas são chamadas de:

Managed Nodes

A arquitetura básica é:

              CONTROL NODE
                 Ansible
                    |
          -----------------------
          |          |          |
         SSH        SSH        SSH
          |          |          |
       Servidor1  Servidor2  Servidor3

O Control Node contém:

  • Ansible;

  • inventários;

  • Playbooks;

  • variáveis;

  • Roles;

  • Collections;

  • credenciais;

  • arquivos de configuração.

Os Managed Nodes recebem as tarefas.

Curiosidade importante

“Agentless” não significa que absolutamente nada seja necessário na máquina remota.

Muitos módulos para Linux dependem da presença de Python. Outros dispositivos utilizam APIs ou bibliotecas específicas. No z/OS, determinadas automações podem depender do Z Open Automation Utilities.

A ideia correta é:

Não existe normalmente um agente Ansible permanente funcionando em cada host.


4. Inventory: o mapa da galáxia

Antes de viajar, precisamos saber para onde estamos indo.

O Inventory é a lista dos sistemas que serão administrados pelo Ansible.

Um inventário simples no formato INI pode ser:

[webservers]
web01
web02
web03

[databases]
db01
db02

Também podemos usar YAML:

---
all:
  children:
    webservers:
      hosts:
        web01:
        web02:
        web03:

    databases:
      hosts:
        db01:
        db02:

Os grupos permitem executar tarefas em conjuntos específicos.

Exemplo:

ansible webservers -m ping

Somente os servidores do grupo webservers serão testados.

Variáveis no inventário

Podemos informar endereços e usuários:

---
all:
  children:
    webservers:
      hosts:
        web01:
          ansible_host: 192.168.10.11

        web02:
          ansible_host: 192.168.10.12

      vars:
        ansible_user: automation
        ansible_port: 22

O nome web01 funciona como uma identidade lógica.

O endereço real está em:

ansible_host: 192.168.10.11

Isso é semelhante à diferença entre um nome simbólico e o recurso físico correspondente.


5. Inventário estático e inventário dinâmico

Um inventário estático é escrito manualmente.

Ele funciona bem quando os servidores mudam pouco.

Entretanto, ambientes modernos podem crescer e diminuir automaticamente.

Em uma Cloud, hoje podemos ter 40 máquinas. Amanhã, 120. Depois de amanhã, 17, porque algum gerente finalmente percebeu a conta.

Para esses ambientes existe o Dynamic Inventory.

O Ansible consulta uma fonte externa, como:

  • AWS;

  • Azure;

  • Google Cloud;

  • VMware;

  • OpenStack;

  • IBM Cloud;

  • CMDB;

  • ServiceNow;

  • scripts;

  • APIs internas.

O inventário é gerado em tempo de execução.

Assim, não precisamos editar manualmente o arquivo sempre que uma máquina nasce, muda ou desaparece no grande buraco negro do autoscaling.


6. Comandos Ad-Hoc

Os comandos Ad-Hoc são úteis para operações rápidas.

Por exemplo, testar conectividade:

ansible all -m ping

É importante observar que o módulo ping do Ansible não é o mesmo comando ICMP tradicional.

Ele verifica se o Ansible consegue:

  • conectar;

  • autenticar;

  • executar um módulo;

  • receber uma resposta.

Podemos consultar o uptime:

ansible all -m command -a "uptime"

Consultar espaço em disco:

ansible all -m shell -a "df -h"

Copiar um arquivo:

ansible all \
  -m copy \
  -a "src=aviso.txt dest=/tmp/aviso.txt"

Reiniciar um serviço:

ansible webservers \
  -m service \
  -a "name=nginx state=restarted" \
  --become

Os comandos Ad-Hoc são excelentes para diagnóstico e intervenções pontuais.

Porém, se uma operação precisa ser:

  • repetida;

  • auditada;

  • versionada;

  • revisada;

  • executada novamente no futuro;

ela provavelmente deve virar um Playbook.


7. Playbooks: o JCL da automação distribuída

Um Playbook é um arquivo YAML que descreve uma ou mais automações.

Para um programador COBOL, podemos fazer uma analogia aproximada:

JCL define uma execução em mainframe.
Playbook define uma automação em um conjunto de hosts.

Um Playbook básico:

---
- name: Configurar servidores de aplicação
  hosts: appservers
  become: true

  tasks:
    - name: Instalar Java
      ansible.builtin.package:
        name: java-17-openjdk
        state: present

    - name: Criar diretório da aplicação
      ansible.builtin.file:
        path: /opt/minha-app
        state: directory
        owner: app
        group: app
        mode: "0750"

Os principais elementos são:

name:
hosts:
become:
vars:
tasks:
handlers:
roles:

name

É a descrição do Play ou da tarefa.

name: Instalar Java

Escolha nomes claros. Quando algo falhar às três da manhã, “Executar coisa” não será uma descrição reconfortante.

hosts

Define os alvos:

hosts: appservers

become

Solicita elevação de privilégio:

become: true

É semelhante ao uso de sudo.

tasks

Contém as tarefas a executar.


8. YAML: o universo onde os espaços têm poder

YAML é uma linguagem de serialização de dados muito utilizada em automação.

Ela é legível, mas possui uma característica inquietante:

A indentação faz parte da estrutura.

Exemplo correto:

tasks:
  - name: Instalar Nginx
    ansible.builtin.package:
      name: nginx
      state: present

Exemplo incorreto:

tasks:
  - name: Instalar Nginx
      ansible.builtin.package:
    name: nginx

Para quem conhece COBOL, isso não deveria causar tanto choque. Afinal, fomos treinados por décadas a respeitar colunas, níveis, pontos e estruturas.

Regras práticas

Use espaços, não TAB.

Mantenha uma indentação consistente, normalmente dois espaços.

Inicie arquivos com:

---

Use aspas quando um valor puder ser interpretado incorretamente:

mode: "0644"

Valide a sintaxe:

ansible-playbook playbook.yml --syntax-check

Use análise de qualidade:

ansible-lint playbook.yml

Easter egg para veteranos

YAML significa originalmente “Yet Another Markup Language”.

Posteriormente, o significado passou a ser “YAML Ain’t Markup Language”, uma sigla recursiva.

Ou seja, a própria linguagem entrou em uma discussão existencial sobre o que ela é. Algo perfeitamente normal no universo da tecnologia.


9. Módulos: os utilitários do Ansible

Os módulos são unidades de trabalho.

Exemplos:

package
apt
dnf
copy
template
file
user
group
service
systemd
uri
command
shell
debug
assert
fail

Um módulo realiza uma operação específica.

Exemplo:

- name: Criar usuário
  ansible.builtin.user:
    name: vagner
    state: present
    shell: /bin/bash

A forma totalmente qualificada:

ansible.builtin.user

é chamada de FQCN, ou Fully Qualified Collection Name.

Ela mostra exatamente de onde vem o módulo.

Isso evita ambiguidades entre módulos com nomes semelhantes.

command ou shell?

command executa diretamente um programa:

- name: Consultar uptime
  ansible.builtin.command:
    cmd: uptime

shell executa por meio de um shell:

- name: Procurar processo
  ansible.builtin.shell:
    cmd: "ps -ef | grep nginx"

Use shell apenas quando precisar de:

  • pipes;

  • redirecionamento;

  • curingas;

  • expansão de variáveis;

  • operadores como &&.

Sempre que existir um módulo específico, prefira o módulo.

Ruim:

- name: Criar usuário
  ansible.builtin.shell:
    cmd: useradd vagner

Melhor:

- name: Garantir que o usuário exista
  ansible.builtin.user:
    name: vagner
    state: present

10. Idempotência: executar novamente sem destruir o universo

Idempotência é uma das palavras centrais no Ansible.

Uma operação idempotente produz o mesmo estado final mesmo quando executada várias vezes.

Considere:

- name: Garantir que o diretório exista
  ansible.builtin.file:
    path: /opt/app
    state: directory

Na primeira execução:

Diretório não existe.
Ansible cria.
Resultado: changed

Na segunda:

Diretório já existe.
Nenhuma alteração.
Resultado: ok

Na terceira:

Continua existindo.
Resultado: ok

Esse comportamento é vital em automação.

Um Playbook não deve depender da esperança de que alguém se lembre se ele já foi executado.

Analogia com COBOL

Imagine um programa batch que recebe um arquivo e insere registros sem verificar duplicidade.

Executá-lo duas vezes pode produzir registros duplicados.

Um processamento idempotente verifica se o dado já existe ou utiliza uma chave que impede duplicação.

No Ansible, os módulos são projetados para verificar o estado antes de agir.


11. Variáveis

Variáveis tornam os Playbooks flexíveis.

vars:
  package_name: nginx
  service_name: nginx
  http_port: 80

Uso:

- name: Instalar pacote
  ansible.builtin.package:
    name: "{{ package_name }}"
    state: present

As chaves duplas:

{{ package_name }}

indicam uma expressão Jinja2.

Variáveis podem vir de diversos lugares:

  • Playbook;

  • Inventory;

  • group_vars;

  • host_vars;

  • Role;

  • linha de comando;

  • arquivos externos;

  • facts;

  • Vault.

group_vars e host_vars

Variáveis para um grupo:

group_vars/webservers.yml
---
http_port: 8080
package_name: nginx

Variáveis para um host:

host_vars/web01.yml
---
http_port: 9090

O host web01 poderá usar um valor específico.


12. Facts: o Ansible investigando o sistema

Facts são informações coletadas dos hosts.

Exemplos:

  • hostname;

  • sistema operacional;

  • versão;

  • kernel;

  • CPU;

  • memória;

  • interfaces;

  • endereços IP;

  • discos;

  • arquitetura.

Podemos visualizar facts:

ansible all -m setup

No Playbook:

- name: Mostrar distribuição
  ansible.builtin.debug:
    msg: "Sistema: {{ ansible_facts['distribution'] }}"

Podemos tomar decisões:

- name: Instalar Apache em sistemas Red Hat
  ansible.builtin.dnf:
    name: httpd
    state: present
  when: ansible_facts['os_family'] == 'RedHat'

Outro exemplo:

- name: Instalar Apache em Debian
  ansible.builtin.apt:
    name: apache2
    state: present
  when: ansible_facts['os_family'] == 'Debian'

Facts permitem escrever Playbooks adaptáveis.

Entretanto, coletar facts possui custo.

Quando não forem necessários:

gather_facts: false

Em milhares de máquinas, evitar uma coleta desnecessária pode economizar bastante tempo.


13. Condicionais

A cláusula when decide se uma tarefa será executada.

- name: Reiniciar serviço somente em produção
  ansible.builtin.service:
    name: app
    state: restarted
  when: environment == "production"

Verificar se uma variável existe:

when: app_port is defined

Verificar se não existe:

when: app_port is not defined

Comparação numérica:

when: free_space_mb | int < 1000

Para quem vem do COBOL:

IF condição
    EXECUTE tarefa
END-IF

No Ansible:

when: condição

O princípio é o mesmo. Apenas trocaram o END-IF por uma indentação que observa você em silêncio.


14. Loops

Loops repetem tarefas.

- name: Instalar pacotes
  ansible.builtin.package:
    name: "{{ item }}"
    state: present
  loop:
    - nginx
    - git
    - curl

Para um programador COBOL, isso lembra:

PERFORM VARYING WS-I FROM 1 BY 1
    UNTIL WS-I > 3

Podemos trabalhar com estruturas:

- name: Criar usuários
  ansible.builtin.user:
    name: "{{ item.name }}"
    groups: "{{ item.groups }}"
    state: present

  loop:
    - name: ana
      groups: developers

    - name: bruno
      groups: operations

    - name: carla
      groups: auditors

Cada item possui propriedades.


15. Register: guardando o resultado

A palavra register armazena o resultado de uma tarefa.

- name: Consultar espaço em disco
  ansible.builtin.command:
    cmd: df -P /opt
  register: disk_result
  changed_when: false

Depois:

- name: Mostrar saída
  ansible.builtin.debug:
    var: disk_result.stdout

Um resultado pode conter:

stdout
stderr
rc
changed
failed
results

Podemos reagir ao código de retorno:

- name: Falhar quando o comando retornar erro
  ansible.builtin.fail:
    msg: "A verificação falhou."
  when: disk_result.rc != 0

Essa lógica é familiar para qualquer pessoa que já analisou RETURN-CODE, MAXCC, SQLCODE ou um ABEND que decidiu surgir cinco minutos antes do fim do expediente.


16. Handlers: agir apenas quando algo mudou

Handlers são tarefas executadas quando notificadas por outra tarefa.

Exemplo:

tasks:
  - name: Publicar configuração do Nginx
    ansible.builtin.template:
      src: nginx.conf.j2
      dest: /etc/nginx/nginx.conf
    notify: Reiniciar Nginx

handlers:
  - name: Reiniciar Nginx
    ansible.builtin.service:
      name: nginx
      state: restarted

O Handler somente será acionado quando o arquivo for alterado.

Se não houver mudança:

Nenhum restart.

Se dez tarefas notificarem o mesmo Handler:

O Handler normalmente executa uma vez ao final do Play.

Isso evita reinicializações desnecessárias.

Analogia

Imagine dez etapas atualizando parâmetros de uma aplicação.

Sem Handler:

Altera parâmetro.
Reinicia.

Altera outro parâmetro.
Reinicia.

Altera certificado.
Reinicia.

Com Handler:

Executa todas as alterações.
Reinicia uma vez.

Menos indisponibilidade, menos risco e menos oportunidades para o servidor desenvolver personalidade própria.


17. Tags

Tags permitem executar partes específicas do Playbook.

- name: Instalar aplicação
  ansible.builtin.package:
    name: minha-app
    state: present
  tags:
    - install
    - application

Execução:

ansible-playbook site.yml --tags install

Pular tarefas:

ansible-playbook site.yml --skip-tags debug

Tags são úteis para:

  • manutenção;

  • instalação;

  • configuração;

  • validação;

  • depuração;

  • operações seletivas.

Porém, use com cuidado.

Executar apenas uma etapa pode ignorar dependências anteriores.

Um Playbook deve continuar coerente mesmo quando dividido por tags.


18. Roles: organizando a automação

Quando um Playbook cresce, ele pode virar uma criatura de milhares de linhas que ninguém deseja encontrar em um corredor escuro.

Roles resolvem esse problema.

Uma Role organiza arquivos por finalidade:

roles/
└── webserver/
    ├── tasks/
    │   └── main.yml
    ├── handlers/
    │   └── main.yml
    ├── defaults/
    │   └── main.yml
    ├── vars/
    │   └── main.yml
    ├── templates/
    ├── files/
    ├── meta/
    │   └── main.yml
    └── README.md

Diretórios principais

tasks contém as tarefas.

handlers contém os Handlers.

defaults contém variáveis padrão de baixa precedência.

vars contém variáveis da Role.

templates contém arquivos Jinja2.

files contém arquivos estáticos.

meta pode declarar dependências.

Uso:

---
- name: Configurar servidores web
  hosts: webservers
  become: true

  roles:
    - common
    - security
    - webserver

Analogia com mainframe

Uma Role pode ser comparada a uma PROC ou componente reutilizável.

Em vez de repetir passos em todos os Playbooks, centralizamos a lógica.


19. Templates e Jinja2

Templates permitem gerar arquivos diferentes para cada máquina.

Exemplo:

server {
    listen {{ http_port }};
    server_name {{ inventory_hostname }};

    location / {
        proxy_pass http://127.0.0.1:{{ app_port }};
    }
}

O arquivo pode ser chamado:

nginx.conf.j2

A tarefa:

- name: Gerar configuração
  ansible.builtin.template:
    src: nginx.conf.j2
    dest: /etc/nginx/conf.d/app.conf
    owner: root
    group: root
    mode: "0644"
  notify: Recarregar Nginx

O mesmo template produz configurações diferentes com base nas variáveis de cada host.

Condicionais no template

{% if environment == "production" %}
log_level error;
{% else %}
log_level debug;
{% endif %}

Loops no template

{% for server in backend_servers %}
server {{ server }};
{% endfor %}

Filtros

{{ app_name | upper }}
{{ user_name | lower }}
{{ value | default('desconhecido') }}

Jinja2 transforma dados em arquivos de configuração.

É como uma combinação de STRING, edição de relatórios, geração de parâmetros e um toque de magia burocrática.


20. Ansible Vault

Nunca grave senhas diretamente no Playbook.

Não faça isto:

db_password: admin123

Também não faça isto seguido da frase:

Depois eu removo.

Essa frase é uma das principais causas de segredos permanentes em repositórios.

O Ansible Vault criptografa arquivos ou variáveis.

Criar arquivo:

ansible-vault create secrets.yml

Criptografar arquivo existente:

ansible-vault encrypt secrets.yml

Editar:

ansible-vault edit secrets.yml

Visualizar:

ansible-vault view secrets.yml

Executar Playbook:

ansible-playbook site.yml --ask-vault-pass

Também podemos usar um arquivo de senha controlado:

ansible-playbook site.yml \
  --vault-password-file /caminho/protegido/vault.pass

Segurança adicional

Em tarefas que manipulam segredos:

- name: Configurar credencial
  ansible.builtin.debug:
    msg: "{{ db_password }}"
  no_log: true

O no_log impede a exibição do conteúdo sensível.

Entretanto, ele também reduz informações de diagnóstico. Use somente onde necessário.

Vault não resolve tudo

Ainda é necessário controlar:

  • quem possui a senha;

  • rotação de credenciais;

  • segregação entre ambientes;

  • auditoria;

  • armazenamento seguro;

  • acesso da pipeline.

Em ambientes maiores, podem ser usados:

  • HashiCorp Vault;

  • CyberArk;

  • AWS Secrets Manager;

  • Azure Key Vault;

  • IBM Cloud Secrets Manager;

  • credenciais protegidas do Jenkins;

  • Ansible Automation Platform Credentials.


21. Tratamento de erros com Block, Rescue e Always

Ansible possui uma estrutura semelhante ao tratamento de exceções.

- name: Atualizar aplicação
  block:
    - name: Publicar nova versão
      ansible.builtin.copy:
        src: app.jar
        dest: /opt/app/app.jar

    - name: Reiniciar aplicação
      ansible.builtin.service:
        name: app
        state: restarted

  rescue:
    - name: Restaurar versão anterior
      ansible.builtin.copy:
        src: app.jar.backup
        dest: /opt/app/app.jar

    - name: Informar falha
      ansible.builtin.debug:
        msg: "Falha detectada. Rollback executado."

  always:
    - name: Registrar encerramento
      ansible.builtin.debug:
        msg: "Processo de atualização encerrado."

block contém a operação principal.

rescue executa quando uma tarefa do bloco falha.

always executa independentemente do resultado.

Outros controles

Ignorar erro:

ignore_errors: true

Use com extrema cautela.

Definir falha personalizada:

failed_when: disk_result.rc != 0

Definir mudança personalizada:

changed_when: false

Retry:

- name: Aguardar aplicação responder
  ansible.builtin.uri:
    url: http://localhost:8080/health
    status_code: 200
  register: health
  retries: 10
  delay: 5
  until: health.status == 200

Isso tenta até dez vezes, aguardando cinco segundos entre as tentativas.


22. Ansible Galaxy e Collections

Ansible Galaxy é um catálogo de conteúdo reutilizável.

Podemos encontrar:

  • Roles;

  • Collections;

  • módulos;

  • plugins;

  • exemplos;

  • documentação.

Instalar uma Role:

ansible-galaxy role install geerlingguy.nginx

Instalar uma Collection:

ansible-galaxy collection install community.general

Uma Collection agrupa diferentes tipos de conteúdo.

Exemplos:

community.general
ansible.posix
amazon.aws
azure.azcollection
community.vmware
ibm.ibm_zos_core

Role versus Collection

Role:

Automação organizada para uma finalidade.

Collection:

Pacote maior contendo módulos, plugins, Roles, documentação e outros recursos.

requirements.yml

Dependências devem ser declaradas:

---
collections:
  - name: community.general
    version: 10.4.0

  - name: ansible.posix
    version: 1.6.2

roles:
  - name: geerlingguy.nginx
    version: 3.2.0

Instalação:

ansible-galaxy install -r requirements.yml

Fixar versões aumenta a previsibilidade.

Sem isso, uma atualização externa pode transformar uma pipeline estável em uma aventura filosófica sobre compatibilidade.

Cuidado com conteúdo externo

Antes de usar uma Role ou Collection, avalie:

  • autor;

  • reputação;

  • documentação;

  • atualização;

  • testes;

  • código;

  • licenciamento;

  • versões suportadas;

  • dependências;

  • permissões exigidas.

Não execute conteúdo desconhecido com privilégios administrativos apenas porque ele possui um ícone simpático.


23. Estrutura profissional de projeto

Um projeto organizado pode ter:

ansible-project/
├── ansible.cfg
├── requirements.yml
├── README.md
├── inventories/
│   ├── dev/
│   │   ├── hosts.yml
│   │   └── group_vars/
│   ├── test/
│   │   ├── hosts.yml
│   │   └── group_vars/
│   └── prod/
│       ├── hosts.yml
│       └── group_vars/
├── playbooks/
│   ├── site.yml
│   ├── deploy.yml
│   └── rollback.yml
├── roles/
│   ├── common/
│   ├── security/
│   ├── webserver/
│   └── application/
├── templates/
└── files/

Essa estrutura separa:

  • ambientes;

  • código;

  • configurações;

  • dados;

  • dependências;

  • documentação.

Dica

Nunca misture produção e desenvolvimento no mesmo inventário sem uma razão extremamente boa, três aprovações e talvez a presença de um adulto responsável.


24. Boas práticas

Use módulos idempotentes

Prefira:

ansible.builtin.user
ansible.builtin.package
ansible.builtin.service
ansible.builtin.copy

em vez de comandos arbitrários.

Utilize FQCN

Prefira:

ansible.builtin.copy

em vez de:

copy

Escreva nomes claros

Ruim:

- name: Fazer ajuste

Melhor:

- name: Publicar configuração TLS do portal corporativo

Valide arquivos antes de substituir

- name: Publicar configuração do Nginx
  ansible.builtin.template:
    src: nginx.conf.j2
    dest: /etc/nginx/nginx.conf
    validate: "nginx -t -c %s"

O Ansible valida o arquivo antes de colocá-lo em produção.

Use privilégio mínimo

Evite aplicar:

become: true

em tudo quando apenas algumas tarefas precisam de privilégios.

Documente

Mantenha um README.md com:

  • finalidade;

  • requisitos;

  • variáveis;

  • exemplos;

  • dependências;

  • procedimento de execução;

  • rollback;

  • responsáveis.

Teste antes da produção

Use:

ansible-playbook site.yml --syntax-check

Depois:

ansible-playbook site.yml --check --diff

Por fim, execute em um ambiente de teste.

O modo Check ajuda, mas não é perfeito. Nem todos os módulos simulam integralmente as mudanças.


25. Desempenho

Facts

Desative quando não forem necessários:

gather_facts: false

Forks

Em ansible.cfg:

[defaults]
forks = 30

Isso controla quantos hosts podem ser processados paralelamente.

Aumentar o número pode acelerar a execução, mas também pode:

  • sobrecarregar o Control Node;

  • saturar a rede;

  • sobrecarregar APIs;

  • atingir limites dos servidores;

  • aumentar o impacto de uma falha.

SSH Multiplexing

[ssh_connection]
ssh_args = -o ControlMaster=auto -o ControlPersist=60s
pipelining = True

Isso permite reutilizar conexões SSH.

Serial

Atualize grupos menores:

- name: Atualização gradual
  hosts: webservers
  serial: 5

O Ansible processa cinco servidores por vez.

Essa estratégia é importante em produção.


26. Git, Jenkins e Ansible

Um fluxo DevOps comum é:

Desenvolvedor altera código
        ↓
Git recebe a mudança
        ↓
Pull Request é revisado
        ↓
Jenkins inicia a pipeline
        ↓
Sintaxe é validada
        ↓
Lint é executado
        ↓
Playbook é testado
        ↓
Ansible executa o deploy
        ↓
Resultado é registrado

Git armazena e versiona.

Jenkins coordena.

Ansible executa.

Podemos resumir assim:

Git       = fonte oficial
Jenkins   = maestro
Ansible   = executor
Inventory = mapa
Playbook  = plano operacional

Exemplo de pipeline

pipeline {
    agent any

    stages {
        stage('Checkout') {
            steps {
                git url: 'https://git.example/ansible.git'
            }
        }

        stage('Syntax Check') {
            steps {
                sh '''
                  ansible-playbook \
                    playbooks/deploy.yml \
                    --syntax-check
                '''
            }
        }

        stage('Lint') {
            steps {
                sh 'ansible-lint playbooks/deploy.yml'
            }
        }

        stage('Dry Run') {
            steps {
                sh '''
                  ansible-playbook \
                    -i inventories/test/hosts.yml \
                    playbooks/deploy.yml \
                    --check --diff
                '''
            }
        }

        stage('Deploy') {
            steps {
                sh '''
                  ansible-playbook \
                    -i inventories/prod/hosts.yml \
                    playbooks/deploy.yml \
                    --serial 2
                '''
            }
        }
    }
}

27. Rolling Update

Em produção, raramente devemos atualizar todos os servidores de uma vez.

Um fluxo seguro pode ser:

  1. retirar servidor do balanceador;

  2. parar aplicação;

  3. instalar versão;

  4. iniciar aplicação;

  5. testar saúde;

  6. recolocar servidor;

  7. avançar para o próximo.

Exemplo:

---
- name: Atualização gradual
  hosts: webservers
  serial: 1
  become: true

  pre_tasks:
    - name: Retirar host do balanceador
      ansible.builtin.uri:
        url: "https://lb.example/api/remove/{{ inventory_hostname }}"
        method: POST
      delegate_to: localhost

  tasks:
    - name: Publicar aplicação
      ansible.builtin.copy:
        src: app.jar
        dest: /opt/app/app.jar
      notify: Reiniciar aplicação

  handlers:
    - name: Reiniciar aplicação
      ansible.builtin.service:
        name: app
        state: restarted

  post_tasks:
    - name: Aguardar aplicação responder
      ansible.builtin.uri:
        url: "http://{{ inventory_hostname }}:8080/health"
        status_code: 200
      register: health
      retries: 10
      delay: 5
      until: health.status == 200

    - name: Recolocar host no balanceador
      ansible.builtin.uri:
        url: "https://lb.example/api/add/{{ inventory_hostname }}"
        method: POST
      delegate_to: localhost

Isso é uma implantação controlada, não uma aposta coletiva.


28. Troubleshooting: quando a nave não responde

Erro de YAML

Valide:

ansible-playbook site.yml --syntax-check

Use:

ansible-lint site.yml

Problemas de inventário

Mostrar estrutura:

ansible-inventory \
  -i inventories/prod/hosts.yml \
  --graph

Mostrar host:

ansible-inventory \
  -i inventories/prod/hosts.yml \
  --host web01

Listar hosts:

ansible webservers \
  -i inventories/prod/hosts.yml \
  --list-hosts

Problemas de SSH

ansible all -m ping -vvv

Verifique:

  • endereço;

  • DNS;

  • porta;

  • usuário;

  • chave;

  • senha;

  • firewall;

  • Python remoto;

  • sudo;

  • jump host;

  • host key.

Erros de permissão

Use become quando necessário:

become: true

Mas também investigue:

  • dono;

  • grupo;

  • modo;

  • ACL;

  • SELinux;

  • AppArmor;

  • filesystem somente leitura;

  • espaço em disco.

Nem todo Permission denied é resolvido adicionando mais privilégio. Às vezes isso apenas transforma um pequeno erro em um erro com autoridade.

Debug

- name: Mostrar variável
  ansible.builtin.debug:
    var: minha_variavel

Limitar execução

ansible-playbook site.yml --limit web01

Verbosidade

ansible-playbook site.yml -v
ansible-playbook site.yml -vv
ansible-playbook site.yml -vvv
ansible-playbook site.yml -vvvv

Quanto mais letras v, mais detalhes.

Eventualmente você descobrirá informações que não sabia que existiam e algumas que preferiria continuar não sabendo.


29. Precedência de variáveis

Ansible pode receber a mesma variável de diversos lugares.

Por exemplo:

defaults da Role
Inventory
group_vars
host_vars
facts
Playbook
task
set_fact
extra-vars

Quando vários lugares definem o mesmo nome, uma regra de precedência decide qual valor vence.

Linha de comando:

ansible-playbook site.yml -e "http_port=9090"

extra-vars possui precedência elevada.

Isso é útil, mas pode causar resultados inesperados.

Para descobrir o valor:

- name: Exibir porta
  ansible.builtin.debug:
    var: http_port

Para inspecionar variáveis de um host:

ansible-inventory \
  -i inventory.yml \
  --host web01

Dica

Evite reutilizar o mesmo nome de variável em muitos níveis.

Um nome claro reduz conflitos:

webserver_http_port
database_connection_port
application_health_port

30. Ansible no IBM Z

Ansible também pode automatizar z/OS.

Uma Collection importante é:

ibm.ibm_zos_core

Ela permite trabalhar, dependendo do ambiente e da configuração, com operações como:

  • datasets;

  • membros de PDS e PDSE;

  • USS;

  • JCL;

  • JOBs;

  • comandos;

  • cópia de arquivos;

  • encode e decode;

  • módulos específicos de z/OS.

Exemplo: submeter JCL

---
- name: Executar JOB no z/OS
  hosts: zos
  gather_facts: false

  tasks:
    - name: Submeter JCL de compilação
      ibm.ibm_zos_core.zos_job_submit:
        src: USER.JCL(COMPILE)
        location: data_set
        wait_time_s: 60
        return_output: true
      register: job_result

    - name: Mostrar resultado
      ansible.builtin.debug:
        var: job_result

Validar retorno

- name: Interromper se o retorno for maior que 4
  ansible.builtin.fail:
    msg: "Compilação COBOL falhou."
  when:
    - job_result.jobs is defined
    - job_result.jobs | length > 0
    - job_result.jobs[0].ret_code.code | int > 4

Possível pipeline COBOL

Código COBOL alterado
        ↓
Commit no Git
        ↓
Jenkins inicia pipeline
        ↓
Ansible envia fontes
        ↓
Ansible submete JCL
        ↓
Compilação é monitorada
        ↓
Return Code é validado
        ↓
Testes são executados
        ↓
LOADLIB é promovida
        ↓
CICS é atualizado

O Ansible não substitui COBOL, JCL, Db2, CICS ou z/OS.

Ele coordena e automatiza tarefas ao redor deles.


31. Ansible, COBOL e a arte de pensar em processos

O programador COBOL possui uma vantagem inesperada ao aprender Ansible.

COBOL ensina:

  • organização;

  • clareza;

  • processamento determinístico;

  • controle de retorno;

  • separação de responsabilidades;

  • atenção ao formato;

  • preocupação com reinício;

  • auditabilidade;

  • tratamento de erros;

  • previsibilidade operacional.

Essas qualidades são essenciais em automação.

Um bom Playbook precisa ser:

Legível
Repetível
Idempotente
Testável
Versionado
Auditável
Seguro
Recuperável

Em outras palavras, Ansible moderno precisa exatamente da disciplina que os ambientes mainframe cultivam há décadas.

A indústria às vezes apresenta infraestrutura como código como uma descoberta revolucionária.

O programador mainframe olha para JCLs, PROCs, parâmetros, bibliotecas controladas e processamento automatizado e pensa:

Interessante. Agora colocaram YAML.


32. Perguntas comuns de entrevistas

O que é Ansible?

Ansible é uma plataforma de automação usada para configuração, implantação, provisionamento e orquestração. Normalmente utiliza SSH ou mecanismos remotos semelhantes e descreve automações em Playbooks YAML.

Por que é agentless?

Porque normalmente não exige um agente Ansible permanente nos hosts administrados. Utiliza SSH, WinRM, APIs ou conexões específicas.

Inventory e Playbook são iguais?

Não.

Inventory informa onde executar.

Playbook informa o que executar.

Módulo e Role são iguais?

Não.

Módulo executa uma operação específica.

Role organiza uma automação completa e reutilizável.

command e shell são iguais?

Não.

command executa diretamente um programa.

shell passa o comando por um shell, permitindo pipes e redirecionamentos.

Variáveis e facts são iguais?

Variáveis são valores definidos ou recebidos.

Facts são informações coletadas dos hosts.

O que é Vault?

É o recurso de criptografia de dados sensíveis do Ansible.

O que são Handlers?

São tarefas executadas quando notificadas, normalmente em resposta a uma mudança.

O que é idempotência?

É a propriedade de atingir o mesmo estado final mesmo quando a automação é executada repetidamente.


33. Laboratório inicial passo a passo

Passo 1 — Instalar Ansible

Em distribuições baseadas em Debian ou Ubuntu:

sudo apt update
sudo apt install ansible -y

Validar:

ansible --version

Passo 2 — Criar diretório

mkdir -p ~/ansible-lab
cd ~/ansible-lab

Passo 3 — Criar inventário

# inventory.ini

[local]
localhost ansible_connection=local

Passo 4 — Testar

ansible all -i inventory.ini -m ping

Resultado esperado:

localhost | SUCCESS

Passo 5 — Criar Playbook

# primeiro-playbook.yml
---
- name: Primeiro laboratório Ansible
  hosts: local
  gather_facts: true

  tasks:
    - name: Mostrar sistema operacional
      ansible.builtin.debug:
        msg: >
          Estou executando em
          {{ ansible_facts['distribution'] }}
          {{ ansible_facts['distribution_version'] }}

    - name: Criar diretório de laboratório
      ansible.builtin.file:
        path: /tmp/ansible-lab
        state: directory
        mode: "0755"

    - name: Criar arquivo
      ansible.builtin.copy:
        dest: /tmp/ansible-lab/mensagem.txt
        content: |
          Não entre em pânico.
          O Ansible chegou até aqui.
        mode: "0644"

Passo 6 — Verificar sintaxe

ansible-playbook \
  -i inventory.ini \
  primeiro-playbook.yml \
  --syntax-check

Passo 7 — Simular

ansible-playbook \
  -i inventory.ini \
  primeiro-playbook.yml \
  --check --diff

Passo 8 — Executar

ansible-playbook \
  -i inventory.ini \
  primeiro-playbook.yml

Passo 9 — Executar novamente

ansible-playbook \
  -i inventory.ini \
  primeiro-playbook.yml

Na primeira execução, algumas tarefas terão:

changed

Na segunda, deverão retornar:

ok

Você acabou de observar idempotência funcionando.


34. Curiosidades e Easter Eggs

O nome Ansible

O termo “ansible” ficou conhecido na ficção científica como um dispositivo de comunicação instantânea entre grandes distâncias.

O nome combina bem com uma ferramenta que envia instruções para sistemas remotos.

A maioria dos problemas não está no YAML

Quando um Playbook falha, o instinto inicial é culpar a indentação.

Muitas vezes o verdadeiro problema é:

  • DNS;

  • SSH;

  • permissão;

  • variável;

  • pacote inexistente;

  • caminho incorreto;

  • serviço com outro nome;

  • Python ausente;

  • firewall;

  • sistema operacional diferente.

Ou, como diria um operador veterano:

O erro está exatamente onde o sistema disse que está, exceto quando não está.

changed não significa necessariamente sucesso funcional

Uma tarefa pode alterar um arquivo corretamente e ainda assim produzir uma configuração inválida para a aplicação.

Por isso, use:

  • validate;

  • testes;

  • health checks;

  • asserts;

  • rollback;

  • ambiente de homologação.

Automação ruim automatiza erros

Se um procedimento manual ruim for transformado em código sem revisão, teremos apenas um erro mais rápido, mais consistente e capaz de atingir centenas de máquinas simultaneamente.

A automação amplifica competência.

Infelizmente, também amplifica incompetência.

A resposta para tudo não é 42

Em Ansible, frequentemente é:

--check --diff -vvv

Não resolve tudo, mas oferece boas pistas.


35. O verdadeiro salto mental

O aprendiz pergunta:

Qual comando devo usar?

O profissional pergunta:

Qual estado desejo garantir?

O aprendiz escreve:

shell: systemctl restart nginx

O profissional pergunta:

Por que reiniciar? Houve mudança? Posso validar antes? Posso recarregar em vez de reiniciar?

O aprendiz cria um Playbook para funcionar uma vez.

O profissional cria uma automação para:

  • executar repetidamente;

  • falhar com clareza;

  • registrar evidências;

  • preservar segurança;

  • limitar impacto;

  • permitir rollback;

  • ser compreendida por outra pessoa.

Esse é o ponto em que Ansible deixa de ser uma coleção de arquivos YAML e se torna engenharia.


Conclusão — Não entre em pânico, versione o Playbook

Ansible não é apenas uma ferramenta para executar comandos em vários servidores.

Ele representa uma forma estruturada de administrar sistemas.

Com ele, podemos transformar operações manuais em processos:

  • repetíveis;

  • previsíveis;

  • auditáveis;

  • seguros;

  • versionados;

  • testáveis;

  • reutilizáveis.

Para um programador COBOL, muitos conceitos são menos alienígenas do que parecem.

O Inventory define os destinos.

O Playbook organiza a execução.

As Tasks representam passos.

Os módulos realizam operações.

As variáveis parametrizam.

Os Facts descrevem o ambiente.

Os Handlers reagem às mudanças.

As Roles organizam componentes.

As Collections distribuem funcionalidades.

O Vault protege segredos.

Git registra a história.

Jenkins coordena o fluxo.

Ansible executa.

E o z/OS, apesar de observar toda essa modernidade com a serenidade de quem já sobreviveu a inúmeras previsões de extinção, também pode participar dessa automação.

O melhor caminho para aprender é começar pequeno.

Crie um inventário.

Execute um ping.

Escreva um Playbook.

Crie um arquivo.

Instale um pacote.

Use uma variável.

Adicione uma condição.

Implemente um Handler.

Transforme o código em uma Role.

Coloque no Git.

Adicione testes.

Integre a uma pipeline.

Automatize um processo real.

Depois, execute tudo novamente.

Se o resultado continuar previsível, você estará no caminho correto.

Se o ambiente desaparecer, verifique se usou:

state: absent

em algum lugar particularmente inconveniente.

No universo da automação, como no mainframe, toda grande jornada começa com uma pequena instrução.

No COBOL:

PROCEDURE DIVISION.

No Ansible:

---

E em qualquer viagem técnica realmente perigosa:

Não entre em pânico. Faça backup, valide a sintaxe e nunca teste pela primeira vez em produção.

Sem comentários:

Enviar um comentário