Terraforma od podstaw: HCL, dostawca i cykl: zaplanuj-zastosuj-zniszcz
W 2026 roku rynek Infrastructure as Code osiągnął taką dojrzałość, że ignorowanie Terraform jest równoznaczne z pisać SQL bez znajomości transakcji: technicznie możliwe, ale zawodowo ryzykowne. Terraform HashiCorp jest dziś właścicielem 32,8% udziału w rynku wśród narzędzi IaC, z ponad 4 miliony miesięcznych instalacji dostawców na stronie Register.terraform.io. Ten przewodnik przeprowadzi Cię od zera do działającej konfiguracji na platformach AWS i Azure, z solidną znajomością cyklu Planuj – Zastosuj – Zniszcz co pozwoli uniknąć kosztownych błędów w produkcji.
Pytanie, które najczęściej słyszę od programistów zbliżających się do IaC, brzmi: „Ponieważ nie tylko używam skrypty bash czy konsola AWS?”. Odpowiedź kryje się w koncepcji infrastruktura deklaratywna: nie mówisz Terraformowi Jak twórz zasoby, mówisz który stan chcesz osiągnąć. Terraforma zajmuje się zrozumieniem sekwencji operacji, zarządzaniem zależnościami między zasobami i zapewnieniem idempotencji.
Czego się nauczysz
- Zainstaluj Terraform i skonfiguruj tfenv do obsługi wielu wersji
- Składnia HCL: bloki, atrybuty, wyrażenia i funkcje wbudowane
- Skonfiguruj dostawcę AWS i dostawcę platformy Azure z bezpiecznym uwierzytelnianiem
- Pełny cykl życia:
terraform init,plan,apply,destroy - Zrozumienie pliku stanu: czym jest, gdzie się znajduje, dlaczego nigdy nie należy go modyfikować ręcznie
- Zbuduj projekt Terraform od samego początku w skalowalny sposób
- Zmienne, wartości lokalne i dane wyjściowe: zorganizuj konfigurację w profesjonalny sposób
Warunki wstępne i instalacja
Zanim napiszemy pierwszą linię HCL, skonfigurujmy środowisko profesjonalnie. Najczęstszym błędem początkujących jest globalna instalacja Terraform za pomocą menedżera pakietów a potem utkniesz na konkretnej wersji. Prawidłowe rozwiązanie to tfenw, menedżer wersji dla Terraform (odpowiednik nvm dla Node.js).
# Installa tfenv (macOS/Linux)
git clone https://github.com/tfutils/tfenv.git ~/.tfenv
echo 'export PATH="$HOME/.tfenv/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
# Installa l'ultima versione stabile di Terraform
tfenv install latest
tfenv use latest
# Verifica installazione
terraform version
# Output: Terraform v1.9.x on linux_amd64
# Installa una versione specifica se il progetto la richiede
tfenv install 1.8.5
tfenv use 1.8.5
# Lista versioni installate
tfenv list
W przypadku systemu Windows zalecane podejście w 2026 r. i WSL2 z Ubuntu lub Chocolatey:
# Windows con Chocolatey
choco install terraform
# Oppure scarica il binario da releases.hashicorp.com
# e aggiungilo al PATH manualmente
Zainstaluj także wtyczkę VS Code Terraforma HashiCorp (id: hashicorp.terraform):
oferuje podświetlanie składni, autouzupełnianie, przejście do definicji dla dostawców i integrację
z terraform fmt. Jest to najbardziej niezawodne środowisko IDE dostępne dla HCL.
HCL: język konfiguracji HashiCorp
HCL (język konfiguracji HashiCorp) to specjalnie zaprojektowany język deklaratywny
do konfiguracji infrastruktury. Nie jest to język programowania ogólnego przeznaczenia:
nie ma pętli imperatywnej (użyj for_each e count), nie ma wyjątków,
Nie ma asynchronicznych wejść/wyjść. To jest cechy, bez ograniczeń: prostota zmniejsza
przypadkowa złożoność konfiguracji.
Podstawowy plik każdego projektu Terraform, np main.tf. Wspólna konwencja
i rozdziel konfigurację na te pliki:
progetto-terraform/
├── main.tf # Risorse principali
├── variables.tf # Dichiarazione variabili
├── outputs.tf # Output values
├── versions.tf # Required providers e terraform block
├── locals.tf # Valori locali computati
└── terraform.tfvars # Valori delle variabili (non committare se contiene segreti)
Oto podstawowa struktura HCL z podstawowymi typami bloków:
# versions.tf — blocco terraform: configura il comportamento del core
terraform {
required_version = ">= 1.8.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.100"
}
}
}
# variables.tf — dichiarazione variabili di input
variable "environment" {
description = "Nome dell'ambiente (dev, staging, prod)"
type = string
default = "dev"
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "L'ambiente deve essere dev, staging o prod."
}
}
variable "aws_region" {
description = "AWS Region dove deployare le risorse"
type = string
default = "eu-west-1"
}
variable "instance_count" {
description = "Numero di istanze EC2 da creare"
type = number
default = 2
}
variable "tags" {
description = "Tag comuni da applicare a tutte le risorse"
type = map(string)
default = {
ManagedBy = "Terraform"
Project = "demo"
}
}
# locals.tf — valori computati a partire da variabili
locals {
# Naming convention uniforme
name_prefix = "${var.environment}-${var.tags["Project"]}"
# Merge tag comuni con tag specifici per risorsa
common_tags = merge(var.tags, {
Environment = var.environment
CreatedAt = timestamp()
})
}
Skonfiguruj dostawcę AWS
I dostawca to wtyczki umożliwiające Terraformowi interakcję z zewnętrznymi API: AWS, Azure, GCP, Kubernetes, GitHub, Datadog – praktycznie każda usługa ma dostawcę Terraform. Dostawca AWS jest najbardziej dojrzały i obsługuje ponad 1200 typów zasobów.
W przypadku uwierzytelniania AWS, nigdy nie używaj zakodowanego na stałe klucza dostępu w kodzie HCL. Dostawca AWS obsługuje następujące tryby, w kolejności priorytetu:
# main.tf — configurazione provider AWS
provider "aws" {
region = var.aws_region
# NON fare questo in produzione:
# access_key = "AKIA..." # MAI
# secret_key = "..." # MAI
# Metodo consigliato 1: assume role (best practice per CI/CD)
# assume_role {
# role_arn = "arn:aws:iam::123456789:role/TerraformRole"
# }
# I tag di default vengono applicati a tutte le risorse
default_tags {
tags = local.common_tags
}
}
# Configurazione autenticazione (fuori da main.tf)
# La best practice e usare il file ~/.aws/credentials oppure
# variabili di ambiente:
# export AWS_ACCESS_KEY_ID="..."
# export AWS_SECRET_ACCESS_KEY="..."
# export AWS_DEFAULT_REGION="eu-west-1"
#
# In produzione: IAM Instance Profile o OIDC con GitHub Actions
Stwórzmy teraz pierwsze zasoby AWS: VPC z podsieciami publicznymi i prywatnymi:
# main.tf — prime risorse AWS
# Data source: recupera gli AZ disponibili nella region
data "aws_availability_zones" "available" {
state = "available"
}
# VPC principale
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "${local.name_prefix}-vpc"
}
}
# Subnet pubblica (una per AZ)
resource "aws_subnet" "public" {
count = min(length(data.aws_availability_zones.available.names), 2)
vpc_id = aws_vpc.main.id
cidr_block = cidrsubnet(aws_vpc.main.cidr_block, 8, count.index)
availability_zone = data.aws_availability_zones.available.names[count.index]
map_public_ip_on_launch = true
tags = {
Name = "${local.name_prefix}-public-${count.index + 1}"
Tier = "Public"
}
}
# Subnet privata
resource "aws_subnet" "private" {
count = min(length(data.aws_availability_zones.available.names), 2)
vpc_id = aws_vpc.main.id
cidr_block = cidrsubnet(aws_vpc.main.cidr_block, 8, count.index + 10)
availability_zone = data.aws_availability_zones.available.names[count.index]
tags = {
Name = "${local.name_prefix}-private-${count.index + 1}"
Tier = "Private"
}
}
# Internet Gateway per le subnet pubbliche
resource "aws_internet_gateway" "main" {
vpc_id = aws_vpc.main.id
tags = {
Name = "${local.name_prefix}-igw"
}
}
# Route table pubblica
resource "aws_route_table" "public" {
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.main.id
}
tags = {
Name = "${local.name_prefix}-rt-public"
}
}
# Associazione route table - subnet pubblica
resource "aws_route_table_association" "public" {
count = length(aws_subnet.public)
subnet_id = aws_subnet.public[count.index].id
route_table_id = aws_route_table.public.id
}
# outputs.tf — valori di output
output "vpc_id" {
description = "ID della VPC creata"
value = aws_vpc.main.id
}
output "public_subnet_ids" {
description = "IDs delle subnet pubbliche"
value = aws_subnet.public[*].id
}
output "private_subnet_ids" {
description = "IDs delle subnet private"
value = aws_subnet.private[*].id
}
Cykl „Zaplanuj – zastosuj – zniszcz”.
Cykl życia Terraform składa się z czterech podstawowych poleceń. Zrozum je dokładnie Należy unikać najczęstszych wypadków na produkcji.
inicjalizacja terraforma
# Inizializza il working directory:
# - Scarica i provider (plugin binaries)
# - Configura il backend per lo state
# - Installa i moduli referenziati
terraform init
# Output atteso:
# Initializing the backend...
# Initializing provider plugins...
# - Finding hashicorp/aws versions matching "~> 5.0"...
# - Installing hashicorp/aws v5.54.1...
# Terraform has been successfully initialized!
# Upgrade dei provider all'ultima versione compatibile
terraform init -upgrade
# Ricrea il .terraform.lock.hcl (file di lock dei provider)
terraform providers lock -platform=linux_amd64 -platform=darwin_amd64
Plik .terraform.lock.hcl
Plik .terraform.lock.hcl należy zatwierdzić w repozytorium.
Zapewnia to, że wszyscy członkowie zespołu i potok CI korzystają dokładnie z tego samego
dostawcy, unikając „działa na moim komputerze” w przypadku infrastruktury.
Katalog .terraform/ zamiast tego idzie do .gitignore.
planu terraformy
# Genera il piano di esecuzione (DRY RUN)
terraform plan
# Salva il piano in un file binario (consigliato per CI/CD)
terraform plan -out=tfplan
# Specifica le variabili inline
terraform plan -var="environment=staging" -var="instance_count=3"
# Usa un file di variabili
terraform plan -var-file="staging.tfvars"
# Output tipico di plan:
# Terraform will perform the following actions:
#
# # aws_vpc.main will be created
# + resource "aws_vpc" "main" {
# + arn = (known after apply)
# + cidr_block = "10.0.0.0/16"
# + enable_dns_hostnames = true
# ...
# }
#
# Plan: 8 to add, 0 to change, 0 to destroy.
Symbol + wskazuje na stworzenie, ~ edycja na miejscu,
-/+ niszczyć i odtwarzać (wymuszać przestoje), - zniszczenie.
Zawsze uważnie czytaj zaznaczone bloki -/+:
oznaczają one konieczność ponownego utworzenia zasobu, co często powoduje przestoje lub utratę danych.
stosuje się terraformę
# Applica le modifiche (chiede conferma interattiva)
terraform apply
# Applica il piano salvato (NON chiede conferma - usare in CI/CD)
terraform apply tfplan
# Auto-approve per ambienti non critici (attento in prod!)
terraform apply -auto-approve
# Apply con variabili
terraform apply -var="environment=prod" -var-file="prod.tfvars"
# Output dopo apply:
# Apply complete! Resources: 8 added, 0 changed, 0 destroyed.
#
# Outputs:
# vpc_id = "vpc-0123456789abcdef0"
# public_subnet_ids = [
# "subnet-0abc123def456gh78",
# "subnet-0def456abc789ij01",
# ]
zniszczyć terraformę
# Distrugge TUTTE le risorse gestite dallo state corrente
terraform destroy
# Destroy con auto-approve (ATTENZIONE: irreversibile)
terraform destroy -auto-approve
# Distrugge solo una risorsa specifica (con grande cautela)
terraform destroy -target=aws_subnet.public[0]
# In produzione, preferisci eliminare le risorse dal codice
# e fare terraform apply: Terraform le distruggerà correttamente
Anty-wzorzec: zniszczenie terraformy w fazie produkcji
Nigdy nie biegaj terraform destroy bez planu naprawczego.
Najlepszą praktyką jest usunięcie zasobu z kodu HCL i uruchomienie terraform apply:
otrzymasz ten sam wynik, ale z wyraźnym planem, który możesz najpierw przejrzeć.
Niektóre organizacje blokują możliwość niszczenia na poziomie zasad IAM
w środowiskach produkcyjnych.
Skonfiguruj dostawcę platformy Azure
Dostawca lazurerm zarządza zasobami Azure. W odróżnieniu od AWS-a Platforma Azure używa nazwy głównej usługi lub tożsamości zarządzanej do uwierzytelniania.
# versions.tf aggiornato con provider Azure
terraform {
required_version = ">= 1.8.0"
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.100"
}
}
}
# Configurazione provider Azure
provider "azurerm" {
features {
resource_group {
prevent_deletion_if_contains_resources = true
}
key_vault {
purge_soft_delete_on_destroy = false
recover_soft_deleted_key_vaults = true
}
}
# Autenticazione via variabili d'ambiente (consigliato)
# ARM_CLIENT_ID, ARM_CLIENT_SECRET, ARM_TENANT_ID, ARM_SUBSCRIPTION_ID
# oppure Azure CLI: az login
}
# Risorse Azure di base
resource "azurerm_resource_group" "main" {
name = "${local.name_prefix}-rg"
location = "West Europe"
tags = local.common_tags
}
resource "azurerm_virtual_network" "main" {
name = "${local.name_prefix}-vnet"
address_space = ["10.1.0.0/16"]
location = azurerm_resource_group.main.location
resource_group_name = azurerm_resource_group.main.name
tags = local.common_tags
}
resource "azurerm_subnet" "public" {
name = "public-subnet"
resource_group_name = azurerm_resource_group.main.name
virtual_network_name = azurerm_virtual_network.main.name
address_prefixes = ["10.1.1.0/24"]
}
resource "azurerm_subnet" "private" {
name = "private-subnet"
resource_group_name = azurerm_resource_group.main.name
virtual_network_name = azurerm_virtual_network.main.name
address_prefixes = ["10.1.2.0/24"]
}
Zmienne, wartości lokalne i źródła danych
Dobre wykorzystanie zmiennych, lokalnych i źródeł danych wyróżnia konfigurację Terraform profesjonalista ze skryptu ad hoc. Oto podstawowe wzory:
# Tipi di variabili in HCL
# Stringa semplice
variable "app_name" {
type = string
default = "myapp"
}
# Numero con validazione
variable "min_instances" {
type = number
default = 1
validation {
condition = var.min_instances >= 1 && var.min_instances <= 10
error_message = "Il numero di istanze deve essere tra 1 e 10."
}
}
# Lista di stringhe
variable "allowed_cidr_blocks" {
type = list(string)
default = ["10.0.0.0/8"]
}
# Map di stringhe
variable "database_config" {
type = map(string)
default = {
engine = "postgres"
version = "15.4"
size = "db.t3.medium"
}
}
# Oggetto con schema tipizzato
variable "network_config" {
type = object({
vpc_cidr = string
subnet_count = number
enable_nat = bool
})
default = {
vpc_cidr = "10.0.0.0/16"
subnet_count = 2
enable_nat = false
}
}
# Locals: valori computati (non input dall'utente)
locals {
# Concatenazioni
full_name = "${var.environment}-${var.app_name}"
# Condizionale ternario
instance_type = var.environment == "prod" ? "t3.medium" : "t3.micro"
# Ciclo su lista (for expression)
subnet_cidrs = [
for i in range(var.network_config.subnet_count) :
cidrsubnet(var.network_config.vpc_cidr, 8, i)
]
# Map transformation
tag_map = {
for k, v in var.database_config :
"db_${k}" => v
}
}
# Data sources: recuperano informazioni da risorse esistenti
# non gestite da questo state
# AMI Amazon Linux 2023 piu recente
data "aws_ami" "amazon_linux" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["al2023-ami-*-x86_64"]
}
filter {
name = "virtualization-type"
values = ["hvm"]
}
}
# Account ID corrente (utile per ARN)
data "aws_caller_identity" "current" {}
# Uso nei resource:
# ami = data.aws_ami.amazon_linux.id
# account_id = data.aws_caller_identity.current.account_id
Plik stanowy: Serce Terraformu
Plik terraform.tfstate to „źródło prawdy” Terraformu: mapuj każdy zasób
zdefiniowane w HCL do swojego rzeczywistego odpowiednika w chmurze. Zrozumienie, jak to działa, jest niezbędne
uniknąć najpoważniejszych problemów.
// Struttura semplificata di terraform.tfstate
{
"version": 4,
"terraform_version": "1.9.0",
"serial": 42,
"lineage": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"outputs": {
"vpc_id": {
"value": "vpc-0123456789abcdef0",
"type": "string"
}
},
"resources": [
{
"mode": "managed",
"type": "aws_vpc",
"name": "main",
"provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
"instances": [
{
"schema_version": 1,
"attributes": {
"id": "vpc-0123456789abcdef0",
"cidr_block": "10.0.0.0/16",
"enable_dns_hostnames": true,
...
}
}
]
}
]
}
Złote zasady akt państwowych
- Nigdy nie edytuj
terraform.tfstateręcznie - Nigdy nie popełniaj podaj to w swoim repozytorium Git (dodaj do
.gitignore) - W zespołach używaj zawsze zdalny backend z zamkiem (patrz artykuł 03 serii)
- Państwo może to powstrzymać tajemnice na wierzchu (hasło RDS, dane uwierzytelniające): Traktuj to jako dane wrażliwe
- Przed ryzykownymi operacjami wykonaj ręczną kopię zapasową:
terraform state pull > backup.tfstate
Polecenia Państwowej Inspekcji
# Lista tutte le risorse gestite dallo state
terraform state list
# Mostra i dettagli di una risorsa specifica
terraform state show aws_vpc.main
# Rinomina una risorsa nello state (senza toccare l'infrastruttura)
terraform state mv aws_subnet.public aws_subnet.public_new
# Rimuove una risorsa dallo state (Terraform non la gestirà piu)
# La risorsa rimane nel cloud ma non è piu "owned" da Terraform
terraform state rm aws_subnet.private[0]
# Importa una risorsa esistente nello state
# (vedi articolo 03 per dettagli)
terraform import aws_vpc.main vpc-0123456789abcdef0
# Mostra l'output senza fare apply
terraform output vpc_id
terraform output -json # tutti gli output in formato JSON
Zalecana struktura projektu
W przypadku prawdziwych projektów pojedyncza struktura katalogów szybko staje się niemożliwa do zarządzania. Oto dwa typowe wzorce organizacji infrastruktury Terraform w środowisku produkcyjnym:
# Pattern 1: Organizzazione per ambiente
infra/
├── modules/ # Moduli riusabili
│ ├── networking/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ └── outputs.tf
│ └── compute/
│ ├── main.tf
│ ├── variables.tf
│ └── outputs.tf
├── environments/
│ ├── dev/
│ │ ├── main.tf # Usa i moduli
│ │ ├── variables.tf
│ │ ├── terraform.tfvars # Valori specifici per dev
│ │ └── versions.tf
│ ├── staging/
│ │ └── ...
│ └── prod/
│ └── ...
└── .gitignore # Esclude .terraform/, *.tfstate
# Pattern 2: Terragrunt (wrapper per DRY)
infra/
├── terragrunt.hcl # Config globale
├── modules/
│ └── networking/
├── live/
│ ├── dev/
│ │ └── networking/
│ │ └── terragrunt.hcl
│ └── prod/
│ └── networking/
│ └── terragrunt.hcl
Najlepsze praktyki na początek
Po zapoznaniu się z teorią, oto praktyczne zasady, które wyróżniają tych, którzy korzystają z Terraform poprawnie przez tych, którzy od pierwszego dnia tworzą dług techniczny:
# 1. Formatta sempre prima di committare
terraform fmt -recursive
# 2. Valida la sintassi
terraform validate
# 3. Usa tflint per linting avanzato (trova deprecazioni, pattern errati)
tflint --init
tflint
# 4. Esegui checkov per security scanning
pip install checkov
checkov -d .
# 5. Pre-commit hooks per automatizzare tutto
# .pre-commit-config.yaml
# repos:
# - repo: https://github.com/antonbabenko/pre-commit-terraform
# hooks:
# - id: terraform_fmt
# - id: terraform_validate
# - id: terraform_tflint
# - id: terraform_checkov
Plik .gitignore dla Terraform
# .gitignore per progetti Terraform
.terraform/
*.tfstate
*.tfstate.backup
*.tfstate.*.backup
.terraform.tfstate.lock.info
*.tfvars # Se contengono segreti (crea terraform.tfvars.example)
override.tf
override.tf.json
*_override.tf
*_override.tf.json
crash.log
.terraformrc
terraform.rc
Kompletny przykład: aplikacja internetowa na platformie AWS
Zestawmy to wszystko w prawdziwym przykładzie: instancja EC2 z grupą bezpieczeństwa, moduł równoważenia obciążenia i baza danych RDS, o prawidłowej strukturze.
# main.tf — infrastruttura web app completa
# Security Group per le istanze web
resource "aws_security_group" "web" {
name = "${local.name_prefix}-sg-web"
description = "Security group per istanze web"
vpc_id = aws_vpc.main.id
ingress {
description = "HTTP dal load balancer"
from_port = 80
to_port = 80
protocol = "tcp"
security_groups = [aws_security_group.alb.id]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = { Name = "${local.name_prefix}-sg-web" }
}
# Security Group per ALB
resource "aws_security_group" "alb" {
name = "${local.name_prefix}-sg-alb"
description = "Security group per Application Load Balancer"
vpc_id = aws_vpc.main.id
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
# Launch Template per le istanze EC2
resource "aws_launch_template" "web" {
name_prefix = "${local.name_prefix}-lt-"
image_id = data.aws_ami.amazon_linux.id
instance_type = local.instance_type
network_interfaces {
associate_public_ip_address = false
security_groups = [aws_security_group.web.id]
}
user_data = base64encode(<<-EOF
#!/bin/bash
dnf update -y
dnf install -y nginx
systemctl enable nginx
systemctl start nginx
echo "Deploy Terraform - ${var.environment}
" > /usr/share/nginx/html/index.html
EOF
)
tag_specifications {
resource_type = "instance"
tags = merge(local.common_tags, {
Name = "${local.name_prefix}-web"
})
}
}
# Auto Scaling Group
resource "aws_autoscaling_group" "web" {
name = "${local.name_prefix}-asg"
vpc_zone_identifier = aws_subnet.private[*].id
target_group_arns = [aws_lb_target_group.web.arn]
health_check_type = "ELB"
min_size = var.environment == "prod" ? 2 : 1
max_size = var.environment == "prod" ? 6 : 2
desired_capacity = var.environment == "prod" ? 2 : 1
launch_template {
id = aws_launch_template.web.id
version = "$Latest"
}
tag {
key = "Name"
value = "${local.name_prefix}-web"
propagate_at_launch = true
}
}
# Application Load Balancer
resource "aws_lb" "main" {
name = "${local.name_prefix}-alb"
internal = false
load_balancer_type = "application"
security_groups = [aws_security_group.alb.id]
subnets = aws_subnet.public[*].id
enable_deletion_protection = var.environment == "prod"
tags = local.common_tags
}
resource "aws_lb_target_group" "web" {
name = "${local.name_prefix}-tg-web"
port = 80
protocol = "HTTP"
vpc_id = aws_vpc.main.id
health_check {
enabled = true
healthy_threshold = 2
unhealthy_threshold = 3
timeout = 5
interval = 30
path = "/health"
}
}
resource "aws_lb_listener" "http" {
load_balancer_arn = aws_lb.main.arn
port = "80"
protocol = "HTTP"
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.web.arn
}
}
Wnioski i dalsze kroki
Masz teraz solidne podstawy do profesjonalnej pracy z Terraform: znasz składnię HCL, wiesz jak skonfigurować dostawców AWS i Azure, rozumiesz cykl Zaplanuj-Zastosuj-Zniszcz i zasady niezbędne do bezpiecznego zarządzania plikiem stanu.
Kolejnym naturalnym krokiem w Twoim rozwoju dzięki Terraform jest nauka organizowania kodu w moduły wielokrotnego użytku: Gdy Twoja infrastruktura przekroczy 200–300 linii HCL, modularyzacja staje się niezbędna dla łatwości konserwacji.
Kompletna seria: Terraform i IaC
- Artykuł 01 (ten) — Terraformuj od podstaw: HCL, dostawca i planuj-zastosuj-zniszcz
- Artykuł 02 — Projektowanie modułów Terraform wielokrotnego użytku: struktura, wejścia/wyjścia i rejestr
- Artykuł 03 — Stan Terraform: zdalny backend z S3/GCS, blokowaniem i importem
- Artykuł 04 — Terraform w CI/CD: GitHub Actions, Atlantis i przepływ pracy dotyczący żądania ściągnięcia
- Artykuł 05 – Testowanie IaC: test terenu, test rodzimy dla terenu i testowanie kontraktowe
- Artykuł 06 — Bezpieczeństwo IaC: Checkov, Trivy i OPA Policy-as-Code
- Artykuł 07 — Terraform Multi-Cloud: AWS + Azure + GCP z modułami współdzielonymi
- Artykuł 08 — GitOps dla Terraform: kontroler Flux TF, wykrywanie lotów kosmicznych i dryfu
- Artykuł 09 — Terraform vs Pulumi vs OpenTofu: ostateczne porównanie 2026
- Artykuł 10 — Wzorce Terraform Enterprise: przestrzeń robocza, strażnik i skalowanie zespołu
Oficjalne zasoby
- Oficjalna dokumentacja Terraform
- Rejestr Terraform — dostawcy, moduły i polityki
- HashiCorp Learn — interaktywne samouczki







