Document and commit the production bootstrap state after the initial Hetzner and Ansible rollout. - switch Ansible prod runbooks to use the shared vault password file - record production admin CIDRs, SSH key path, encrypted group vault, and encrypted per-host vault files - add generated production inventory and the prod setup history notes from the first bootstrap - keep root password login disabled while preserving key-based root access for Ansible bootstrap continuity - document separate Hetzner projects and tokens for test/prod and commit the prod provider lock file - remove the private Redis firewall allowance from the prod Terraform firewall and matching setup docs
4.9 KiB
Prod Ortamı Kurulum Geçmişi
İlk prod kurulumunda yaşanan sorunlar, uygulanan düzeltmeler ve mevcut durum.
Terraform
Ayrı Hetzner Projesi Zorunluluğu
Test ve prod ayrı Hetzner Cloud projelerinde çalışır. Her proje için ayrı API token alınmalıdır.
Aynı token kullanılırsa terraform apply sırasında SSH key çakışması hatası alınır:
SSH key not unique (uniqueness_error, <fingerprint>)
Hetzner Cloud, aynı public key'i bir projede yalnızca bir kez kabul eder. Test projesinde oluşturulmuş key, prod projesine ait olmayan bir token ile kullanılamaz.
Düzeltme: terraform/hetzner/prod/terraform.tfvars içindeki hcloud_token değeri iklim_prod projesinin token'ı olmalıdır.
State Kaybı Sonrası SSH Key Import
Terraform state'i olmadan terraform apply çalıştırılırsa, Hetzner'da zaten var olan SSH key yeniden oluşturulmaya çalışılır ve yukarıdaki hata alınır. Bu durumda key Hetzner Console → Security → SSH Keys üzerinden ID'si bulunarak import edilir:
terraform import hcloud_ssh_key.admin <ID>
prevent_destroy
Prod sunucuları lifecycle { prevent_destroy = true } ile korunur. terraform destroy çalıştırmak gerekirse bu değer geçici olarak false yapılır, işlem bittikten sonra tekrar true'ya alınır.
Inventory Üretimi
cd Environment_Infrastructure/terraform/hetzner/prod
mkdir -p ../../../ansible/prod/inventory/generated
terraform output -raw ansible_inventory_yaml > ../../../ansible/prod/inventory/generated/prod.yml
Ansible
admin_allowed_cidrs
group_vars/all/vars.yml içindeki admin_allowed_cidrs değeri başlangıçta 127.0.0.1/8 olarak tanımlanmıştı. Bu değer hardening rolü tarafından firewalld'a uygulanır ve SSH erişimini tamamen kapatır.
Doğru değer: tüm admin IP'lerini boşlukla ayrılmış string olarak içermelidir.
admin_allowed_cidrs: "78.187.87.109/32 95.70.151.248/32"
Terraform terraform.tfvars içindeki admin_allowed_cidrs ile birebir uyumlu olmalıdır.
admin_ssh_public_key_path
group_vars/all/vars.yml içinde başlangıçta ~/.ssh/id_ed25519.pub yazıyordu; bu makinede bu dosya yoktu. Doğru değer:
admin_ssh_public_key_path: "~/.ssh/id_rsa.pub"
PermitRootLogin
Hardening rolü başlangıçta PermitRootLogin no uyguluyordu. Bu ayar sshd handler'ı ilk play'in sonunda tetiklediğinden, aynı Ansible çalışmasının devamındaki play'ler (swarm, db_labels, db_stack, act_runner) root ile bağlanamıyordu.
Düzeltme: PermitRootLogin prohibit-password olarak değiştirildi. Key tabanlı root girişi açık kalır; parola ile root girişi engellenir. Ansible tüm bootstrap boyunca root ile bağlanmaya devam edebilir.
vault_iklim_password — Per-Host Şifre
vault_iklim_password başlangıçta group_vars/all/vault.yml içinde tek bir değer olarak tanımlıydı; tüm sunuculara aynı şifre uygulanıyordu.
Her sunucuya farklı şifre vermek için host_vars/<hostname>/vault.yml yapısına geçildi:
prod/
group_vars/all/vault.yml ← vault_iklim_password KALDIRILDI
host_vars/
iklim-app-01/vault.yml ← vault_iklim_password: "<şifre>"
iklim-app-02/vault.yml
iklim-app-03/vault.yml
iklim-db-01/vault.yml
iklim-db-02/vault.yml
iklim-db-03/vault.yml
Her dosya ayrı ayrı şifrelenir: ansible-vault encrypt host_vars/<hostname>/vault.yml
StorageBox Mount
StorageBox WebDAV mount (/mnt/storagebox) davfs2 ile yapılır. Aynı anda 6 sunucunun mount denemesi zaman zaman sorun çıkarabilir; Ansible idempotent çalıştığından tekrar çalıştırmak yeterlidir.
Bootstrap Çalıştırma Sırası
cd Environment_Infrastructure/ansible/prod
# 1. Tüm node'lar
ansible-playbook prod-bootstrap.yml \
--tags base,hardening,docker,node_dirs,storagebox,storagebox_ssh_key \
--ask-vault-pass
# 2. Swarm kurulumu
ansible-playbook prod-bootstrap.yml \
--tags swarm \
--ask-vault-pass
# 3. DB node label'ları
ansible-playbook prod-bootstrap.yml \
--tags db_labels \
--ask-vault-pass
# 4. DB node konfigürasyonu
ansible-playbook prod-bootstrap.yml \
--tags db_stack \
--ask-vault-pass
# 5. Act runner kurulumu
ansible-playbook prod-bootstrap.yml \
--tags act_runner \
--ask-vault-pass
Mevcut Durum (2026-05-19)
| Adım | Durum |
|---|---|
| Terraform — 6 sunucu, ağ, firewall, floating IP | ✅ |
| Ansible base + hardening + docker + node_dirs | ✅ |
| Ansible storagebox + storagebox_ssh_key | ✅ |
| Ansible swarm (3 manager app + 3 worker db) | ✅ |
| Ansible db_labels (Patroni koordinasyonu için) | ✅ |
| Ansible db_stack (StorageBox DB dizinleri) | ✅ |
| Ansible act_runner (3 prod runner Gitea'da Idle) | ✅ |
| DB stack deploy (docker-stack-db.prod.yml) | ⏳ bekliyor |
| MongoDB replica set init | ⏳ bekliyor |
| Ana infra stack deploy (docker-stack-infra.prod.yml) | ⏳ bekliyor |
| Deploy pipeline ilk çalışma | ⏳ bekliyor |