This commit introduces a reordered and renumbered set of setup documentation files to better reflect the deployment stages for both test and production environments. Key changes include: * A new `setup-vs-roadmap-map.md` file to provide a clear mapping between roadmap tasks and their corresponding setup phases. * Significantly expanded Ansible bootstrap documentation for both test and production, detailing Docker, Swarm, security hardening, and StorageBox SSH key management roles. * Formalized database Docker and Swarm cluster setup instructions for test and production, including explicit steps for Swarm worker integration of DB nodes. * Updated roadmap documentation (`roadmap/prod-env/*`) to align with the refined setup, incorporating correct private IP addresses for Swarm joins, new node labels, and floating IP usage for GoDaddy DNS records.
12 KiB
06 - 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
- App/Swarm subnet:
- Firewall:
- Public ingress: sadece
22/tcp,80/tcp,443/tcp - Private ingress:
01-private-network-port-matrisi.mddosyasindaki prod kurallari
- Public ingress: sadece
- SSH key
- Placement groups:
iklim-prod-app-spreadiklim-prod-db-spread
- Floating IP: app entry point icin sabit IPv4 (
iklim-app-01'e atanir) - Servers:
iklim-app-01iklim-app-02iklim-app-03iklim-db-01iklim-db-02iklim-db-03
- Ansible inventory output
DB cluster yazilimi Terraform ile kurulmayacak. DB node'lari sadece makine, network ve firewall seviyesinde hazirlanacak.
Versiyon Gereksinimleri
Terraform >= 1.6
hcloud provider ~> 1.49
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 = "cpx42"
server_type_db = "cpx32"
admin_ssh_public_key_path = "~/.ssh/id_ed25519.pub"
admin_allowed_cidrs = ["X.X.X.X/32"]
Server type karari ../hetzner-sizing-report.md dokumanindaki mevcut test
ortami metrikleri ve prod cluster topolojisi dikkate alinarak belirlenmistir.
Prod app node'lar icin Java mikroservis bellek baskisi nedeniyle cpx42,
prod DB node'lar icin ise 3 node cluster baslangici nedeniyle ekonomik
cpx32 onerilir. Kapasite ihtiyaci metriklerle dogrulandiginda node ekleme
veya in-place rescale yapilabilir.
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.
Onerilen Kaynaklar ve Maliyet
| Server | Rol | Server Type | CPU | RAM | SSD | Aylik |
|---|---|---|---|---|---|---|
iklim-app-01 |
Swarm manager + app worker + runner | cpx42 |
8 AMD | 16 GB | 320 GB | $29.99 |
iklim-app-02 |
Swarm manager + app worker + runner | cpx42 |
8 AMD | 16 GB | 320 GB | $29.99 |
iklim-app-03 |
Swarm manager + app worker + runner | cpx42 |
8 AMD | 16 GB | 320 GB | $29.99 |
iklim-db-01 |
DB cluster node | cpx32 |
4 AMD | 8 GB | 160 GB | $16.49 |
iklim-db-02 |
DB cluster node | cpx32 |
4 AMD | 8 GB | 160 GB | $16.49 |
iklim-db-03 |
DB cluster node | cpx32 |
4 AMD | 8 GB | 160 GB | $16.49 |
| Toplam | 6 server | 36 vCPU | 72 GB | 1,440 GB | $139.44 |
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/tcpVault5432/tcpPostgreSQL27017/tcpMongoDB6379/tcpRedis5672/tcp,15672/tcp,61613/tcp,15674/tcpRabbitMQ2377/tcp,7946/tcp,7946/udp,4789/udpDocker Swarm9180/tcpAPISIX Admin API9090/tcpPrometheus3000/tcpGrafana
Private Firewall
App (swarm) Firewall — Private Ingress
App subnet kaynakli (10.20.10.0/24):
| 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 | 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 |
9090/tcp |
Prometheus | SWAG arkasinda 443 — IP kisitli |
3000/tcp |
Grafana | SWAG arkasinda 443 — IP kisitli |
DB subnet kaynakli (iklim-db-* node'lari Swarm'a worker olarak katildigi icin):
| Port | Servis | Kaynak |
|---|---|---|
2377/tcp |
Docker Swarm control plane | 10.20.20.0/24 |
7946/tcp,udp |
Docker Swarm node discovery | 10.20.20.0/24 |
4789/udp |
Docker Swarm VXLAN overlay | 10.20.20.0/24 |
DB Firewall — Private Ingress
Admin erisimi:
| Port | Servis | Kaynak |
|---|---|---|
22/tcp |
SSH | admin_allowed_cidrs |
App subnet kaynakli (10.20.10.0/24):
| Port | Servis | Not |
|---|---|---|
5432/tcp |
PostgreSQL (Patroni primary) | App subnet erisimi |
27017/tcp |
MongoDB replica set endpoint | App subnet erisimi |
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 |
DB subnet icindeki karsilikli erisim (10.20.20.0/24):
| Port | Servis | Not |
|---|---|---|
5432/tcp |
PostgreSQL Patroni replication | DB node'lari arasi |
27017/tcp |
MongoDB replica set internal | DB node'lari arasi |
2379/tcp |
etcd client | Patroni → etcd erisimi |
2380/tcp |
etcd peer | etcd cluster internal |
8008/tcp |
Patroni REST API | Patroni leader election ve saglik kontrolu |
IP kisitlamasi Hetzner firewall'da degil, SWAG nginx konfigurasyonunda yapilir.
Outputs
terraform apply veya terraform output sonrasi asagidaki degerler alinabilir:
| Output | Aciklama |
|---|---|
ansible_inventory_yaml |
Ansible inventory YAML — ansible/inventory/generated/prod.yml dosyasina yazilir |
prod_private_ips |
Tum node'larin private IP haritasi (swarm ve db alt anahtarlari) |
prod_public_ips |
Tum node'larin public IPv4 haritasi |
prod_floating_ip |
Swarm giris noktasi icin Floating IP adresi (DNS A kaydi bu IP'ye yonlendirilir) |
Ansible inventory cikarmak icin:
terraform output -raw ansible_inventory_yaml > \
../../ansible/inventory/generated/prod.yml
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_eachile her node icin)hcloud_firewall_attachment— firewall iliskisi (for_eachile turetilen server listesi)
prevent_destroy Korumasi
Her sunucuya lifecycle { prevent_destroy = true } eklenir. Kasitli silmek icin
once lifecycle blogunu gecici olarak kaldir.
Nasil Calistirilir
Hazirlik
1. tfvars olustur (bir kere):
cd Environment_Infrastructure/terraform/hetzner/prod
cp terraform.tfvars.example terraform.tfvars
# terraform.tfvars icerigini gercek degerlerle doldur
# (hcloud_token, admin_allowed_cidrs, vb.)
terraform.tfvars commit edilmez — .gitignore ile korunur.
2. Provider yukle (bir kere):
terraform init
Ilk Uygulama
# Nelerin olusacagini goster — bozma yapma
terraform plan
# Onayla ve olustur
terraform apply
apply sonrasi 6 sunucu, 2 firewall, 1 floating IP ve network kaynaklari Hetzner'da gorunur.
Ansible Inventory Alma
terraform output -raw ansible_inventory_yaml > \
../../ansible/inventory/generated/prod.yml
Resize (Server Type Degistirme)
terraform.tfvars icinde server_type_swarm veya server_type_db degerini degistir:
terraform apply
Sunucu durdurulur, Hetzner Resize API cagirilir, yeniden baslatilir. Disk ve Docker volumes korunur. Downtime olur.
Sunucu Silme (Zorla)
prevent_destroy = true oldugu icin normal terraform destroy hata verir. Once servers.tf icindeki lifecycle blogunu gecici kaldir:
# lifecycle {
# prevent_destroy = true
# }
Sonra:
terraform destroy -target=hcloud_server.swarm["iklim-app-01"]
Islemi tamamladiktan sonra lifecycle blogunu geri ekle.
State Yonetimi
Simdilik local state kullanilmaktadir (terraform.tfstate). State dosyasi repo'ya commit edilmez. Ekipte birden fazla kisi calisiyorsa Hetzner Object Storage veya HCP Terraform remote state kullanilmalidir.
Kabul Kriterleri
terraform plansadece 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-spreadplacement group icindedir. - DB node'lari
iklim-prod-db-spreadplacement group icindedir. - Public firewall sadece
22,80,443ingress'e izin verir. - Private firewall
01-private-network-port-matrisi.mdile 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.