Ansible roles: - act_runner/defaults: set act_runner_name to inventory_hostname (was hardcoded to iklim-test-app); added vault_gitea_runner_token to vault.yml - prod/group_vars/all: restructured from flat files to all/ directory; added act_runner_labels override (prod-runner,ubuntu-24.04,hostname); added storagebox_managed_directories; added swarm_manager_ip and other prod-specific vars - prod/roles/db_stack: prod-specific db_node tasks using StorageBox paths (/mnt/storagebox/db/...) instead of local paths - docker/tasks: split firewalld loop into all-nodes (Swarm ports) and app-only (80/443) tasks - swarm/tasks: added --advertise-addr private_ip to join commands for correct multi-homed node advertisement - hardening/tasks: corrected firewalld drop zone configuration - node_dirs/tasks: added /opt/iklimco/vault/data for Vault Raft volume - db_stack/tasks/app_node: updated stale comment (removed pg-proxy reference) - db_stack/templates: removed pg-proxy and mongo-proxy service blocks - test/host_vars/iklim-app-01: added act_runner_name override to preserve existing test runner registration Roadmap and setup docs: - roadmap/03-infra-stack-changes: added replicas:0 for etcd/postgresql/ mongodb/pg-proxy/mongo-proxy in prod overlay; updated placement table; fixed grafana/data mkdir (auto-created by Ansible); translated Turkish note to English - roadmap/08-deploy-pipeline-update: updated stale "remains idle" note for standalone etcd (now disabled with replicas:0) - roadmap/01-swarm-init-multinode: consistency fixes - setup/06: added Outputs section and etcd firewall port documentation - setup/07: removed prometheus/data from StorageBox acceptance criteria; replaced manual StorageBox mkdir section with Ansible auto-creation note; updated prod README section with full bootstrap instructions and vault docs; added act_runner_labels prod policy - setup/08: extensive rewrite — aligned with Patroni etcd overlay DNS, corrected hcloud_firewall.app reference, updated all StorageBox paths from /prod/db/ to /db/ - setup/09: removed prometheus/data from acceptance criteria; updated runner label policy (removed docker/swarm-manager labels); added acceptance criterion for disabled services absent from docker service ls Terraform: - prod/firewall.tf: added missing DB subnet mutual rules (etcd, Patroni) - prod/outputs.tf: added prod_floating_ip and prod_private_ips outputs - prod/servers.tf: aligned placement group and naming - prod/variables.tf: corrected variable descriptions - prod/terraform.tfvars.example: updated defaults - terraform/hetzner/README.md: new comprehensive README covering both test and prod environments with firewall tables and inventory instructions ansible/README.md: expanded prod section with inventory groups, bootstrap run order, runner label policy, and vault variable documentation
Terraform — iklim.co Hetzner Cloud Altyapısı
Bu dizin, iklim.co test ve prod ortamlarının Hetzner Cloud altyapısını Terraform ile yönetir.
Dizin Yapısı
terraform/hetzner/
test/ — test ortamı: 1 app + 1 db node, single-node Swarm
prod/ — prod ortamı: 3 app + 3 db node, 3-manager HA Swarm
Her ortam kendi bağımsız Terraform state dosyasına sahiptir; birbirini etkilemez.
Ortam Karşılaştırması
| Özellik | Test | Prod |
|---|---|---|
| App node sayısı | 1 (iklim-app-01) |
3 (iklim-app-01/02/03) |
| DB node sayısı | 1 (iklim-db-01) |
3 (iklim-db-01/02/03) |
| App sunucu tipi | cpx42 |
cpx42 |
| DB sunucu tipi | cpx42 |
cpx32 |
| Swarm mimarisi | Single-node | 3-manager HA |
| App subnet | 10.10.10.0/24 |
10.20.10.0/24 |
| DB subnet | 10.10.20.0/24 |
10.20.20.0/24 |
| Floating IP | Var | Var |
| Placement group | Yok | Spread (farklı fiziksel host) |
Ön Koşullar
- Terraform >= 1.5 kurulu olmalı.
- Hetzner Cloud ortama özel proje API token'ı hazır olmalı (test ve prod ayrı proje).
terraform.tfvarsdosyası oluşturulmuş olmalı (bkz.terraform.tfvars.example).
terraform.tfvars Kurulumu
# Test için:
cd terraform/hetzner/test
cp terraform.tfvars.example terraform.tfvars
# Prod için:
cd terraform/hetzner/prod
cp terraform.tfvars.example terraform.tfvars
terraform.tfvars içindeki değişkenler:
| Değişken | Açıklama |
|---|---|
hcloud_token |
Hetzner Cloud ortama özel proje API token'ı |
location |
Sunucu lokasyonu (örn. fsn1) |
image |
Sunucu işletim sistemi (örn. rocky-10) |
server_type_app |
App sunucu tipi |
server_type_db |
DB sunucu tipi |
admin_ssh_public_key_path |
Admin SSH public key dosya yolu |
admin_allowed_cidrs |
SSH erişimine izin verilen CIDR listesi |
terraform.tfvarshassas bilgi içerir; repository'e commit edilmez.
Terraform Komutları
Tüm komutlar ilgili ortam dizininden çalıştırılmalıdır:
# Test:
cd terraform/hetzner/test
# Prod:
cd terraform/hetzner/prod
Başlatma
terraform init
Değişiklik önizleme
terraform plan
Uygulama
terraform apply
Kaynakları kaldırma
terraform destroy
Ansible Inventory Üretimi
terraform apply tamamlandıktan sonra Ansible inventory'si şu komutlarla üretilir:
# Test inventory:
cd terraform/hetzner/test
terraform output -raw ansible_inventory_yaml \
> ../../../ansible/test/inventory/generated/test.yml
# Prod inventory:
cd terraform/hetzner/prod
terraform output -raw ansible_inventory_yaml \
> ../../../ansible/prod/inventory/generated/prod.yml
Sunucu ekleme/silme veya IP değişimi sonrası inventory yeniden üretilmelidir.
Outputs
Test
| Output | Açıklama |
|---|---|
ansible_inventory_yaml |
Ansible inventory YAML |
test_private_ips |
Node private IP haritası |
test_public_ips |
Node public IPv4 haritası |
test_floating_ip |
Swarm giriş noktası floating IP |
Prod
| Output | Açıklama |
|---|---|
ansible_inventory_yaml |
Ansible inventory YAML |
prod_private_ips |
Node private IP haritası (app ve db alt anahtarlarıyla) |
prod_public_ips |
Node public IPv4 haritası |
prod_floating_ip |
Swarm giriş noktası floating IP — DNS A kaydı bu IP'ye yönlendirilir |
# Floating IP'yi görmek için:
terraform output prod_floating_ip # veya test_floating_ip
Güvenlik Duvarı Özeti
App Firewall (her iki ortam)
| Port | Protokol | Kaynak | Açıklama |
|---|---|---|---|
22 |
TCP | admin_allowed_cidrs |
SSH |
80 |
TCP | 0.0.0.0/0 | HTTP (SWAG) |
443 |
TCP | 0.0.0.0/0 | HTTPS (SWAG) |
2377 |
TCP | DB subnet | Docker Swarm control plane |
7946 |
TCP/UDP | DB subnet | Docker Swarm node discovery |
4789 |
UDP | DB subnet | Docker Swarm VXLAN overlay |
DB Firewall (her iki ortam)
App subnet kaynaklı:
| Port | Açıklama |
|---|---|
22/tcp |
SSH |
5432/tcp |
PostgreSQL |
27017/tcp |
MongoDB |
2377/tcp |
Docker Swarm control plane |
7946/tcp,udp |
Docker Swarm node discovery |
4789/udp |
Docker Swarm VXLAN overlay |
Prod'a özgü (app subnet kaynaklı):
| Port | Açıklama |
|---|---|
2379/tcp |
etcd client (Patroni + APISIX) |
Prod'a özgü (DB subnet içi, karşılıklı):
| Port | Açıklama |
|---|---|
5432/tcp |
Patroni replikasyon |
27017/tcp |
MongoDB replica set internal |
2379/tcp |
etcd client |
2380/tcp |
etcd peer |
8008/tcp |
Patroni REST API |
IP kısıtlaması (admin paneli, dashboard vb.) Hetzner Firewall'da değil, SWAG nginx konfigürasyonunda yapılır.
Sonraki Adım
Terraform apply ve inventory üretiminin ardından Ansible bootstrap çalıştırılır. Detaylar için ansible/README.md dosyasına bakın.