Environment_Infrastructure/setup/02-test-terraform-iaac.md
Murat ÖZDEMİR 3bf0a513f9 docs(setup): sync 01-05 documentation with actual terraform/ansible/workflow
- 01: Add WireGuard 51820/udp to public ingress table; add 9000/tcp
  (APISIX Dashboard) to admin CIDR row in test private rules
- 02: Fix admin_ssh_public_key_path (id_rsa.pub, not id_ed25519.pub);
  add WireGuard 51820/udp to DB firewall table; clarify 9000/9180 port
  descriptions (app subnet access + SWAG proxy)
- 03: Update file structure with new roles (db_stack, wireguard,
  act_runner) and playbooks (test-app/db-post-stack.yml); add floating
  IP systemd service to base role description; clarify node labels
- 04: Clarify two-phase deployment (Ansible prepares dirs/config,
  Gitea CI/CD deploys stack); add WireGuard setup info
- 05: Add system user column to runner table; fix runner name in
  acceptance criteria (iklim-test-app → test-runner)
2026-05-14 16:13:25 +03:00

8.2 KiB

02 - Test Terraform IaC

Bu asamanin amaci test Hetzner Cloud Project icinde minimum IaaS kaynaklarini Terraform ile olusturmaktir. Bu dokuman tek basina uygulanabilir olacak sekilde yazilmistir.

Kapsam

Terraform test ortaminda sunlari olusturur:

  • Private network: iklim-test-net
  • Subnetler:
    • App/Swarm subnet: 10.10.10.0/24
    • DB subnet: 10.10.20.0/24
  • Firewall:
    • Public ingress: sadece 22/tcp, 80/tcp, 443/tcp
    • Private ingress: 01-private-network-port-matrisi.md dosyasindaki test kurallari
  • SSH key
  • Placement group: iklim-test-spread
  • Floating IP: swarm entry point icin sabit IPv4
  • Server:
    • iklim-app-01
    • iklim-db-01
  • Ansible inventory output

Terraform DB yazilimini kurmaz. DB node sadece makine, network ve firewall seviyesinde hazirlanir.

Onerilen Dosya Yapisi

terraform/
  hetzner/
    test/
      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 commit edilmeyecek. .gitignore icinde ignore edilmelidir.

Degiskenler

Minimum degiskenler:

hcloud_token              = "secret"
location                  = "fsn1"
image                     = "rocky-10"
server_type_app           = "cpx42"
server_type_db            = "cpx42"
admin_ssh_public_key_path = "~/.ssh/id_rsa.pub"
admin_allowed_cidrs       = ["X.X.X.X/32"]

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

location icin tek lokasyonla baslanir. Farkli region/lokasyon felaket kurtarma bu asamada konu disidir; ileride dokumana eklenmelidir.

Server type karari ../hetzner-sizing-report.md dokumanindaki mevcut test ortami metriklerine dayanir. Test app node uzerinde 10 mikroservis ve altyapi servisleri birlikte calistigi icin cpx32 RAM acisindan riskli bulunmustur. Test DB node icin de tek node CPU spike riski nedeniyle cpx42 onerilir.

Server Rolleri

Server Private IP Rol
iklim-app-01 10.10.10.11 Swarm manager + app worker + Gitea runner
iklim-db-01 10.10.20.11 Manuel DB kurulumu icin hazir DB node

Private IP'ler Terraform icinde sabit tanimlanmalidir. Ansible inventory ve firewall kurallari deterministik kalir.

Onerilen Kaynaklar ve Maliyet

Server Rol Server Type CPU RAM SSD Aylik
iklim-app-01 Swarm manager + app worker + Gitea runner cpx42 8 AMD 16 GB 320 GB $29.99
iklim-db-01 PostgreSQL/PostGIS + MongoDB node cpx42 8 AMD 16 GB 320 GB $29.99
Toplam 2 server 16 vCPU 32 GB 640 GB $59.98

Firewall Kurallari

Public ingress:

Port Kaynak Hedef
22/tcp admin_allowed_cidrs Tum test node'lari
80/tcp 0.0.0.0/0, ::/0 iklim-app-01
443/tcp 0.0.0.0/0, ::/0 iklim-app-01

Public ingress icin 8200/tcp, 5432/tcp, 27017/tcp, 5672/tcp, 15672/tcp, 6379/tcp, 2379/tcp, 9000/tcp, 9180/tcp, 9090/tcp, 3000/tcp acilmayacak.

App (swarm) Firewall — Private Ingress

App subnet kaynakli (iklim-app-01):

Port Servis Erisim yontemi
2377/tcp Docker Swarm control plane App subnet icinden
7946/tcp,udp Docker Swarm node discovery App subnet icinden
4789/udp Docker Swarm VXLAN overlay App subnet icinden
8200/tcp Vault Docker overlay / private network
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
15672/tcp RabbitMQ Management App subnet icinden; dis erisim SWAG 443 uzerinden — IP kisitli
9000/tcp APISIX Dashboard App subnet icinden; dis erisim SWAG 443 uzerinden — IP kisitli
9180/tcp APISIX Admin API App subnet icinden (Docker overlay dahil)
9090/tcp Prometheus App subnet icinden; dis erisim SWAG 443 uzerinden — IP kisitli
3000/tcp Grafana App subnet icinden; dis erisim SWAG 443 uzerinden — IP kisitli

DB subnet kaynakli (iklim-db-01 Swarm'a worker olarak katildigi icin):

Port Servis Kaynak
2377/tcp Docker Swarm control plane 10.10.20.0/24
7946/tcp,udp Docker Swarm node discovery 10.10.20.0/24
4789/udp Docker Swarm VXLAN overlay 10.10.20.0/24

DB Firewall — Private Ingress

Port Servis Kaynak
22/tcp SSH admin_allowed_cidrs
51820/udp WireGuard VPN 0.0.0.0/0, ::/0 — kriptografik anahtar ile kimlik dogrulama
5432/tcp PostgreSQL 10.10.10.0/24 (app subnet)
27017/tcp MongoDB 10.10.10.0/24 (app subnet)
2377/tcp Docker Swarm control plane 10.10.10.0/24 (app subnet)
7946/tcp,udp Docker Swarm node discovery 10.10.10.0/24 (app subnet)
4789/udp Docker Swarm VXLAN overlay 10.10.10.0/24 (app subnet)

IP kisitlamasi Hetzner firewall'da degil, SWAG nginx konfigurasyonunda yapilir. Bu portlarin hicbiri admin_allowed_cidrs kaynagiyla public'ten acilmaz.

Diger private ingress kurallari icin 01-private-network-port-matrisi.md kaynak alinacak.

Placement Group

iklim-test-spread placement group type = "spread" olacak. Testte iki server oldugu icin bu grup iklim-app-01 ve iklim-db-01 makinelerinin farkli fiziksel host'lara dagitilmasini hedefler.

Not: Spread placement group farkli kabinet veya lokasyon garantisi degildir; tek fiziksel host arizasinin etkisini azaltir.

Terraform Cikti Beklentisi

outputs.tf minimum su bilgileri uretmelidir:

output "ansible_inventory_yaml" {
  sensitive = false
}

output "test_private_ips" {
  sensitive = false
}

output "test_public_ips" {
  sensitive = false
}

output "test_floating_ip" {
  sensitive = false
}

Inventory output'u daha sonra ansible/inventory/generated/test.yml dosyasina yazilabilir. Inventory dosyasinda secret bulunmayacaksa commit edilebilir; secret veya token icerirse commit edilmeyecek.

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
  • hcloud_firewall_attachment — firewall iliskisi

Gomulu tanimlamada bazi provider versiyonlari bu alanlardaki degisiklikleri sunucu recreation olarak yorumlar. Ayri resource kullanildiginda sadece attachment guncellenir, sunucu dokunulmaz.

prevent_destroy Korumasi

Her sunucuya lifecycle { prevent_destroy = true } eklenir. Bu blok varken Terraform hicbir kosulda sunucuyu silemez, plan asamasinda hata verir. Kasitli silmek icin once lifecycle blogunu gecici olarak kaldir.

Kabul Kriterleri

  • terraform plan sadece test Hetzner Project token'i ile calisir.
  • terraform apply sonrasinda 2 server olusur.
  • Iki server private network uzerinden birbirine erisebilir.
  • Public internetten sadece 22, 80, 443 firewall seviyesinde aciktir.
  • Vault 8200 public'ten kapali kalir.
  • Terraform state repo'ya commit edilmez.