Environment_Infrastructure/setup/04-prod-terraform-iaac.md
Murat ÖZDEMİR 720c79d460 Add Hetzner Cloud production infrastructure with multi-node support
- This commit introduces the Terraform configuration to provision a production environment on Hetzner Cloud, building on the existing test setup.
- Key improvements and new features include:
* **Multi-node clusters:** Scaling to 3-node Swarm application and database clusters for improved resilience.
* **High availability:** Utilizing a Hetzner Floating IP for the application entry point and `spread` placement groups for fault tolerance across physical hosts.
* **Enhanced network security:** Internal management services (RabbitMQ, APISIX, Prometheus, Grafana) are restricted to the application subnet, expected to be accessed via an internal reverse proxy (SWAG).
* **Internal database replication:** New firewall rules enable PostgreSQL replication and MongoDB replica set traffic within the database subnet.
* **Refined test environment:** Updates to align `test` configuration with the new `prod` structure, including a dedicated floating IP and adjusted firewall rules.
* **Configuration standardization:** Environment-specific details moved to `locals.tf` for clarity, with upgraded server types and migration to Rocky Linux as the base image.
- Updates were also made to the latest version of Terraform to ensure consistency in the documentation
2026-05-10 15:43:22 +03:00

7.2 KiB

04 - Prod Terraform IaC

Bu asamanin amaci prod Hetzner Cloud Project icinde HA odakli IaaS kaynaklarini Terraform ile olusturmaktir. Bu dokuman prod Terraform ajanina tek basina verilebilir.

Kapsam

Terraform prod ortaminda sunlari olusturur:

  • Private network: iklim-prod-net
  • Subnetler:
    • App/Swarm subnet: 10.20.10.0/24
    • DB subnet: 10.20.20.0/24
  • Firewall:
    • Public ingress: sadece 22/tcp, 80/tcp, 443/tcp
    • Private ingress: 07-private-network-port-matrisi.md dosyasindaki prod kurallari
  • SSH key
  • Placement groups:
    • iklim-prod-app-spread
    • iklim-prod-db-spread
  • Floating IP: app entry point icin sabit IPv4 (iklim-app-01'e atanir)
  • Servers:
    • iklim-app-01
    • iklim-app-02
    • iklim-app-03
    • iklim-db-01
    • iklim-db-02
    • iklim-db-03
  • Ansible inventory output

DB cluster yazilimi Terraform ile kurulmayacak. DB node'lari sadece makine, network ve firewall seviyesinde hazirlanacak.

Onerilen Dosya Yapisi

terraform/
  hetzner/
    prod/
      versions.tf
      providers.tf
      variables.tf
      locals.tf
      network.tf
      firewall.tf
      placement.tf
      servers.tf
      floating_ip.tf
      outputs.tf
      terraform.tfvars.example

terraform.tfvars, state dosyalari ve token repo'ya commit edilmeyecek.

Degiskenler

environment sabiti locals.tf icindedir; tfvars ile override edilmez.

Minimum degiskenler:

hcloud_token              = "secret"
location                  = "fsn1"
image                     = "rocky-10"
server_type_swarm         = "cx42"
server_type_db            = "cx52"
admin_ssh_public_key_path = "~/.ssh/id_ed25519.pub"
admin_allowed_cidrs       = ["X.X.X.X/32"]

Server type degerleri kapasiteye gore degisebilir. Bu dokuman topoloji ve guvenlik kararini tanimlar; sizing daha sonra revize edilebilir.

Server Rolleri ve Private IP Plani

Server Private IP Rol
iklim-app-01 10.20.10.11 Swarm manager + app worker + runner (primary, FIP alir)
iklim-app-02 10.20.10.12 Swarm manager + app worker + runner
iklim-app-03 10.20.10.13 Swarm manager + app worker + runner
iklim-db-01 10.20.20.11 Manuel DB cluster node
iklim-db-02 10.20.20.12 Manuel DB cluster node
iklim-db-03 10.20.20.13 Manuel DB cluster node

Private IP'ler locals.tf icinde swarm_private_ips ve db_private_ips map'leri olarak sabit tanimlanir. Sunucu listesi for_each ile bu map'lerden turetilir.

Placement Group Karari

Prod icin iki ayri spread placement group:

iklim-prod-app-spread: iklim-app-01/02/03
iklim-prod-db-spread:  iklim-db-01/02/03

Bu sayede Swarm quorum node'lari kendi aralarinda farkli fiziksel host'lara, DB node'lari da kendi aralarinda farkli fiziksel host'lara yerlestirilmeye calisilir.

Notlar:

  • Hetzner kabinet secimi dogrudan sunmaz.
  • Spread placement group farkli fiziksel host hedefler.
  • Farkli lokasyon/region felaket kurtarma bu asamada konu disidir.
  • Ileride scale buyudugunde multi-location DR ayri tasarlanmalidir.

Floating IP

iklim-prod-app-fip adli IPv4 floating IP olusturulur ve iklim-app-01'e atanir. DNS A kaydi bu IP'ye yonlendirilir. Failover gerekirse floating IP baska bir app node'una tasinabilir.

Public Firewall

Public ingress:

Port Kaynak Hedef
22/tcp admin_allowed_cidrs Tum prod node'lari
80/tcp 0.0.0.0/0, ::/0 iklim-app-* (Floating IP uzerinden)
443/tcp 0.0.0.0/0, ::/0 iklim-app-* (Floating IP uzerinden)

Prod'da su portlar public acilmayacak:

  • 8200/tcp Vault
  • 5432/tcp PostgreSQL
  • 27017/tcp MongoDB
  • 6379/tcp Redis
  • 5672/tcp, 15672/tcp, 61613/tcp, 15674/tcp RabbitMQ
  • 2377/tcp, 7946/tcp, 7946/udp, 4789/udp Docker Swarm
  • 9180/tcp APISIX Admin API
  • 9090/tcp Prometheus
  • 3000/tcp Grafana

Private Firewall

Private ingress (app subnet 10.20.10.0/24 kaynakli):

Port Servis Erisim yontemi
15672/tcp RabbitMQ Management SWAG arkasinda 443 — IP kisitli
9090/tcp Prometheus SWAG arkasinda 443 — IP kisitli
3000/tcp Grafana SWAG arkasinda 443 — IP kisitli
9000/tcp APISIX Dashboard SWAG arkasinda 443 — IP kisitli
9180/tcp APISIX Admin API Docker overlay icinden sadece Dashboard erisir
8200/tcp Vault Docker overlay / private network
2377/tcp Docker Swarm control plane App subnet icinden
7946/tcp, 7946/udp Docker Swarm node discovery App subnet icinden
4789/udp Docker Swarm VXLAN overlay App subnet icinden
6379/tcp Redis App subnet icinden
5672/tcp RabbitMQ AMQP App subnet icinden
61613/tcp RabbitMQ STOMP App subnet icinden
15674/tcp RabbitMQ Web STOMP App subnet icinden

DB firewall ek kurallar (db subnet 10.20.20.0/24 kaynakli):

Port Servis Kural
5432/tcp PostgreSQL replication DB subnet icinden
27017/tcp MongoDB replica set DB subnet icinden

IP kisitlamasi Hetzner firewall'da degil, SWAG nginx konfigurasyonunda yapilir.

Lifecycle ve Resize Politikasi

server_type Degisikligi (Yeniden Boyutlandirma)

server_type degistirmek Terraform destroy+create tetiklemez. hcloud provider bunu natively destekler: sunucuyu durdurur, Hetzner Resize API'sini cagirir, yeniden baslatir. terraform.tfvars icinde degeri guncelle, terraform apply calistir.

Downtime olur (sunucu durur ve baslar) ancak disk, kurulu yazilim ve Docker volumes korunur. ignore_changes veya manuel adim gerekmez.

Hangi Degisiklikler Sunucuyu Zorla Yeniden Olusturur?

Degisen alan Davranis Not
server_type In-place resize (provider native) terraform apply yeterli
hcloud_server_network Sadece attachment guncellenir Ayri resource kullanildigi icin
hcloud_firewall_attachment Sadece attachment guncellenir Ayri resource kullanildigi icin
placement_group_id Hetzner API degisime izin vermiyor → destroy+create Degistirme
image Disk imaji degisir → destroy+create Degistirme
location Baska datacenter'a tasinamaz → destroy+create Degistirme

Network ve Firewall Attachment Ayrimi

network blogu ve firewall_ids hcloud_server icine gomulmez. Bunun yerine ayri resource tanimlanir:

  • hcloud_server_network — private IP atamasi (for_each ile her node icin)
  • hcloud_firewall_attachment — firewall iliskisi (for_each ile turetilen server listesi)

prevent_destroy Korumasi

Her sunucuya lifecycle { prevent_destroy = true } eklenir. Kasitli silmek icin once lifecycle blogunu gecici olarak kaldir.

Kabul Kriterleri

  • terraform plan sadece prod Hetzner Project token'i ile calisir.
  • 6 server olusur (iklim-app-01/02/03, iklim-db-01/02/03).
  • Swarm node'lari iklim-prod-app-spread placement group icindedir.
  • DB node'lari iklim-prod-db-spread placement group icindedir.
  • Public firewall sadece 22, 80, 443 ingress'e izin verir.
  • Private firewall 07-private-network-port-matrisi.md ile uyumludur.
  • DB replication portlari yalnizca DB subnet'ten erisilebilir.
  • Floating IP olusur ve iklim-app-01'e atanir.
  • Terraform state ve secret tfvars commit edilmez.