Ansible ou Terraform: qual você precisa?
Terraform cria o VPS e Ansible configura o sistema. Entenda a divisão, o problema dos provisioners, os comandos de handoff e quando usar só Ansible.
Ansible vs Terraform em uma 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 chamados de infraestrutura como código (IaC). A diferença real está no que cada um guarda. O Terraform escreve um ficheiro de estado que associa cada recurso do seu 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 deve ser destruído. O Ansible não guarda nada entre execuções. Liga-se por SSH, inspeciona a máquina e altera apenas o que ainda não corresponde ao playbook.
Essa ú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 provider define os tipos de recursos 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 deste 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, terminando numa linha como 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 se julgava estarem protegidos.
Guardar o plano num ficheiro e aplicar esse ficheiro, em vez de executar um terraform apply isolado, garante que é executado exatamente aquilo que foi revisto. 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, porque duas pessoas a aplicar alterações 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 conseguir 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: mostra o que seria alterado sem efetuar alterações. No entanto, as tarefas que dependem de tarefas anteriores podem apresentar resultados incorretos no modo de verificação, porque a alteração anterior nunca foi realmente efetuada.
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 apresentar changed=0. Uma tarefa que apresenta changed em todas as execuções não é idempotente. Normalmente, é uma tarefa command ou shell que deveria ter usado um módulo próprio. Se este assunto for novo para si, comece por um primeiro playbook 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. Os passos do provisioner nunca aparecem em terraform plan, por isso a revisão não mostra qualquer indicação deles. Se o script falhar, o Terraform marca o recurso como comprometido, e a próxima execução de 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 o indica, 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. O que se perde é 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 ele alguma vez lhe pertencia.
A regra resultante é esta: 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, bem definida
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, que é exatamente o necessário 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 a etapa ping entre as duas ferramentas. Ela separa o problema "o Terraform forneceu o endereço errado" do problema "o meu playbook tem um erro". Os dois problemas parecem idênticos quando o playbook é o primeiro componente a contactar a nova máquina.
Leitura do estado do Terraform como inventário do Ansible
Se preferir não escrever 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 abordagem. O plugin executa terraform show em project_path, pelo que esse diretório já tem de estar inicializado. Caso contrário, o plugin falha. O plugin também não cria hosts a partir dos seus recursos de servidor: lê recursos ansible_host e ansible_group, que declara 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 introduzir erros de escrita. Esse é também o ponto em que gerir vários servidores Linux a partir de uma máquina de controlo passa a ser um fluxo de trabalho real, e não apenas um hábito.
Você realmente precisa de Terraform?
A maioria das pessoas que lê isto não precisa, pelo menos ainda não. O Terraform justifica o custo quando criar e destruir infraestrutura passa a ser uma tarefa recorrente. Se você contratou um único VPS por 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 reconstruir ambientes for frequente, quando o staging tiver de corresponder exatamente à produção, quando várias pessoas alterarem a infraestrutura e você quiser um plano que possa ser revisto antes de algo ser eliminado, ou quando a gestão ultrapassar os servidores e incluir registos DNS, load balancers e regras de firewall mantidos numa API do fornecedor.
Use apenas Ansible quando os servidores tiverem uma vida longa e forem poucos, e quando a pergunta diária for "este servidor está configurado corretamente?" em vez de "este servidor existe?". Um único playbook que aplica a configuração de segurança a 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ê reconstrói.
O que falha na transição
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 estar a escutar. Aguarde pela porta em vez de adicionar uma espera fixa. O Ansible tem ansible.builtin.wait_for_connection para este caso exato; execute-o como a primeira tarefa do play.
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 obsoleta com ssh-keygen -R 203.0.113.10. Isto acontece constantemente quando o Terraform passa a fazer a reconstrução, o que é uma boa razão para evitar reconstruções frequentes em máquinas que contêm 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 deployment ou passe --ask-become-pass.
O Terraform quer destruir algo que não alterou. O plano mostra alterações que nunca escreveu. Isto 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á errado. 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 é apenas um problema cosmético, porque deixa de poder usar changed=0 como sinal de que o servidor está no estado solicitado.
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 esses scripts são executados apenas na criação do recurso, nunca aparecem no terraform plan e colocam o recurso em estado tainted quando falham. Isso agenda a destruição e a recriação no próximo apply. O Terraform não tem um equivalente a 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.
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 devo aprender primeiro?
Ansible, se já administra servidores. O retorno surge logo no primeiro servidor, não requer nada além de SSH e a competência aplica-se a um servidor que tenha encomendado manualmente. O Terraform compensa mais tarde, quando recria ambientes repetidamente ou gere recursos do provider além de servidores, como registos DNS e regras de firewall.
Como passo o novo IP do 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 todas as saídas de uma vez quando existem vários hosts. Escreva esse valor num ficheiro de inventário ou instale a collection cloud.terraform e aponte ansible-inventory -i terraform.yml --graph para o diretório do projeto.
Por que motivo o meu playbook falha logo depois de o Terraform terminar?
O provider indica que o servidor foi criado assim que a respetiva API o informa, 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 conforme a imagem e o plano.