SSD Nodes Learn 🎉 VPS od $5.50/mies.
Przewodniki Matt ConnorAutor: Matt Connor · Zaktualizowano 2026-08-07

Ansible czy Terraform: co wybrać do infrastruktury?

Terraform tworzy zasoby, a Ansible konfiguruje systemy. Poznaj różnice w działaniu, dlaczego łączenie obu narzędzi bywa ryzykowne i kiedy wystarczy sam Ansible do pracy.

Ansible a Terraform w jednym zdaniu

Wybór między Ansible a Terraform nie jest wyborem dwóch narzędzi wykonujących to samo zadanie. Terraform deklaruje, jaka infrastruktura istnieje: serwery, dyski, sieci, rekordy DNS. Ansible deklaruje, co jest prawdą wewnątrz już istniejącej maszyny: pakiety, użytkownicy, pliki konfiguracyjne, działające usługi. Terraform tworzy VPS. Ansible zmienia ten VPS w serwer WWW.

Oba narzędzia są deklaratywne i oba określa się mianem infrastruktury jako kodu (IaC). Rzeczywista różnica polega na tym, co zapamiętują. Terraform zapisuje plik stanu, który mapuje każdy zasób w kodzie na rzeczywisty obiekt utworzony przez API, dzięki czemu „wie”, że usunięcie pięciu linii oznacza konieczność zniszczenia serwera. Ansible nie zapamiętuje niczego między uruchomieniami. Łączy się przez SSH, sprawdza stan maszyny i zmienia tylko to, co nie jest jeszcze zgodne z playbookiem.

Ta jedna różnica wyjaśnia resztę tego przewodnika, w tym powody, dla których łączenie obu zadań w jednym narzędziu prowadzi do błędów.

Jak faktycznie działa Terraform

Terraform komunikuje się z API za pośrednictwem wtyczki typu provider. Strona rejestru danego dostawcy definiuje typy zasobów, które można zadeklarować, dlatego serwer u jednego dostawcy i serwer u innego mają różne nazwy zasobów oraz wymagają innych argumentów.

resource "cloud_server" "web" {
  name  = "web1"
  image = "ubuntu-24.04"
  type  = "small"
}

output "web_ip" {
  value = cloud_server.web.ipv4_address
}

Zastąp cloud_server typem zasobu opisanym w dokumentacji dostawcy. Blok output jest kluczowy dla tego przewodnika, ponieważ określa sposób, w jaki adres opuszcza Terraform.

terraform init
terraform fmt -check
terraform validate
terraform plan -out=tfplan
terraform apply tfplan

terraform init pobiera dostawcę i tworzy plik blokady (lock file). terraform plan wyświetla różnice między kodem a plikiem stanu, kończąc się wierszem typu Plan: 1 to add, 0 to change, 0 to destroy.. Należy go każdorazowo analizować. Niektóre argumenty nie mogą zostać zmienione w miejscu, co plan sygnalizuje za pomocą # forces replacement przy atrybucie, a następnie 1 to add, 0 to change, 1 to destroy. Zastosowanie takiego planu usuwa serwer i tworzy nowy, pusty egzemplarz, co prowadzi do utraty danych, które użytkownik uważał za bezpieczne.

Zapisanie planu do pliku i jego późniejsze zastosowanie, zamiast uruchamiania samego terraform apply, gwarantuje, że wykonane zostanie dokładnie to, co zostało zweryfikowane. W czasie między tymi dwiema operacjami ktoś inny może zmodyfikować infrastrukturę.

terraform.tfstate to pamięć narzędzia. Jej utrata sprawia, że Terraform przestaje rozpoznawać istniejące serwery jako zarządzane przez siebie, co przy kolejnej operacji apply skutkuje próbą tworzenia duplikatów. Gdy z narzędzia korzysta więcej niż jedna osoba, należy przechowywać ten plik w zdalnym backendzie, ponieważ jednoczesne uruchomienie poleceń przez dwie osoby prowadzi do następującego błędu:

Error: Error acquiring the state lock

OpenTofu to fork Terraform, obsługujący te same polecenia i format plików. Według stanu na lipiec 2026, wszystkie instrukcje w tym przewodniku działają po wpisaniu tofu zamiast terraform.

Czym w rzeczywistości zajmuje się Ansible

Ansible nie wymaga agenta ani API. Nawiązuje połączenie SSH, kopiuje niewielki moduł Python na serwer docelowy, uruchamia go, a następnie usuwa. Ansible może skonfigurować wszystko, do czego użytkownik ma dostęp przez SSH i hasło sudo.

- 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

Moduł ping pozwala zweryfikować działanie SSH, Python oraz sudo przed rozpoczęciem debugowania playbooka. Prawidłowy wynik to web1 | SUCCESS => {"ping": "pong"}. Uruchomienie --check --diff jest najbliższym odpowiednikiem planu w Ansible: raportuje zmiany, które zostałyby wprowadzone, bez ich faktycznego stosowania. Należy pamiętać, że zadania zależne od wcześniejszych kroków mogą w trybie sprawdzania raportować błędne dane, ponieważ wcześniejsza zmiana w rzeczywistości nie nastąpiła.

Każde uruchomienie kończy się podsumowaniem, takim jak ok=6 changed=2 unreachable=0 failed=0. Należy uruchomić ten sam playbook dwukrotnie. Drugie uruchomienie powinno zwrócić wynik changed=0. Zadanie, które przy każdym uruchomieniu raportuje zmianę, nie jest idempotentne; zazwyczaj jest to zadanie command lub shell, które powinno zostać zrealizowane za pomocą dedykowanego modułu. Jeśli jest to pierwsze zetknięcie z narzędziem, warto zacząć od pierwszego playbooka Ansible na pojedynczym VPS i stopniowo rozbudowywać konfigurację.

Gdzie narzędzia te nakładają się na siebie i gdzie wchodzą w konflikt

Terraform może wykonywać polecenia na nowym serwerze za pomocą provisioner remote-exec. Dokumentacja HashiCorp określa provisionery jako rozwiązanie ostateczne. Istnieją ku temu istotne powody.

Provisioner uruchamia się tylko w momencie tworzenia zasobu. Edycja skryptu nie wywołuje żadnych zmian na istniejącym serwerze, ponieważ z punktu widzenia Terraform zasób jest już zgodny z kodem. Kroki provisionera nigdy nie pojawiają się w terraform plan, więc przegląd zmian nie wykazuje ich obecności. Jeśli skrypt zakończy się niepowodzeniem, Terraform oznacza zasób jako tainted, a kolejne polecenie apply niszczy i tworzy od nowa serwer, który prawdopodobnie był sprawny.

Awaria następuje również w nieodpowiednim momencie. Provider zgłasza utworzenie serwera w chwili, gdy potwierdza to API, podczas gdy system operacyjny wciąż się uruchamia, a sshd jeszcze nie nasłuchuje.

Error: remote-exec provisioner error
timeout - last error: dial tcp 203.0.113.10:22: connect: connection refused

Ansible wiąże się z odwrotną pokusą. Moduły chmurowe potrafią tworzyć serwery i w przypadku kilku maszyn takie rozwiązanie działa. Ceną jest jednak utrata grafu zależności oraz pliku stanu. Ansible bez problemu utworzy zasób, ale usunięcie zadania z playbooka spowoduje, że zasób pozostanie uruchomiony i naliczane będą za niego opłaty, ponieważ nic nie odnotowało faktu, że należał on do użytkownika.

Zasada wynikająca z powyższego jest następująca: należy pozwolić Terraform zarządzać obiektami, które są tworzone i usuwane przez API, a Ansible powierzyć wszystko, co znajduje się wewnątrz uruchomionego systemu operacyjnego.

Przekazanie sterowania, działanie

Przekazanie sterowania stanowi granicę, a nie integrację. Terraform kończy pracę, publikuje adres i zatrzymuje się. Ansible rozpoczyna działanie od tego adresu.

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 wypisuje jedną wartość bez cudzysłowów i bez otoczki JSON, co jest pożądane w przypadku podstawiania w powłoce. Dla wielu serwerów należy użyć terraform output -json i na tej podstawie zbudować inwentarz, ponieważ -raw obsługuje tylko pojedynczy ciąg znaków, liczbę lub wartość logiczną.

Krok ping pomiędzy tymi dwoma narzędziami jest wart zachowania. Pozwala on odróżnić sytuację, w której "Terraform podał błędny adres", od sytuacji, w której "playbook zawiera błąd". Oba te problemy wyglądają identycznie, gdy playbook jest pierwszym elementem, który nawiązuje połączenie z nową maszyną.

Odczytywanie stanu Terraform jako inwentarza Ansible

Jeśli wolisz całkowicie zrezygnować z tworzenia pliku inwentarza, kolekcja cloud.terraform odczytuje stan bezpośrednio.

ansible-galaxy collection install cloud.terraform

Utwórz plik terraform.yml obok swojego playbooka:

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

Należy pamiętać o dwóch kwestiach przed rozpoczęciem korzystania z tego rozwiązania. Wtyczka uruchamia terraform show w katalogu project_path, dlatego musi on być wcześniej zainicjowany, w przeciwnym razie wtyczka zgłosi błąd. Ponadto wtyczka nie tworzy automatycznie hostów na podstawie zasobów serwerowych: odczytuje ona zasoby ansible_host oraz ansible_group, które deklaruje się w kodzie Terraform przy użyciu dostawcy Ansible. W ansible-inventory --graph nie pojawi się nic, dopóki nie zostaną one dodane.

Zwykły wygenerowany plik inwentarza jest łatwiejszy w debugowaniu i współpracuje z każdym dostawcą. Wtyczka staje się opłacalna, gdy inwentarz rozrośnie się poza kilka maszyn, a ręczna edycja zaczyna powodować literówki. Jest to moment, w którym zarządzanie wieloma serwerami Linux z jednej maszyny sterującej staje się rzeczywistym procesem roboczym, a nie tylko nawykiem.

Czy Terraform jest rzeczywiście potrzebny?

Większość osób czytających ten tekst go nie potrzebuje, przynajmniej na razie. Terraform zwraca poniesione koszty, gdy tworzenie i usuwanie infrastruktury jest powtarzalnym zadaniem. Jeśli zamówiono jeden VPS przez panel sterowania i planuje się utrzymywać go przez dwa lata, Terraform opisuje czynność wykonywaną jednorazowo i dodaje plik stanu, którego nie wolno utracić.

Po Terraform należy sięgnąć, gdy środowiska są często przebudowywane, gdy środowisko testowe musi dokładnie odpowiadać produkcyjnemu, gdy kilka osób zmienia infrastrukturę i wymagany jest plan możliwy do sprawdzenia przed usunięciem jakichkolwiek zasobów lub gdy zarządzane elementy wykraczają poza serwery i obejmują rekordy DNS, load balancery oraz reguły firewalla dostępne przez API dostawcy.

Warto pozostać przy samym Ansible, gdy serwery są nieliczne i działają długo, a codzienne pytanie brzmi „czy ten serwer jest poprawnie skonfigurowany”, a nie „czy ten serwer istnieje”. Pojedynczy playbook, który zabezpiecza świeży serwer, realizuje te same cele co pierwsze dziesięć minut na nowym VPS, z tą zaletą, że działa w ten sam sposób na kolejnym serwerze.

Kolejność nauki wynika z powyższego. Ansible przynosi korzyści już przy pierwszym posiadanym serwerze. Terraform przynosi korzyści przy trzecim przebudowywanym środowisku.

Co psuje się podczas przekazania

Serwer nie jest gotowy. Terraform kończy działanie pomyślnie, Ansible zawodzi natychmiast.

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}

API zwróciło adres, zanim sshd zaczął nasłuchiwać. Należy poczekać na port, zamiast dodawać sztywne opóźnienie. Ansible posiada ansible.builtin.wait_for_connection dokładnie do tego celu; należy uruchomić to jako pierwsze zadanie w play.

Klucz hosta uległ zmianie. Serwer został zniszczony i utworzony ponownie, a nowy odpowiada pod tym samym adresem z nowym kluczem.

Host key verification failed.

Należy usunąć nieaktualny wpis za pomocą ssh-keygen -R 203.0.113.10. Dzieje się tak stale, gdy Terraform zajmuje się przebudową infrastruktury, co stanowi dobry powód, aby ograniczyć przebudowy maszyn przechowujących dane.

Sudo kończy się błędem. fatal: [web1]: FAILED! => {"msg": "Missing sudo password"} oznacza, że become: true wymaga hasła na danym hoście. Należy skonfigurować sudo bez hasła dla użytkownika wdrażającego lub przekazać --ask-become-pass.

Terraform chce zniszczyć coś, czego nie modyfikowano. Plan pokazuje zmiany, które nie zostały zapisane w kodzie, co oznacza, że rzeczywista infrastruktura odbiegła od stanu zdefiniowanego w kodzie, zazwyczaj z powodu zmiany ustawień w panelu WWW dostawcy. Należy uruchomić terraform plan -refresh-only, aby zobaczyć tę różnicę, a następnie zdecydować, czy błąd leży po stronie kodu, czy zasobu na żywo. Nigdy nie należy zatwierdzać destrukcyjnego planu, którego nie można wyjaśnić linijka po linijce.

Ansible zgłasza zmianę przy każdym uruchomieniu. Zadanie shell bez warunku creates lub when wykonuje się bezwarunkowo. Nie jest to problem kosmetyczny, ponieważ oznacza, że nie można już używać changed=0 jako sygnału, że serwer znajduje się w oczekiwanym stanie.

FAQ

Czy Terraform może zastąpić Ansible?

Nie w zakresie konfiguracji wewnątrz serwera. Terraform może wywoływać skrypty za pomocą provisioner remote-exec, ale są one uruchamiane tylko podczas tworzenia zasobu, nigdy nie pojawiają się w terraform plan i oznaczają zasób jako uszkodzony w przypadku niepowodzenia, co planuje jego usunięcie i ponowne utworzenie przy następnym wywołaniu apply. Terraform nie posiada odpowiednika modułu, który sprawdza, czy Nginx jest już zainstalowany i nie podejmuje żadnych działań, jeśli tak jest. Należy użyć Terraform do utworzenia maszyny, a następnie przekazać sterowanie.

Czy Ansible może zastąpić Terraform?

W przypadku niewielkiej liczby długo działających serwerów – tak. Ansible posiada moduły chmurowe, które tworzą serwery; jeśli zamawiasz dwie instancje VPS i utrzymujesz je, jest to wystarczające. Tracisz jednak plik stanu i graf zależności: usunięcie zadania z playbooka sprawia, że zasób nadal działa i generuje koszty, ponieważ Ansible nigdy nie odnotował, że go utworzył. Terraform zaplanowałby operację destroy.

Czego powinienem nauczyć się najpierw?

Ansible, jeśli obecnie zarządzasz serwerami. Zwraca się już przy pierwszej maszynie, nie wymaga niczego poza SSH, a umiejętności można zastosować do serwera zamówionego ręcznie. Terraform zwraca się później, gdy wielokrotnie przebudowujesz środowiska lub zarządzasz zasobami dostawcy wykraczającymi poza serwery, takimi jak rekordy DNS czy reguły firewall.

Jak przekazać adres IP nowego serwera z Terraform do Ansible?

Zadeklaruj output output w kodzie Terraform, a następnie odczytaj go po zakończeniu operacji apply. terraform output -raw web_ip wyświetla surową wartość do podstawienia w powłoce, a terraform output -json zwraca wszystkie wyjścia jednocześnie, gdy hostów jest więcej. Zapisz to w pliku inwentarza lub zainstaluj kolekcję cloud.terraform i skieruj ansible-inventory -i terraform.yml --graph na katalog projektu.

Dlaczego mój playbook kończy się niepowodzeniem zaraz po zakończeniu pracy Terraform?

Dostawca zgłasza utworzenie serwera, gdy tylko jego API potwierdzi taką informację, podczas gdy system operacyjny wciąż się uruchamia, więc połączenia SSH są odrzucane przez pierwsze sekundy. Błąd to UNREACHABLE! z Connection refused. Uczyń ansible.builtin.wait_for_connection pierwszym zadaniem w play zamiast zgadywać czas oczekiwania, ponieważ czas rozruchu różni się w zależności od obrazu i planu.