SSD Nodes Learn 🎉 VPS desde $5.50/mês
Guias Matt ConnorPor Matt Connor · Atualizado 2026-08-07

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 tfplan

terraform 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 lock

O 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: true
ansible -i inventory.ini web -m ansible.builtin.ping
ansible-playbook -i inventory.ini site.yml --check --diff
ansible-playbook -i inventory.ini site.yml

O 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 refused

O 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.yml

terraform 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.terraform

Escreva terraform.yml junto ao seu playbook:

plugin: cloud.terraform.terraform_provider
project_path: /home/deploy/infra
ansible-inventory -i terraform.yml --graph
ansible-playbook -i terraform.yml site.yml

Há 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.