Imperium Rzymskie słynęło z planów architektonicznych — każdy akwedukt, droga i fortyfikacja była najpierw zaprojektowana na papierze, zanim rozpoczęto budowę. Dzięki temu mogły być odtwarzane w różnych prowincjach z identycznym rezultatem. W DevOps, tę samą filozofię realizuje Infrastructure as Code (IaC) — definiowanie infrastruktury w plikach konfiguracyjnych zamiast ręcznego klikania w panelach administracyjnych.
IaC to podejście, w którym infrastruktura (serwery, bazy danych, sieci) jest definiowana w kodzie — wersjonowanym, testowalnym i powtarzalnym:
1// Ręczne zarządzanie vs IaC
2const comparison = {
3 reczne: {
4 metoda: 'Klikanie w AWS Console / Heroku Dashboard',
5 problemy: [
6 'Brak powtarzalności — każde środowisko inne',
7 'Brak historii zmian — kto co zmienił?',
8 'Brak code review — nikt nie weryfikuje zmian',
9 'Trudne do odtworzenia po awarii',
10 ],
11 },
12 iac: {
13 metoda: 'Terraform / Pulumi / CloudFormation',
14 korzysci: [
15 'Powtarzalność — identyczne środowiska',
16 'Git history — pełna historia zmian',
17 'Code review — zespół weryfikuje infrastrukturę',
18 'Disaster recovery — odtworzenie w minuty',
19 ],
20 },
21};Terraform (HashiCorp) to najpopularniejsze narzędzie IaC. Używa deklaratywnego języka HCL (HashiCorp Configuration Language):
1# Instalacja Terraform
2brew install terraform
3
4# Inicjalizacja projektu
5terraform init
6
7# Podgląd zmian
8terraform plan
9
10# Zastosowanie zmian
11terraform apply
12
13# Usunięcie infrastruktury
14terraform destroy1// Cykl pracy z Terraform
2const terraformWorkflow = {
3 krok1_init: 'terraform init — pobierz providery i moduły',
4 krok2_plan: 'terraform plan — pokaż co się zmieni (DRY RUN)',
5 krok3_apply: 'terraform apply — zastosuj zmiany na infrastrukturze',
6 krok4_destroy: 'terraform destroy — usuń całą infrastrukturę',
7};
8
9// Plan to jak "blueprint" — widzisz zmiany ZANIM je zastosujesz
10// Apply to jak "budowa" — Terraform tworzy zasoby w chmurzeProvider to wtyczka łącząca Terraform z dostawcą chmury:
1# main.tf — Konfiguracja providera
2terraform {
3 required_providers {
4 aws = {
5 source = "hashicorp/aws"
6 version = "~> 5.0"
7 }
8 }
9
10 # Backend — gdzie przechowywać stan
11 backend "s3" {
12 bucket = "roman-imperium-terraform-state"
13 key = "production/terraform.tfstate"
14 region = "eu-central-1"
15 }
16}
17
18provider "aws" {
19 region = var.aws_region
20
21 default_tags {
22 tags = {
23 Project = "roman-imperium"
24 Environment = var.environment
25 ManagedBy = "terraform"
26 }
27 }
28}1# variables.tf — Definicje zmiennych
2variable "aws_region" {
3 description = "Region AWS"
4 type = string
5 default = "eu-central-1"
6}
7
8variable "environment" {
9 description = "Srodowisko (dev, staging, production)"
10 type = string
11}
12
13variable "app_name" {
14 description = "Nazwa aplikacji"
15 type = string
16 default = "roman-imperium-api"
17}
18
19variable "db_instance_class" {
20 description = "Klasa instancji bazy danych"
21 type = string
22 default = "db.t3.micro"
23}
24
25variable "app_port" {
26 description = "Port aplikacji NestJS"
27 type = number
28 default = 4000
29}1# compute.tf — Serwer aplikacji
2resource "aws_instance" "api_server" {
3 ami = "ami-0c55b159cbfafe1f0" # Amazon Linux 2
4 instance_type = "t3.small"
5
6 vpc_security_group_ids = [aws_security_group.api_sg.id]
7 subnet_id = aws_subnet.public.id
8
9 user_data = <<-EOF
10 #!/bin/bash
11 yum update -y
12 yum install -y docker
13 systemctl start docker
14 docker pull ${var.app_name}:latest
15 docker run -d -p ${var.app_port}:${var.app_port} ${var.app_name}:latest
16 EOF
17
18 tags = {
19 Name = "${var.app_name}-server"
20 }
21}
22
23resource "aws_security_group" "api_sg" {
24 name = "${var.app_name}-sg"
25 description = "Security group dla API NestJS"
26 vpc_id = aws_vpc.main.id
27
28 ingress {
29 from_port = var.app_port
30 to_port = var.app_port
31 protocol = "tcp"
32 cidr_blocks = ["0.0.0.0/0"]
33 }
34
35 ingress {
36 from_port = 443
37 to_port = 443
38 protocol = "tcp"
39 cidr_blocks = ["0.0.0.0/0"]
40 }
41
42 egress {
43 from_port = 0
44 to_port = 0
45 protocol = "-1"
46 cidr_blocks = ["0.0.0.0/0"]
47 }
48}1# database.tf — Baza danych
2resource "aws_docdb_cluster" "mongodb" {
3 cluster_identifier = "${var.app_name}-db"
4 engine = "docdb"
5 master_username = "imperator"
6 master_password = var.db_password
7 skip_final_snapshot = var.environment != "production"
8
9 vpc_security_group_ids = [aws_security_group.db_sg.id]
10 db_subnet_group_name = aws_docdb_subnet_group.db.name
11}
12
13resource "aws_docdb_cluster_instance" "mongodb_instance" {
14 count = var.environment == "production" ? 2 : 1
15 identifier = "${var.app_name}-db-${count.index}"
16 cluster_identifier = aws_docdb_cluster.mongodb.id
17 instance_class = var.db_instance_class
18}Terraform przechowuje stan (state) — mapowanie między konfiguracją a rzeczywistą infrastrukturą:
1// Stan Terraform
2const terraformState = {
3 localState: {
4 plik: 'terraform.tfstate',
5 problemy: ['Nie współdzielony', 'Brak blokady', 'Ryzyko utraty'],
6 },
7 remoteState: {
8 backend: 'S3, Azure Blob, GCS, Terraform Cloud',
9 korzysci: ['Współdzielony', 'Blokada (locking)', 'Wersjonowanie'],
10 },
11};
12
13// NIGDY nie commituj terraform.tfstate do repozytorium!
14// Zawiera wrażliwe dane (hasła, klucze)Moduły to reużywalne bloki infrastruktury — jak prefabrykowane elementy rzymskich budowli:
1# modules/nestjs-app/main.tf
2module "nestjs_app" {
3 source = "./modules/nestjs-app"
4
5 app_name = "roman-imperium-api"
6 environment = "production"
7 instance_type = "t3.small"
8 app_port = 4000
9 db_instance_class = "db.t3.medium"
10}
11
12# Moduł można użyć wielokrotnie
13module "staging_app" {
14 source = "./modules/nestjs-app"
15
16 app_name = "roman-imperium-api"
17 environment = "staging"
18 instance_type = "t3.micro"
19 app_port = 4000
20 db_instance_class = "db.t3.micro"
21}1# outputs.tf
2output "api_server_ip" {
3 description = "Adres IP serwera API"
4 value = aws_instance.api_server.public_ip
5}
6
7output "database_endpoint" {
8 description = "Endpoint bazy danych"
9 value = aws_docdb_cluster.mongodb.endpoint
10 sensitive = true
11}
12
13output "app_url" {
14 description = "URL aplikacji"
15 value = "http://${aws_instance.api_server.public_ip}:${var.app_port}"
16}1# 1. Inicjalizacja projektu
2terraform init
3
4# 2. Sprawdź formatowanie
5terraform fmt
6
7# 3. Waliduj konfigurację
8terraform validate
9
10# 4. Podgląd zmian (DRY RUN)
11terraform plan -out=tfplan
12
13# 5. Zastosuj zmiany
14terraform apply tfplan
15
16# 6. Sprawdź wyniki
17terraform outputTerraform to plany architektoniczne naszego Imperium — definiujemy infrastrukturę w kodzie, wersjonujemy ją w Git, przeglądamy w code review i stosujemy automatycznie. Dzięki IaC możemy odtworzyć całe środowisko w minuty, nie w dni.