Ansible ou Terraform: qual você precisa?
Terraform cria o VPS e Ansible configura o sistema. Entenda a divisão, por que provisioners falham, os comandos de handoff e quando usar só Ansible.
Ansible vs Terraform numa frase
Ansible vs Terraform não é uma escolha entre duas ferramentas que fazem o mesmo trabalho. O Terraform declara que infraestrutura existe: servidores, discos, redes e registos DNS. O Ansible declara o que deve ser verdadeiro dentro de uma máquina que já existe: pacotes, utilizadores, ficheiros de configuração e serviços em execução. O Terraform cria o VPS. O Ansible transforma esse VPS num servidor Web.
Ambos são declarativos e ambos são considerados infraestrutura como código (IaC). A diferença real está naquilo que cada um guarda. O Terraform grava um ficheiro de estado que associa cada recurso do código a um objeto real criado através de uma API. Assim, consegue determinar que a remoção de cinco linhas significa que um servidor tem de ser destruído. O Ansible não guarda estado entre execuções. Liga-se por SSH, inspeciona a máquina e altera apenas o que ainda não corresponde ao playbook.
Esta única diferença explica o restante deste guia, incluindo o motivo pelo qual misturar os dois trabalhos numa só ferramenta causa problemas.
O que o Terraform realmente faz
O Terraform comunica com uma API através de um plugin de provider. A página do registry do seu provider define os tipos de recurso que pode declarar. Por isso, um servidor num host e um servidor noutro host podem ter nomes de recursos diferentes e argumentos diferentes.
resource "cloud_server" "web" {
name = "web1"
image = "ubuntu-24.04"
type = "small"
}
output "web_ip" {
value = cloud_server.web.ipv4_address
}Substitua cloud_server pelo tipo de recurso documentado pelo seu provider. O bloco output é a parte importante para este guia, porque é assim que o endereço sai do Terraform.
terraform init
terraform fmt -check
terraform validate
terraform plan -out=tfplan
terraform apply tfplanterraform init transfere o provider e grava um ficheiro de lock. terraform plan mostra a diferença entre o seu código e o ficheiro de estado. O resultado termina com uma linha semelhante a Plan: 1 to add, 0 to change, 0 to destroy.. Leia essa linha sempre. Alguns argumentos não podem ser alterados no local. O plano indica isso com # forces replacement junto ao atributo, seguido de 1 to add, 0 to change, 1 to destroy. Aplicar esse plano elimina o servidor e cria um novo servidor vazio. É assim que se perdem dados que pareciam estar protegidos.
Guardar o plano num ficheiro e aplicar o ficheiro, em vez de executar um terraform apply isolado, garante que aquilo que foi revisto é aquilo que será executado. Entre os dois comandos, outra pessoa pode ter alterado a infraestrutura.
terraform.tfstate é a memória. Se o perder, o Terraform deixa de saber que esses servidores lhe pertencem. O próximo apply tenta então criar duplicados. Mantenha-o num backend remoto assim que mais de uma pessoa executar os comandos. Duas pessoas a executar apply ao mesmo tempo produzem isto:
Error: Error acquiring the state lockO OpenTofu é um fork do Terraform com os mesmos comandos e o mesmo formato de ficheiro. Em julho de 2026, tudo neste guia funciona se escrever tofu em vez de terraform.
O que o Ansible realmente faz
O Ansible não precisa de agente nem de API. Abre uma ligação SSH, copia um pequeno módulo Python para o destino, executa-o e elimina-o. Tudo o que puder alcançar com SSH e uma palavra-passe de sudo pode ser configurado pelo Ansible.
- name: Base web server
hosts: web
become: true
tasks:
- name: Install nginx
ansible.builtin.apt:
name: nginx
state: present
update_cache: true
- name: Ensure nginx is running at boot
ansible.builtin.service:
name: nginx
state: started
enabled: trueansible -i inventory.ini web -m ansible.builtin.ping
ansible-playbook -i inventory.ini site.yml --check --diff
ansible-playbook -i inventory.ini site.ymlO módulo ping valida o SSH, o Python e o sudo antes de começar a depurar um playbook. Um resultado correto é web1 | SUCCESS => {"ping": "pong"}. A execução --check --diff é o equivalente mais próximo de um plano no Ansible: indica o que seria alterado sem alterar nada. No entanto, as tarefas que dependem de tarefas anteriores podem apresentar resultados incorretos em modo de verificação, porque a alteração anterior nunca foi realmente aplicada.
Todas as execuções terminam com um resumo como ok=6 changed=2 unreachable=0 failed=0. Execute o mesmo playbook duas vezes. A segunda execução deve indicar changed=0. Uma tarefa que indique changed em todas as execuções não é idempotente. Normalmente, é uma tarefa command ou shell que deveria usar um módulo real. Se este assunto for novo para si, comece por um primeiro playbook do Ansible num único VPS e desenvolva-o a partir daí.
Onde as duas ferramentas se sobrepõem e onde entram em conflito
O Terraform pode executar comandos num servidor novo com o provisioner remote-exec. A própria documentação da HashiCorp classifica os provisioners como último recurso. Existem boas razões para isso.
Um provisioner é executado apenas quando o recurso é criado. Edite o script e nada acontece no servidor existente, porque, do ponto de vista do Terraform, o recurso já corresponde ao código. As etapas do provisioner nunca aparecem em terraform plan, por isso a revisão não mostra qualquer sinal delas. Se o script falhar, o Terraform marca o recurso como comprometido, e o próximo apply destrói e recria um servidor que provavelmente estava funcional.
A falha também ocorre num momento inadequado. O provider comunica que o servidor foi criado assim que a API confirma essa operação, enquanto o sistema operativo ainda está a arrancar e o sshd ainda não está a escutar.
Error: remote-exec provisioner error
timeout - last error: dial tcp 203.0.113.10:22: connect: connection refusedO Ansible apresenta a tentação oposta. Os módulos de cloud podem criar servidores, e isso funciona para um número reduzido de máquinas. Mas deixa de ter o grafo de dependências e o ficheiro de estado. O Ansible cria um recurso sem problemas, mas, se remover a tarefa do playbook, o recurso continua em execução e continua a gerar custos, porque nada registou que alguma vez lhe pertencia.
A regra que resulta daqui é simples: deixe o Terraform gerir os objetos que uma API cria e destrói, e deixe o Ansible gerir tudo dentro de um sistema operativo já iniciado.
A transferência funcionou
A transferência é uma fronteira, não uma integração. O Terraform termina, publica um endereço e para. O Ansible começa a partir desse endereço.
terraform apply -auto-approve
terraform output -raw web_ip
printf '[web]\n%s ansible_user=root\n' "$(terraform output -raw web_ip)" > inventory.ini
ansible -i inventory.ini web -m ansible.builtin.ping
ansible-playbook -i inventory.ini site.ymlterraform output -raw imprime um valor sem aspas e sem um invólucro JSON. É isso que pretende dentro de uma substituição de shell. Para vários servidores, use terraform output -json e crie o inventário a partir desse resultado, porque -raw processa apenas uma string, um número ou um booleano.
Vale a pena manter o passo ping entre as duas ferramentas. Ele separa "o Terraform forneceu o endereço errado" de "o meu playbook tem um erro". Estes dois problemas parecem idênticos quando o playbook é a primeira coisa que alguma vez interage com o novo servidor.
Lendo o estado do Terraform como inventário do Ansible
Se preferir não criar um ficheiro de inventário, a coleção cloud.terraform lê o estado diretamente.
ansible-galaxy collection install cloud.terraformEscreva terraform.yml junto ao seu playbook:
plugin: cloud.terraform.terraform_provider
project_path: /home/deploy/infraansible-inventory -i terraform.yml --graph
ansible-playbook -i terraform.yml site.ymlHá dois aspetos a conhecer antes de depender desta opção. O plugin executa terraform show em project_path, por isso esse diretório já tem de estar inicializado; caso contrário, o plugin falha. Além disso, não cria hosts a partir dos seus recursos de servidor: lê recursos ansible_host e ansible_group, que deve declarar no código Terraform através do provider do Ansible. Nada aparece em ansible-inventory --graph até os adicionar.
Um ficheiro de inventário gerado de forma simples é mais fácil de depurar e funciona com qualquer provider. O plugin torna-se útil quando o inventário ultrapassa algumas máquinas e a edição manual começa a gerar erros de escrita. Esse é também o ponto em que gerir vários servidores Linux a partir de uma única máquina de controlo passa a ser um fluxo de trabalho real, e não apenas um hábito.
Você realmente precisa do Terraform?
A maioria das pessoas que lê isto não precisa, pelo menos ainda não. O Terraform compensa quando criar e destruir infraestrutura é uma tarefa recorrente. Se você contratou um VPS por meio de um painel de controlo e pretende mantê-lo durante dois anos, o Terraform descreve algo que acontece uma vez e acrescenta um ficheiro de estado que você não pode perder.
Use o Terraform quando recria ambientes com frequência, quando o staging tem de corresponder exatamente à produção, quando várias pessoas alteram a infraestrutura e você quer um plano que possa ser revisto antes de qualquer eliminação, ou quando o que gere vai além dos servidores e inclui registos DNS, balanceadores de carga e regras de firewall mantidos numa API do fornecedor.
Use apenas o Ansible quando os servidores têm uma vida longa e são poucos, e quando a pergunta diária é "este servidor está configurado corretamente?" e não "este servidor existe?". Um único playbook que prepara um servidor novo cobre o mesmo que os primeiros dez minutos num VPS novo, com a vantagem de ser executado da mesma forma no servidor seguinte.
A ordem de aprendizagem decorre disso. O Ansible compensa logo no primeiro servidor que você administra. O Terraform compensa a partir do terceiro ambiente que você recria.
O que falha na transferência
O servidor não está pronto. O Terraform termina com sucesso, mas o Ansible falha imediatamente.
fatal: [web1]: UNREACHABLE! => {"changed": false, "msg": "Failed to connect to the host via ssh: ssh: connect to host 203.0.113.10 port 22: Connection refused", "unreachable": true}A API devolveu um endereço antes de sshd começar a escutar. Aguarde pela porta em vez de adicionar uma pausa fixa. O Ansible tem ansible.builtin.wait_for_connection para este caso específico; execute-o como a primeira tarefa do play. Quando o mesmo playbook visar um grupo em vez de um único servidor acabado de criar, defina antecipadamente o que deve acontecer quando um host continuar inacessível, porque o Ansible exclui esse host do restante da execução e a linha de resumo é o único local onde informa isso.
A chave do host mudou. Destruiu e recriou o servidor, e o novo servidor responde no mesmo endereço com uma chave nova.
Host key verification failed.Remova a entrada antiga com ssh-keygen -R 203.0.113.10. Isto acontece frequentemente quando o Terraform passa a tratar da reconstrução, o que é uma boa razão para evitar reconstruções frequentes em máquinas que armazenam dados.
O Sudo falha. fatal: [web1]: FAILED! => {"msg": "Missing sudo password"} significa que become: true precisa de uma palavra-passe nesse host. Configure o sudo sem palavra-passe para o utilizador de implementação ou passe --ask-become-pass.
O Terraform quer destruir algo que não alterou. O plano mostra alterações que nunca escreveu, o que significa que a infraestrutura real divergiu do código, normalmente porque alguém alterou uma definição no painel web do provider. Execute terraform plan -refresh-only para ver apenas essa diferença e decida se o código ou o recurso ativo está incorreto. Nunca aplique um plano destrutivo que não consiga explicar linha a linha.
O Ansible indica alterações em todas as execuções. Uma tarefa shell sem uma condição creates ou when é executada incondicionalmente. Isto não é um problema meramente cosmético, porque significa que já não pode usar changed=0 como sinal de que um servidor está no estado pretendido.
FAQ
O Terraform pode substituir o Ansible?
Não para a configuração dentro de um servidor. O Terraform pode executar scripts com o provisioner remote-exec, mas estes scripts são executados apenas na criação do recurso, nunca aparecem no terraform plan e marcam o recurso como inválido quando falham. Isso agenda a destruição e a recriação no próximo apply. O Terraform não tem um equivalente de um módulo que verifique se o nginx já está instalado e não faça nada nesse caso. Use o Terraform para criar a máquina e depois transfira a configuração para o Ansible.
O Ansible pode substituir o Terraform?
Para um número reduzido de servidores de longa duração, sim. O Ansible tem módulos de cloud que criam servidores. Se encomendar duas instâncias VPS e as mantiver, isso pode ser suficiente. O que perde é o ficheiro de estado e o grafo de dependências: se remover uma tarefa do playbook, o recurso continua em execução e continua a gerar custos, porque o Ansible nunca registou que o criou. O Terraform teria planeado a destruição.
Qual dos dois devo aprender primeiro?
Ansible, se já administra servidores. O investimento compensa logo no primeiro servidor, requer apenas SSH e o conhecimento aplica-se a um servidor que tenha encomendado manualmente. O Terraform compensa mais tarde, quando recria ambientes repetidamente ou gere recursos do provider para além dos servidores, como registos DNS e regras de firewall.
Como passo o IP do novo servidor do Terraform para o Ansible?
Declare um output no código do Terraform e leia-o depois do apply. terraform output -raw web_ip imprime apenas o valor, para substituição numa shell, e terraform output -json fornece todos os outputs de uma vez quando existem vários hosts. Escreva esse valor num ficheiro de inventário ou instale a collection cloud.terraform e indique ansible-inventory -i terraform.yml --graph para o diretório do projeto.
Porque é que o meu playbook falha logo depois de o Terraform terminar?
O provider informa que o servidor foi criado assim que a respetiva API o indica, enquanto o sistema operativo ainda está a arrancar. Por isso, o SSH é recusado durante os primeiros segundos. O erro é UNREACHABLE! com Connection refused. Faça de ansible.builtin.wait_for_connection a primeira tarefa do play, em vez de adivinhar uma duração para o sleep, porque o tempo de arranque varia consoante a imagem e o plano.