Terraform i OpenTofu: Infrastructure as Code bez magije

IaC znači da VPS, DNS i firewall nisu klikovi u panelu nego kod s planom i stateom. Terraform vs OpenTofu, backend, moduli i granica prema Ansibleu.

DevOps OpenTofu Terraform
Terraform i OpenTofu: Infrastructure as Code bez magije

Infrastructure as Code (IaC) nije magija niti cloud religion. To je način da infrastrukturu (VPS, DNS zapis, security group, object storage) opišete datotekama, pregledate plan prije promjene i držite state kao izvor istine o tome što provider stvarno ima.

Za male timove IaC se isplati čim imate više od jednog okruženja ili čim ste umorni od ručnog klikanja istih postavki nakon recreatea servera. Aplikacijski deploy i dalje može ići preko Composea i CI-ja; IaC pokriva sloj ispod.

Zašto IaC

Ponovljivost: staging i production razlikuju se parametrima, ne sjećanjem. Pregled promjene: plan pokazuje create/update/destroy prije applya. Dokumentacija koja radi: repo opisuje stvarno stanje bolje od zastarjelog wiki screena. Manje drift-a iz panela: ako svi idu kroz kod, manje hitnih ručnih izmjena.

Terraform vs OpenTofu (činjenice)

Terraform (HashiCorp) dugo je bio de facto alat. Nakon promjene licence HashiCorpa na Business Source License (BSL) za novije verzije, zajednica je forknula OpenTofu pod Linux Foundationom, s open-source licencom (MPL). Sintaksa (HCL), provideri i većina workflowa ostaju vrlo slični.

Terraform donosi široku dokumentaciju i Terraform Cloud/Enterprise ekosustav, uz BSL na novijim verzijama (provjerite što vaša organizacija smije koristiti). OpenTofu je community fork, u praksi kompatibilan s Terraform workflowom za većinu providera, s MPL licencom.

Za SMB stack na Hetzner/DigitalOcean/AWS providerima oba alata rade. Birajte prema licenci, podršci tima i tome što već imate u CI-ju. Ostatak članka vrijedi za oba; naredbe su terraform / tofu.

State i backend

State datoteka mapira resurse u kodu na ID-eve kod providera. Lokalni terraform.tfstate radi za eksperimente; za tim i CI treba remote backend s lockingom:

terraform {
  required_version = ">= 1.6.0"

  backend "s3" {
    bucket         = "example-tf-state"
    key            = "prod/network/terraform.tfstate"
    region         = "eu-central-1"
    encrypt        = true
    dynamodb_table = "tf-locks"
  }
}

Alternativa: HTTP/GitLab, Terraform Cloud, ili S3-kompatibilni backend (npr. MinIO) ovisno o stacku. Nikad ne commitajte state s tajnama u git. Uključite encryption at rest i access control na bucketu. Locking sprječava dva applya odjednom. Odvojite state po okruženju ili po stacku (network / app / dns), ne jedan monolitni state za sve.

Mali modul za VPS stack

# modules/vps/main.tf (skica)
resource "hcloud_server" "app" {
  name        = var.name
  server_type = var.server_type
  image       = var.image
  location    = var.location
  ssh_keys    = var.ssh_key_ids
  firewall_ids = [hcloud_firewall.app.id]
}

resource "hcloud_firewall" "app" {
  name = "${var.name}-fw"
  rule {
    direction  = "in"
    protocol   = "tcp"
    port       = "22"
    source_ips = var.ssh_cidrs
  }
  rule {
    direction  = "in"
    protocol   = "tcp"
    port       = "80"
    source_ips = ["0.0.0.0/0", "::/0"]
  }
  rule {
    direction  = "in"
    protocol   = "tcp"
    port       = "443"
    source_ips = ["0.0.0.0/0", "::/0"]
  }
}
# envs/prod/main.tf
module "app_vps" {
  source      = "../../modules/vps"
  name        = "app-prod"
  server_type = "cx22"
  image       = "ubuntu-24.04"
  location    = "nbg1"
  ssh_key_ids = [data.hcloud_ssh_key.deploy.id]
  ssh_cidrs   = ["203.0.113.10/32"]
}

Moduli za mali stack: VPS + firewall + DNS zapis. Nemojte abstrahirati prerano. Duplicirani HCL u dva enva često je jasniji od genijalnog "universal" modula.

Uvijek plan prije applya

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

Čitajte plan. Destroy linije na bazi ili volumeu nisu warning, nego potencijalni data loss. U CI-ju: plan na PR, apply samo s main plus protection rules.

Drift

Drift nastaje kad netko promijeni resurs u cloud panelu, a state ostane star. Simptomi: sljedeći plan želi vratiti ručnu izmjenu ili, gore, ne vidi resurs.

Dogovor: promjene idu kroz kod. Povremeni tofu plan u CI-ju (npr. noćni) služi kao drift signal. tofu refresh / plan s refreshom usklađuje state s reality, ali ne rješava politiku tko smije klikati u panelu. Za resurse stvorene ručno koristite import, umjesto recreatea.

IaC za provisioning vs Ansible za konfiguraciju

Gruba, korisna granica: Terraform/OpenTofu kreira i drži životni ciklus resursa kod providera (VM, disk, DNS, load balancer, object storage). Ansible (ili cloud-init + paketi) drži stanje unutar OS-a: paketi, sshd_config, korisnici, agenti, app config datoteke.

Možete instalirati Docker i Compose i Terraform remote-exec provisionerom, ali to brzo postane nepregledno i loše idempotentno. Bolje: IaC digne VPS i firewall; cloud-init ili Ansible dovezu baseline OS; Compose/CI dovezu aplikaciju.

Detaljnije o konfiguracijskom pristupu: Ansible za konfiguraciju servera. Kad je Ansible bolji sam: već imate flotu servera, konfiguracija se često mijenja, a cloud resursi su stabilni. Kad je IaC kritičan: često recreateate okruženja, multi-cloud DNS/network, audit "tko je digao taj load balancer".

Česte greške

State u gitu ili na laptopu bez backupa. Apply bez čitanja plana i destroy baze usput. Jedan state za sve projekte (blast radius pri grešci). Tajne hardcodane u .tf umjesto variables + env / secret store. Miješanje app deploja i infrastrukture u istom applyu bez jasne granice.

Varijable, outputi i tajne u praksi

Držite *.tfvars s ne-tajnama u gitu (veličina instance, lokacija). Tajne (API tokeni providera) idu u environment varijable CI-ja ili secret store, ne u tfvars u repou.

export HCLOUD_TOKEN="..."   # samo lokalno / CI secret
tofu plan -var-file=prod.tfvars

Outputi (ipv4_address, DNS ime) koristite kao ulaz u Ansible inventory ili dokumentaciju deploya. Kad brišete stack, pročitajte destroy plan dvaput: volume i floating IP lako ostanu napušteni i i dalje se naplaćuju.

Verzije providera i lock file

Commitajte .terraform.lock.hcl (ili OpenTofu ekvivalent). Time tim i CI koriste iste verzije providera, ne što god registry danas posluži. required_providers blokom ograničite major verzije; bumpajte svjesno uz plan.

terraform {
  required_providers {
    hcloud = {
      source  = "hetznercloud/hcloud"
      version = "~> 1.49"
    }
  }
}

Zaključak

Kod, remote state s lockom i plan prije applya rade posao; konfiguraciju OS-a ostavite Ansibleu ili cloud-initu. Terraform i OpenTofu rješavaju isti problem s različitim licencnim i community kontekstom. Birajte svjesno, ne po Twitter threadu. Za dizajn stacka i uvođenje IaC-a u mali tim, DevOps usluge.