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
208 lines
6.0 KiB
Markdown
208 lines
6.0 KiB
Markdown
# 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ı
|
||
|
||
```text
|
||
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ı.
|
||
- Her ortam için **ayrı** Hetzner Cloud projesi ve API token'ı hazır olmalı (aşağıya bak).
|
||
- `terraform.tfvars` dosyası oluşturulmuş olmalı (bkz. `terraform.tfvars.example`).
|
||
|
||
## ⚠️ Her Ortam İçin Ayrı Hetzner Projesi Gereklidir
|
||
|
||
Test ve prod **farklı Hetzner Cloud projeleri** altında çalışır; her projenin kendi API token'ı olmalıdır.
|
||
|
||
**Neden ayrı proje?**
|
||
|
||
- Hetzner Cloud, aynı SSH public key'i bir projede yalnızca bir kez kabul eder. Test ortamının token'ı prod için kullanılırsa `terraform apply` SSH key çakışmasıyla (`uniqueness_error`) hata verir.
|
||
- Kaynak izolasyonu: test destroy işlemi prod kaynaklarını etkilemez.
|
||
- Maliyet ve kota takibi ortam bazında yapılabilir.
|
||
|
||
**Token nasıl alınır:**
|
||
|
||
1. [Hetzner Cloud Console](https://console.hetzner.cloud) → ilgili projeyi seç (ör. `iklim_prod`).
|
||
2. **Security → API Tokens → Generate API Token** — Read & Write izni ver.
|
||
3. Token yalnızca bir kez gösterilir; hemen kopyala.
|
||
4. `terraform.tfvars` içindeki `hcloud_token` değerine yapıştır.
|
||
|
||
> Test `terraform.tfvars` içindeki token prod dizinine **kopyalanmamalıdır.** Her ortamın kendi dizininde kendi token'ı olmalıdır.
|
||
|
||
## terraform.tfvars Kurulumu
|
||
|
||
```bash
|
||
# Test için:
|
||
cd terraform/hetzner/test
|
||
cp terraform.tfvars.example terraform.tfvars
|
||
# hcloud_token = iklim_test projesi token'ı
|
||
|
||
# Prod için:
|
||
cd terraform/hetzner/prod
|
||
cp terraform.tfvars.example terraform.tfvars
|
||
# hcloud_token = iklim_prod projesi token'ı
|
||
```
|
||
|
||
`terraform.tfvars` içindeki değişkenler:
|
||
|
||
| Değişken | Açıklama |
|
||
| --- | --- |
|
||
| `hcloud_token` | **Ortama özel** Hetzner Cloud API token'ı — test ve prod token'ları birbirinden farklıdır |
|
||
| `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.tfvars` hassas bilgi içerir; repository'e commit edilmez.
|
||
|
||
## Terraform Komutları
|
||
|
||
Tüm komutlar ilgili ortam dizininden çalıştırılmalıdır:
|
||
|
||
```bash
|
||
# Test:
|
||
cd terraform/hetzner/test
|
||
|
||
# Prod:
|
||
cd terraform/hetzner/prod
|
||
```
|
||
|
||
### Başlatma
|
||
|
||
```bash
|
||
terraform init
|
||
```
|
||
|
||
### Değişiklik önizleme
|
||
|
||
```bash
|
||
terraform plan
|
||
```
|
||
|
||
### Uygulama
|
||
|
||
```bash
|
||
terraform apply
|
||
```
|
||
|
||
### Kaynakları kaldırma
|
||
|
||
```bash
|
||
terraform destroy
|
||
```
|
||
|
||
## Ansible Inventory Üretimi
|
||
|
||
`terraform apply` tamamlandıktan sonra Ansible inventory'si şu komutlarla üretilir:
|
||
|
||
```bash
|
||
# 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 |
|
||
|
||
```bash
|
||
# 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.
|