Modul 10 — Infrastructure as Code
48. Terraform základy: providery, resources, state
První praktické kroky s Terraformem — providery, definice resources, pracovní cyklus init/plan/apply a k čemu slouží state soubor.
Úvod a kontext
Terraform je nejrozšířenější open-source nástroj pro deklarativní
Infrastructure as Code, vyvíjený firmou HashiCorp. Na rozdíl od
cloud-specifických nástrojů (např. AWS CloudFormation) je Terraform
multi-cloud — stejným jazykem (HCL) lze spravovat zdroje v AWS,
Azure, GCP, ale i v desítkách dalších systémů (DNS providery, GitHub,
Kubernetes, a další), díky pluginové architektuře providerů. Tato lekce
projde základní stavební bloky a pracovní cyklus.
Teorie
HCL — HashiCorp Configuration Language
Terraform konfigurace se píše v jazyce HCL, deklarativním formátu
navrženém tak, aby byl čitelnější než čisté JSON, ale strojově stejně
dobře parsovatelný:
resource "typ_zdroje" "lokální_jméno" {
argument1 = "hodnota"
argument2 = 42
}
Providery
Provider je plugin, který Terraformu říká, jak komunikovat
s konkrétní platformou (API volání, autentizace, mapování HCL zdrojů na
skutečné API operace). Provider se deklaruje v bloku terraform a
nakonfiguruje v bloku provider:
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "eu-central-1"
}
Verze provideru je vhodné omezit (~> 5.0 znamená „libovolná verze
5.x, ale ne 6.0“), aby automatický upgrade provideru nerozbil existující
konfiguraci neočekávanou změnou chování.
Resources
Resource (zdroj) je základní stavební blok — jedna spravovaná
entita: virtuální server, síť, DNS záznam, databáze. Blok resource má
tvar resource "typ" "lokální_jméno" { ... }, kde typ je definovaný
providerem (např. aws_instance, aws_s3_bucket) a lokální jméno slouží
jen pro odkazování uvnitř Terraform konfigurace, nemá vliv na skutečné
jméno zdroje v cloudu:
resource "aws_instance" "web" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t3.micro"
tags = {
Name = "web-server"
Environment = "production"
}
}
Na jiný zdroj se lze odkázat přes typ.lokální_jméno.atribut, čímž
Terraform automaticky odvodí závislosti mezi zdroji a vytvoří je ve
správném pořadí:
resource "aws_security_group" "web_sg" {
name = "web-sg"
# ... pravidla ...
}
resource "aws_instance" "web" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t3.micro"
vpc_security_group_ids = [aws_security_group.web_sg.id]
}
Zde aws_instance.web závisí na aws_security_group.web_sg — Terraform
proto nejdřív vytvoří bezpečnostní skupinu a teprve pak instanci.
Pracovní cyklus: init, plan, apply, destroy
terraform init # stáhne potřebné providery a inicializuje backend
terraform plan # spočítá a vypíše, co by se změnilo (bez zásahu)
terraform apply # po potvrzení skutečně provede změny
terraform destroy # zruší veškerou infrastrukturu spravovanou touto konfigurací
terraform plan je klíčový bezpečnostní krok — ukáže přesně, co bude
vytvořeno (+), změněno (~) nebo smazáno (-), ještě než se cokoliv
skutečně stane. V týmovém provozu se plan typicky pouští automaticky
v CI při pull requestu, aby recenzenti viděli dopad změny, a apply
až po schválení a mergi.
State
Terraform potřebuje vědět, jaké zdroje už vytvořil a s jakými
identifikátory, aby při dalším plan/apply mohl spočítat rozdíl mezi
požadovaným a aktuálním stavem. K tomu slouží state soubor
(terraform.tfstate) — JSON soubor s mapováním mezi zdroji v HCL
konfiguraci a skutečnými identifikátory zdrojů v cloudu.
Ve výchozím nastavení se state ukládá lokálně na disk, což je v praxi
nebezpečné pro cokoliv víc než osobní experimenty:
- pokud state ztratíte, Terraform „zapomene“, že zdroje existují, a
při dalšímapplyby se je pokusil vytvořit znovu (duplicitně), - při práci v týmu si dva lidé mohou state navzájem přepsat.
Proto se v produkci téměř vždy používá vzdálený backend — state se
ukládá centrálně (např. v AWS S3 s DynamoDB tabulkou pro zamykání, aby
dva apply neběžely současně):
terraform {
backend "s3" {
bucket = "moje-firma-terraform-state"
key = "projekty/web-app/terraform.tfstate"
region = "eu-central-1"
dynamodb_table = "terraform-locks"
encrypt = true
}
}
State soubor obsahuje i citlivé hodnoty (např. hesla generovaná
Terraformem) v čitelné podobě — proto musí být zabezpečený (šifrování
na backendu, přístupová práva) a nikdy se necommituje do Gitu.
Proměnné a výstupy
Konfiguraci lze parametrizovat proměnnými (variable) a exportovat
hodnoty pro použití jinde (output):
variable "environment" {
description = "Nasazované prostředí"
type = string
default = "staging"
}
resource "aws_instance" "web" {
instance_type = var.environment == "production" ? "t3.medium" : "t3.micro"
# ...
}
output "instance_ip" {
value = aws_instance.web.public_ip
}
Praktický příklad
Kompletní minimální konfigurace vytvářející jeden S3 bucket a vypisující
jeho jméno jako výstup:
# main.tf
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "eu-central-1"
}
resource "aws_s3_bucket" "uploads" {
bucket = "moje-appka-uploads-2024"
tags = {
Environment = "production"
ManagedBy = "terraform"
}
}
output "bucket_name" {
value = aws_s3_bucket.uploads.bucket
}
Spuštění a typický výstup plan:
$ terraform init
Terraform has been successfully initialized!
$ terraform plan
Terraform will perform the following actions:
# aws_s3_bucket.uploads will be created
+ resource "aws_s3_bucket" "uploads" {
+ bucket = "moje-appka-uploads-2024"
+ id = (known after apply)
+ tags = {
+ "Environment" = "production"
+ "ManagedBy" = "terraform"
}
}
Plan: 1 to add, 0 to change, 0 to destroy.
$ terraform apply
# ... po potvrzení "yes" ...
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
Outputs:
bucket_name = "moje-appka-uploads-2024"
Shrnutí
Terraform popisuje infrastrukturu deklarativně v HCL, kde provider
říká, s jakou platformou se komunikuje, a resource popisuje jednotlivé
spravované zdroje s automaticky odvozenými závislostmi. Pracovní cyklus
je init → plan (náhled beze změny) → apply (skutečná změna po
potvrzení). Terraform si vede state — mapování mezi konfigurací a
skutečnými zdroji — který se v týmovém provozu musí ukládat na vzdálený,
zamykatelný a šifrovaný backend, nikdy lokálně ani v Gitu.
Kontrolní otázky
- K čemu slouží
terraform plana proč je důležité ho spouštět před
apply? - Co se stane, pokud se ztratí
terraform.tfstatebez vzdáleného
backendu, a proč je to problém? - Proč se state soubor nikdy necommituje do Gitu?
- Mini cvičení: napište HCL definici pro
aws_security_group
s jedním pravidlem, které povoluje příchozí provoz na portu 443,
a odkažte se na jejíidz blokuaws_instancepodobně jako
v příkladu v lekci.
Lekce na sebe nejsou zamčené — libovolnou lekci můžete otevřít i označit jako hotovou v jakémkoliv pořadí.