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
139 lines
4.9 KiB
Markdown
139 lines
4.9 KiB
Markdown
# 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:
|
||
|
||
```bash
|
||
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
|
||
|
||
```bash
|
||
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.
|
||
|
||
```yaml
|
||
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:
|
||
|
||
```yaml
|
||
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:
|
||
|
||
```text
|
||
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ı
|
||
|
||
```bash
|
||
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 |
|