Implement: Gitea Actions runner, automated DB stack, and Turkish localization
* Introduces an Ansible role for installing and registering `act_runner` for Gitea Actions. * Automates PostgreSQL and MongoDB deployment on Docker Swarm in the test environment, leveraging Docker named volumes for data persistence. * Translates core documentation, including `README.md` and `setup/04-test-db-docker-kurulum.md`, to Turkish. * Adds comprehensive documentation for firewall architecture (`facts/firewall.md`) and Docker Swarm node recovery (`facts/swarm-node-recovery.md`). * Enhances security hardening by ensuring `fail2ban` is enabled and streamlining admin SSH key management via Ansible. * Updates Ansible vault structure to support new secret variables and adds `.vault_pass` to `.gitignore`.
This commit is contained in:
parent
bbeaf97815
commit
2198f932cd
2
.gitignore
vendored
2
.gitignore
vendored
@ -48,3 +48,5 @@ runner-config.secret.yaml
|
|||||||
*.swo
|
*.swo
|
||||||
|
|
||||||
*.pdf
|
*.pdf
|
||||||
|
|
||||||
|
ansible/.vault_pass
|
||||||
|
|||||||
199
README.md
199
README.md
@ -1,86 +1,87 @@
|
|||||||
# 🌍 Environment Infrastructure
|
# 🌍 Sunucu Ortam ve Altyapıları
|
||||||
|
|
||||||
Infrastructure-as-code and operational runbook repository for `iklim.co` test and production environments on Hetzner Cloud.
|
`iklim.co` test ve prod ortamları için Hetzner Cloud üzerinde Infrastructure-as-code ve operasyonel runbook deposu.
|
||||||
|
|
||||||
This repository defines:
|
Bu depo şunları kapsar:
|
||||||
- 🧱 Terraform resources for Hetzner infrastructure (`test` and `prod`)
|
- 🧱 Hetzner altyapısı için Terraform kaynakları (`test` ve `prod`)
|
||||||
- 🤖 Ansible bootstrap playbooks, shared roles, and inventory targets
|
- 🤖 Ansible bootstrap playbook'ları, paylaşımlı roller ve envanter hedefleri
|
||||||
- 📚 End-to-end setup guides and roadmap documents (mostly Turkish)
|
- 📚 Uçtan uca kurulum rehberleri ve yol haritası dokümanları
|
||||||
- 📊 Sizing/cost analysis and supporting reference assets
|
- 📊 Boyutlandırma/maliyet analizi ve referans kaynakları
|
||||||
|
|
||||||
## 🎯 Scope
|
## 🎯 Kapsam
|
||||||
|
|
||||||
The main goal is to standardize and document infrastructure provisioning with clear responsibility boundaries:
|
Temel amaç, sorumluluk sınırları net biçimde tanımlanmış, standart ve belgelenmiş bir altyapı provisioning süreci oluşturmaktır:
|
||||||
|
|
||||||
- 🧱 **Terraform**: creates cloud infrastructure (servers, private networks, firewalls, placement groups, floating IPs, SSH key registration, inventory output)
|
- 🧱 **Terraform**: bulut altyapısını oluşturur (sunucular, private ağlar, firewall'lar, placement group'lar, floating IP'ler, SSH key kaydı, envanter çıktısı)
|
||||||
- 🤖 **Ansible**: prepares OS, security hardening, Docker/Swarm, runner setup, and StorageBox mount workflows via in-repo playbooks and shared roles
|
- 🤖 **Ansible**: OS hazırlığı, güvenlik sertleştirme, Docker/Swarm, runner kurulumu ve StorageBox mount süreçlerini depodaki playbook ve paylaşımlı roller aracılığıyla yönetir
|
||||||
- 🚀 **Application/stack deployment**: handled in related deployment workflows and stack manifests referenced by roadmap docs
|
- 🚀 **Uygulama/stack dağıtımı**: yol haritası dokümanlarında referans verilen ilgili deployment workflow'ları ve stack manifest'leri tarafından yönetilir
|
||||||
|
|
||||||
## 📌 Current Repository Status
|
## 📌 Mevcut Depo Durumu
|
||||||
|
|
||||||
As of now, this repository primarily contains:
|
Bu depo şu an ağırlıklı olarak şunları içermektedir:
|
||||||
|
|
||||||
- 🧱 Ready Terraform code for:
|
- 🧱 Hazır Terraform kodu:
|
||||||
- `terraform/hetzner/test`
|
- `terraform/hetzner/test`
|
||||||
- `terraform/hetzner/prod`
|
- `terraform/hetzner/prod`
|
||||||
- 🤖 Ansible automation assets for both environments:
|
- 🤖 Her iki ortam için Ansible otomasyon varlıkları:
|
||||||
- `ansible/test/test-bootstrap.yml`
|
- `ansible/test/test-bootstrap.yml`
|
||||||
- `ansible/prod/prod-bootstrap.yml`
|
- `ansible/prod/prod-bootstrap.yml`
|
||||||
- `ansible/roles/*`
|
- `ansible/roles/*`
|
||||||
- `ansible/test/group_vars/*` and `ansible/prod/group_vars/*`
|
- `ansible/test/group_vars/*` ve `ansible/prod/group_vars/*`
|
||||||
- 📦 Inventory artifacts and output targets:
|
- 📦 Envanter çıktıları ve hedef yollar:
|
||||||
- `ansible/test/inventory/generated/test.yml` (tracked sample)
|
- `ansible/test/inventory/generated/test.yml` (takip edilen örnek)
|
||||||
- `ansible/prod/inventory/generated/prod.yml` (expected output path)
|
- `ansible/prod/inventory/generated/prod.yml` (beklenen çıktı yolu)
|
||||||
- 📘 Detailed setup phases:
|
- 📘 Detaylı kurulum aşamaları:
|
||||||
- `setup/00-genel-yol-haritasi.md` through `setup/09-prod-runner-ha-ve-swarm.md`
|
- `setup/00-genel-yol-haritasi.md` — `setup/09-prod-runner-ha-ve-swarm.md`
|
||||||
- 🛣️ Environment roadmap steps:
|
- 🛣️ Ortam yol haritası adımları:
|
||||||
- `roadmap/test-env/*`
|
- `roadmap/test-env/*`
|
||||||
- `roadmap/prod-env/*`
|
- `roadmap/prod-env/*`
|
||||||
- 📈 Capacity planning and reference charts:
|
- 📈 Kapasite planlama ve referans grafikler:
|
||||||
- `hetzner-sizing-report.md`
|
- `hetzner-sizing-report.md`
|
||||||
- `test-app-graphs.png`
|
- `test-app-graphs.png`
|
||||||
- `test-db-graphs.png`
|
- `test-db-graphs.png`
|
||||||
|
|
||||||
## 🧭 Target Environment Topology
|
## 🧭 Hedef Ortam Topolojisi
|
||||||
|
|
||||||
### 🧪 Test
|
### 🧪 Test
|
||||||
|
|
||||||
| Node | Role | Private IP | Suggested Type |
|
| Node | Rol | Private IP | Önerilen Tip |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| `iklim-app-01` | Swarm manager + app worker + test runner | `10.10.10.11` | `cpx42` |
|
| `iklim-app-01` | Swarm manager + app worker + test runner | `10.10.10.11` | `cpx42` |
|
||||||
| `iklim-db-01` | DB host (manual/stack-based DB setup path) | `10.10.20.11` | `cpx42` |
|
| `iklim-db-01` | DB host (manuel/stack tabanlı DB kurulum yolu) | `10.10.20.11` | `cpx42` |
|
||||||
|
|
||||||
### 🏭 Production
|
### 🏭 Production
|
||||||
|
|
||||||
| Node | Role | Private IP | Suggested Type |
|
| Node | Rol | Private IP | Önerilen Tip |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| `iklim-app-01` | Swarm manager + app worker + runner (primary FIP target) | `10.20.10.11` | `cpx42` |
|
| `iklim-app-01` | Swarm manager + app worker + runner (birincil FIP hedefi) | `10.20.10.11` | `cpx42` |
|
||||||
| `iklim-app-02` | Swarm manager + app worker + runner | `10.20.10.12` | `cpx42` |
|
| `iklim-app-02` | Swarm manager + app worker + runner | `10.20.10.12` | `cpx42` |
|
||||||
| `iklim-app-03` | Swarm manager + app worker + runner | `10.20.10.13` | `cpx42` |
|
| `iklim-app-03` | Swarm manager + app worker + runner | `10.20.10.13` | `cpx42` |
|
||||||
| `iklim-db-01` | DB cluster node | `10.20.20.11` | `cpx32` |
|
| `iklim-db-01` | DB cluster node | `10.20.20.11` | `cpx32` |
|
||||||
| `iklim-db-02` | DB cluster node | `10.20.20.12` | `cpx32` |
|
| `iklim-db-02` | DB cluster node | `10.20.20.12` | `cpx32` |
|
||||||
| `iklim-db-03` | DB cluster node | `10.20.20.13` | `cpx32` |
|
| `iklim-db-03` | DB cluster node | `10.20.20.13` | `cpx32` |
|
||||||
|
|
||||||
## 🔐 Security and Network Baseline
|
## 🔐 Güvenlik ve Ağ Temeli
|
||||||
|
|
||||||
Core decisions reflected in Terraform and setup docs:
|
Terraform ve kurulum dokümanlarına yansıtılan temel kararlar:
|
||||||
|
|
||||||
- Test and prod are separated into different Hetzner Cloud projects/tokens.
|
- Test ve prod, ayrı Hetzner Cloud proje ve token'larıyla birbirinden yalıtılmıştır.
|
||||||
- Public ingress is limited to:
|
- Kamuya açık gelen trafik şunlarla sınırlıdır:
|
||||||
- `22/tcp` (admin CIDRs only)
|
- `22/tcp` (yalnızca admin CIDR'ları)
|
||||||
- `80/tcp`
|
- `80/tcp`
|
||||||
- `443/tcp`
|
- `443/tcp`
|
||||||
- Critical services remain private-only (for example Vault `8200`, PostgreSQL `5432`, MongoDB `27017`, internal observability and broker ports).
|
- Kritik servisler yalnızca private ağda erişilebilir (örneğin Vault `8200`, PostgreSQL `5432`, MongoDB `27017`, iç gözlemlenebilirlik ve broker portları).
|
||||||
- Placement groups are used for host-spread strategy.
|
- Host dağılımı stratejisi için placement group'lar kullanılmaktadır.
|
||||||
- `prevent_destroy = true` is enabled on server resources to reduce accidental deletion risk.
|
- Sunucu kaynaklarında yanlışlıkla silinmeye karşı `prevent_destroy = true` etkinleştirilmiştir.
|
||||||
- Terraform state and secret files must not be committed.
|
- Terraform state ve gizli dosyalar commit'lenmemelidir.
|
||||||
|
|
||||||
See:
|
Ayrıca bkz.:
|
||||||
- `setup/01-private-network-port-matrisi.md`
|
- [[facts/firewall.md]] — tüm firewall kurallarının araç bazında özet dökümantasyonu
|
||||||
|
- [[setup/01-private-network-port-matrisi.md]]
|
||||||
- `terraform/hetzner/test/firewall.tf`
|
- `terraform/hetzner/test/firewall.tf`
|
||||||
- `terraform/hetzner/prod/firewall.tf`
|
- `terraform/hetzner/prod/firewall.tf`
|
||||||
|
|
||||||
## 🗂️ Repository Structure
|
## 🗂️ Depo Yapısı
|
||||||
|
|
||||||
```text
|
```text
|
||||||
Environment_Infrastructure/
|
Environment_Infrastructure/
|
||||||
@ -123,35 +124,37 @@ Environment_Infrastructure/
|
|||||||
│ └── hetzner/
|
│ └── hetzner/
|
||||||
│ ├── test/
|
│ ├── test/
|
||||||
│ └── prod/
|
│ └── prod/
|
||||||
|
├── facts/
|
||||||
|
│ └── firewall.md
|
||||||
├── hetzner-sizing-report.md
|
├── hetzner-sizing-report.md
|
||||||
├── setup-vs-roadmap-map.md
|
├── setup-vs-roadmap-map.md
|
||||||
├── test-app-graphs.png
|
├── test-app-graphs.png
|
||||||
└── test-db-graphs.png
|
└── test-db-graphs.png
|
||||||
```
|
```
|
||||||
|
|
||||||
## ✅ Prerequisites
|
## ✅ Ön Koşullar
|
||||||
|
|
||||||
- Terraform `>= 1.6`
|
- Terraform `>= 1.6`
|
||||||
- Hetzner Cloud account(s) and API token per environment
|
- Hetzner Cloud hesabı ve ortam başına API token
|
||||||
- SSH key pair (public key path used in Terraform variables)
|
- SSH anahtar çifti (public key yolu Terraform değişkenlerinde kullanılır)
|
||||||
- Linux/macOS shell tools (`bash`, `cp`, `sed` or editor of your choice)
|
- Linux/macOS kabuk araçları (`bash`, `cp`, `sed` veya tercih edilen metin editörü)
|
||||||
- Optional but expected in later phases: Ansible, Docker, access to Gitea/Harbor/StorageBox
|
- İlerleyen aşamalarda gerekli: Ansible, Docker, Gitea/Harbor/StorageBox erişimi
|
||||||
|
|
||||||
## 🛠️ Terraform Usage
|
## 🛠️ Terraform Kullanımı
|
||||||
|
|
||||||
### 1) 🧪 Test Infrastructure
|
### 1) 🧪 Test Altyapısı
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd terraform/hetzner/test
|
cd terraform/hetzner/test
|
||||||
cp terraform.tfvars.example terraform.tfvars
|
cp terraform.tfvars.example terraform.tfvars
|
||||||
```
|
```
|
||||||
|
|
||||||
Edit `terraform.tfvars` values:
|
`terraform.tfvars` değerlerini düzenle:
|
||||||
- `hcloud_token`
|
- `hcloud_token`
|
||||||
- `admin_allowed_cidrs`
|
- `admin_allowed_cidrs`
|
||||||
- optional overrides (`location`, image, server types, key path)
|
- isteğe bağlı geçersiz kılmalar (`location`, image, sunucu tipleri, key yolu)
|
||||||
|
|
||||||
Then run:
|
Ardından çalıştır:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
terraform init
|
terraform init
|
||||||
@ -161,19 +164,19 @@ mkdir -p ../../../ansible/test/inventory/generated
|
|||||||
terraform output -raw ansible_inventory_yaml > ../../../ansible/test/inventory/generated/test.yml
|
terraform output -raw ansible_inventory_yaml > ../../../ansible/test/inventory/generated/test.yml
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2) 🏭 Production Infrastructure
|
### 2) 🏭 Production Altyapısı
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd terraform/hetzner/prod
|
cd terraform/hetzner/prod
|
||||||
cp terraform.tfvars.example terraform.tfvars
|
cp terraform.tfvars.example terraform.tfvars
|
||||||
```
|
```
|
||||||
|
|
||||||
Edit `terraform.tfvars` values:
|
`terraform.tfvars` değerlerini düzenle:
|
||||||
- `hcloud_token` (prod token)
|
- `hcloud_token` (prod token)
|
||||||
- `admin_allowed_cidrs`
|
- `admin_allowed_cidrs`
|
||||||
- optional overrides
|
- isteğe bağlı geçersiz kılmalar
|
||||||
|
|
||||||
Then run:
|
Ardından çalıştır:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
terraform init
|
terraform init
|
||||||
@ -183,79 +186,79 @@ mkdir -p ../../../ansible/prod/inventory/generated
|
|||||||
terraform output -raw ansible_inventory_yaml > ../../../ansible/prod/inventory/generated/prod.yml
|
terraform output -raw ansible_inventory_yaml > ../../../ansible/prod/inventory/generated/prod.yml
|
||||||
```
|
```
|
||||||
|
|
||||||
## 🧱 Setup Flow (Canonical Order)
|
## 🧱 Kurulum Akışı (Kanonik Sıra)
|
||||||
|
|
||||||
Use setup documents in this sequence:
|
Kurulum dokümanlarını bu sırayla kullan:
|
||||||
|
|
||||||
1. `setup/00-genel-yol-haritasi.md` — global decisions and boundaries
|
1. `setup/00-genel-yol-haritasi.md` — genel kararlar ve sınırlar
|
||||||
2. `setup/01-private-network-port-matrisi.md` — private/public port policy
|
2. `setup/01-private-network-port-matrisi.md` — private/public port politikası
|
||||||
3. `setup/02-test-terraform-iaac.md` — test Terraform phase
|
3. `setup/02-test-terraform-iaac.md` — test Terraform aşaması
|
||||||
4. `setup/03-test-ansible-bootstrap.md` — test OS/bootstrap/hardening
|
4. `setup/03-test-ansible-bootstrap.md` — test OS/bootstrap/sertleştirme
|
||||||
5. `setup/04-test-db-docker-kurulum.md` — test DB stack setup on Swarm
|
5. `setup/04-test-db-docker-kurulum.md` — test DB stack kurulumu (Swarm üzerinde)
|
||||||
6. `setup/05-test-runner-ve-deploy-onkosullari.md` — test runner and deploy prerequisites
|
6. `setup/05-test-runner-ve-deploy-onkosullari.md` — test runner ve deploy ön koşulları
|
||||||
7. `setup/06-prod-terraform-iaac.md` — prod Terraform phase
|
7. `setup/06-prod-terraform-iaac.md` — prod Terraform aşaması
|
||||||
8. `setup/07-prod-ansible-bootstrap.md` — prod OS/bootstrap/hardening
|
8. `setup/07-prod-ansible-bootstrap.md` — prod OS/bootstrap/sertleştirme
|
||||||
9. `setup/08-prod-db-cluster-kurulum.md` — prod DB cluster stack (MongoDB + Patroni/etcd)
|
9. `setup/08-prod-db-cluster-kurulum.md` — prod DB cluster stack (MongoDB + Patroni/etcd)
|
||||||
10. `setup/09-prod-runner-ha-ve-swarm.md` — prod runner HA and deploy lock model
|
10. `setup/09-prod-runner-ha-ve-swarm.md` — prod runner HA ve deploy kilit modeli
|
||||||
|
|
||||||
## 🛣️ Roadmap Documents
|
## 🛣️ Yol Haritası Dokümanları
|
||||||
|
|
||||||
The roadmap folders track integration work for Swarm stacks, SWAG, APISIX, pipeline updates, and verification checklists:
|
Yol haritası klasörleri; Swarm stack'leri, SWAG, APISIX, pipeline güncellemeleri ve doğrulama kontrol listeleri için entegrasyon çalışmalarını takip eder:
|
||||||
|
|
||||||
- `roadmap/test-env/*`
|
- `roadmap/test-env/*`
|
||||||
- `roadmap/prod-env/*`
|
- `roadmap/prod-env/*`
|
||||||
|
|
||||||
These documents often reference files from related repositories (for example application root repo workflows and stack files). Treat them as implementation guidance aligned with this infrastructure baseline.
|
Bu dokümanlar zaman zaman ilgili repolardan (örneğin uygulama ana deposu workflow ve stack dosyaları) dosyalara referans verir. Bu altyapı temeliyle hizalanmış uygulama rehberleri olarak değerlendirilmelidir.
|
||||||
|
|
||||||
## 💰 Sizing and Cost Snapshot
|
## 💰 Boyutlandırma ve Maliyet Özeti
|
||||||
|
|
||||||
Reference: `hetzner-sizing-report.md`
|
Referans: `hetzner-sizing-report.md`
|
||||||
|
|
||||||
Suggested baseline:
|
Önerilen temel yapı:
|
||||||
- **Test:** `2 x cpx42` (app + db)
|
- **Test:** `2 x cpx42` (app + db)
|
||||||
- **Prod:** `3 x cpx42` (app) + `3 x cpx32` (db)
|
- **Prod:** `3 x cpx42` (app) + `3 x cpx32` (db)
|
||||||
|
|
||||||
Approximate monthly total in the report:
|
Rapordaki yaklaşık aylık toplam:
|
||||||
- Test: `$59.98`
|
- Test: `$59.98`
|
||||||
- Prod: `$139.44`
|
- Prod: `$139.44`
|
||||||
- Combined: `$199.42`
|
- Toplam: `$199.42`
|
||||||
|
|
||||||
## 🔑 Secrets and State Management
|
## 🔑 Gizli Bilgi ve State Yönetimi
|
||||||
|
|
||||||
Never commit:
|
Kesinlikle commit'lenmemeli:
|
||||||
- `terraform.tfvars`, `*.tfvars`, `*.tfstate`, `.terraform/`
|
- `terraform.tfvars`, `*.tfvars`, `*.tfstate`, `.terraform/`
|
||||||
- private keys, certificates, `.env` secrets
|
- private key'ler, sertifikalar, `.env` gizli bilgileri
|
||||||
- runner tokens and vault password files
|
- runner token'ları ve vault parola dosyaları
|
||||||
|
|
||||||
See `.gitignore` for enforced patterns.
|
Zorunlu kalıplar için `.gitignore` dosyasına bkz.
|
||||||
|
|
||||||
Recommended:
|
Önerilen:
|
||||||
- keep runtime secrets in secure secret stores / encrypted vault files
|
- çalışma zamanı gizli bilgilerini güvenli gizli depolarda / şifreli vault dosyalarında tut
|
||||||
- keep generated runtime artifacts outside version control unless explicitly sanitized
|
- üretilen çalışma zamanı artifakt'larını, açıkça temizlenmedikçe versiyon kontrolü dışında tut
|
||||||
|
|
||||||
## ⚠️ Known Gaps / Notes
|
## ⚠️ Bilinen Eksikler / Notlar
|
||||||
|
|
||||||
- `ansible/prod/inventory/generated/prod.yml` is an expected output path but may not exist until generated.
|
- `ansible/prod/inventory/generated/prod.yml` beklenen bir çıktı yoludur; üretilene kadar mevcut olmayabilir.
|
||||||
- Some roadmap steps target files under the broader `iklim.co` application repository, not this repository alone.
|
- Bazı yol haritası adımları, yalnızca bu depo değil, daha geniş kapsamlı `iklim.co` uygulama deposundaki dosyaları hedef alır.
|
||||||
|
|
||||||
## ✅ Quick Validation Checklist
|
## ✅ Hızlı Doğrulama Kontrol Listesi
|
||||||
|
|
||||||
After Terraform apply:
|
Terraform apply sonrası:
|
||||||
|
|
||||||
- servers are created with expected names and private IPs
|
- sunucular beklenen isimler ve private IP'lerle oluşturulmuş
|
||||||
- floating IP exists and is attached
|
- floating IP mevcut ve bağlı
|
||||||
- firewalls expose only intended public ports
|
- firewall'lar yalnızca amaçlanan public portları açıyor
|
||||||
- placement groups are assigned
|
- placement group'lar atanmış
|
||||||
- generated inventory YAML is exported to `ansible/{test,prod}/inventory/generated/*.yml`
|
- üretilen envanter YAML `ansible/{test,prod}/inventory/generated/*.yml` yoluna aktarılmış
|
||||||
|
|
||||||
After bootstrap/deploy phases:
|
Bootstrap/deploy aşamaları sonrası:
|
||||||
|
|
||||||
- Swarm state and labels match documentation
|
- Swarm durumu ve etiketleri dökümantasyonla eşleşiyor
|
||||||
- DB accessibility is private-only
|
- DB erişimi yalnızca private ağdan mümkün
|
||||||
- Vault/API gateways follow public/private exposure rules
|
- Vault/API gateway'leri public/private erişim kurallarına uyuyor
|
||||||
- runner and deploy lock behavior align with environment policy
|
- Runner ve deploy kilit davranışı ortam politikasıyla örtüşüyor
|
||||||
|
|
||||||
## 🔗 References
|
## 🔗 Referanslar
|
||||||
|
|
||||||
- Hetzner Terraform Provider: https://registry.terraform.io/providers/hetznercloud/hcloud/latest
|
- Hetzner Terraform Provider: https://registry.terraform.io/providers/hetznercloud/hcloud/latest
|
||||||
- Hetzner Networks: https://docs.hetzner.com/cloud/networks/overview/
|
- Hetzner Networks: https://docs.hetzner.com/cloud/networks/overview/
|
||||||
|
|||||||
8
ansible/roles/act_runner/defaults/main.yml
Normal file
8
ansible/roles/act_runner/defaults/main.yml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
act_runner_version: "0.2.12"
|
||||||
|
act_runner_arch: "linux-amd64"
|
||||||
|
act_runner_gitea_url: "https://git.tarla.io"
|
||||||
|
act_runner_name: "iklim-test-app"
|
||||||
|
act_runner_labels: "ubuntu-latest,ubuntu-22.04,ubuntu-20.04"
|
||||||
|
# Gitea'dan alınan tek seferlik registration token; kayıt olmadıysa boş bırakılır.
|
||||||
|
act_runner_registration_token: "{{ vault_gitea_runner_token | default('') }}"
|
||||||
6
ansible/roles/act_runner/handlers/main.yml
Normal file
6
ansible/roles/act_runner/handlers/main.yml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
- name: restart act_runner
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
name: gitea-act-runner
|
||||||
|
state: restarted
|
||||||
|
daemon_reload: true
|
||||||
86
ansible/roles/act_runner/tasks/main.yml
Normal file
86
ansible/roles/act_runner/tasks/main.yml
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
---
|
||||||
|
- name: Install deploy prerequisites
|
||||||
|
ansible.builtin.dnf:
|
||||||
|
name:
|
||||||
|
- gettext
|
||||||
|
- jq
|
||||||
|
- git
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Create gitea-runner system user
|
||||||
|
ansible.builtin.user:
|
||||||
|
name: gitea-runner
|
||||||
|
system: true
|
||||||
|
shell: /bin/bash
|
||||||
|
create_home: true
|
||||||
|
home: /var/lib/gitea-runner
|
||||||
|
groups: docker
|
||||||
|
append: true
|
||||||
|
|
||||||
|
- name: Download act_runner binary
|
||||||
|
ansible.builtin.get_url:
|
||||||
|
url: "https://dl.gitea.com/act_runner/{{ act_runner_version }}/act_runner-{{ act_runner_version }}-{{ act_runner_arch }}"
|
||||||
|
dest: /usr/local/bin/act_runner
|
||||||
|
mode: "0755"
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
|
||||||
|
- name: Create act_runner config directory
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: /etc/gitea-act-runner
|
||||||
|
state: directory
|
||||||
|
owner: gitea-runner
|
||||||
|
group: gitea-runner
|
||||||
|
mode: "0750"
|
||||||
|
|
||||||
|
# Kayıt öncesinde varsayılan config.yaml üretilir; dosya varsa tekrar yazılmaz.
|
||||||
|
- name: Generate default config.yaml
|
||||||
|
ansible.builtin.shell:
|
||||||
|
cmd: /usr/local/bin/act_runner generate-config > /etc/gitea-act-runner/config.yaml
|
||||||
|
creates: /etc/gitea-act-runner/config.yaml
|
||||||
|
become_user: gitea-runner
|
||||||
|
|
||||||
|
- name: Fix config.yaml ownership
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: /etc/gitea-act-runner/config.yaml
|
||||||
|
owner: gitea-runner
|
||||||
|
group: gitea-runner
|
||||||
|
mode: "0640"
|
||||||
|
|
||||||
|
# .runner dosyası varsa runner zaten kayıtlıdır; creates ile idempotent hale gelir.
|
||||||
|
- name: Register runner with Gitea
|
||||||
|
ansible.builtin.command:
|
||||||
|
argv:
|
||||||
|
- /usr/local/bin/act_runner
|
||||||
|
- register
|
||||||
|
- --instance
|
||||||
|
- "{{ act_runner_gitea_url }}"
|
||||||
|
- --token
|
||||||
|
- "{{ act_runner_registration_token }}"
|
||||||
|
- --no-interactive
|
||||||
|
- --name
|
||||||
|
- "{{ act_runner_name }}"
|
||||||
|
- --config
|
||||||
|
- /etc/gitea-act-runner/config.yaml
|
||||||
|
- --labels
|
||||||
|
- "{{ act_runner_labels }}"
|
||||||
|
args:
|
||||||
|
chdir: /var/lib/gitea-runner
|
||||||
|
creates: /var/lib/gitea-runner/.runner
|
||||||
|
become_user: gitea-runner
|
||||||
|
when: act_runner_registration_token | length > 0
|
||||||
|
no_log: true
|
||||||
|
|
||||||
|
- name: Deploy gitea-act-runner systemd service
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: gitea-act-runner.service.j2
|
||||||
|
dest: /etc/systemd/system/gitea-act-runner.service
|
||||||
|
mode: "0644"
|
||||||
|
notify: restart act_runner
|
||||||
|
|
||||||
|
- name: Enable and start gitea-act-runner
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
name: gitea-act-runner
|
||||||
|
enabled: true
|
||||||
|
state: started
|
||||||
|
daemon_reload: true
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Gitea Actions runner
|
||||||
|
After=network.target docker.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=/usr/local/bin/act_runner daemon --config /etc/gitea-act-runner/config.yaml
|
||||||
|
ExecReload=/bin/kill -s HUP $MAINPID
|
||||||
|
WorkingDirectory=/var/lib/gitea-runner
|
||||||
|
User=gitea-runner
|
||||||
|
Group=gitea-runner
|
||||||
|
TimeoutSec=0
|
||||||
|
Restart=always
|
||||||
|
RestartSec=10
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
17
ansible/roles/db_stack/tasks/app_node.yml
Normal file
17
ansible/roles/db_stack/tasks/app_node.yml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
---
|
||||||
|
- name: Stack durumunu kontrol et
|
||||||
|
ansible.builtin.shell: docker stack ls | grep iklim-db
|
||||||
|
register: stack_status
|
||||||
|
failed_when: false
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: DB stack dosyasını oluştur
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: db.stack.yml.j2
|
||||||
|
dest: /opt/iklimco/stacks/db.yml
|
||||||
|
mode: '0600'
|
||||||
|
register: stack_file
|
||||||
|
|
||||||
|
- name: DB stack'i deploy et
|
||||||
|
ansible.builtin.shell: docker stack deploy -c /opt/iklimco/stacks/db.yml iklim-db
|
||||||
|
when: stack_status.rc != 0 or stack_file.changed
|
||||||
12
ansible/roles/db_stack/tasks/db_node.yml
Normal file
12
ansible/roles/db_stack/tasks/db_node.yml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
---
|
||||||
|
- name: MongoDB config dizinini oluştur
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: /opt/iklimco/db/mongodb/config
|
||||||
|
state: directory
|
||||||
|
mode: '0750'
|
||||||
|
|
||||||
|
- name: MongoDB konfigürasyon dosyasını oluştur
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: mongod.conf.j2
|
||||||
|
dest: /opt/iklimco/db/mongodb/config/mongod.conf
|
||||||
|
mode: '0644'
|
||||||
6
ansible/roles/db_stack/tasks/main.yml
Normal file
6
ansible/roles/db_stack/tasks/main.yml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
- include_tasks: db_node.yml
|
||||||
|
when: inventory_hostname in groups['db']
|
||||||
|
|
||||||
|
- include_tasks: app_node.yml
|
||||||
|
when: inventory_hostname in groups['app']
|
||||||
42
ansible/roles/db_stack/templates/db.stack.yml.j2
Normal file
42
ansible/roles/db_stack/templates/db.stack.yml.j2
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
version: "3.8"
|
||||||
|
|
||||||
|
networks:
|
||||||
|
iklimco-net:
|
||||||
|
external: true
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
postgresql_data:
|
||||||
|
mongodb_data:
|
||||||
|
|
||||||
|
services:
|
||||||
|
postgresql:
|
||||||
|
image: {{ db_postgres_image }}
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: "{{ db_postgres_root_user }}"
|
||||||
|
POSTGRES_PASSWORD: "{{ db_postgres_password }}"
|
||||||
|
POSTGRES_DB: postgres
|
||||||
|
PGDATA: /var/lib/postgresql/data/pgdata
|
||||||
|
volumes:
|
||||||
|
- postgresql_data:/var/lib/postgresql/data
|
||||||
|
networks:
|
||||||
|
- iklimco-net
|
||||||
|
deploy:
|
||||||
|
placement:
|
||||||
|
constraints:
|
||||||
|
- node.labels.role == db
|
||||||
|
|
||||||
|
mongodb:
|
||||||
|
image: {{ db_mongo_image }}
|
||||||
|
environment:
|
||||||
|
MONGO_INITDB_ROOT_USERNAME: "{{ db_mongo_root_user }}"
|
||||||
|
MONGO_INITDB_ROOT_PASSWORD: "{{ db_mongo_root_password }}"
|
||||||
|
volumes:
|
||||||
|
- mongodb_data:/data/db
|
||||||
|
- /opt/iklimco/db/mongodb/config/mongod.conf:/etc/mongod.conf
|
||||||
|
command: ["--config", "/etc/mongod.conf"]
|
||||||
|
networks:
|
||||||
|
- iklimco-net
|
||||||
|
deploy:
|
||||||
|
placement:
|
||||||
|
constraints:
|
||||||
|
- node.labels.role == db
|
||||||
7
ansible/roles/db_stack/templates/mongod.conf.j2
Normal file
7
ansible/roles/db_stack/templates/mongod.conf.j2
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
storage:
|
||||||
|
dbPath: /data/db
|
||||||
|
net:
|
||||||
|
port: 27017
|
||||||
|
bindIp: 0.0.0.0
|
||||||
|
security:
|
||||||
|
authorization: enabled
|
||||||
@ -38,6 +38,12 @@
|
|||||||
dest: /etc/fail2ban/jail.local
|
dest: /etc/fail2ban/jail.local
|
||||||
notify: Restart fail2ban
|
notify: Restart fail2ban
|
||||||
|
|
||||||
|
- name: Ensure fail2ban is running and enabled
|
||||||
|
ansible.builtin.service:
|
||||||
|
name: fail2ban
|
||||||
|
state: started
|
||||||
|
enabled: yes
|
||||||
|
|
||||||
- name: Ensure firewalld is running
|
- name: Ensure firewalld is running
|
||||||
ansible.builtin.service:
|
ansible.builtin.service:
|
||||||
name: firewalld
|
name: firewalld
|
||||||
@ -67,6 +73,12 @@
|
|||||||
create_home: yes
|
create_home: yes
|
||||||
state: present
|
state: present
|
||||||
|
|
||||||
|
- name: Add SSH key to iklim user
|
||||||
|
ansible.posix.authorized_key:
|
||||||
|
user: iklim
|
||||||
|
state: present
|
||||||
|
key: "{{ lookup('file', admin_ssh_public_key_path) }}"
|
||||||
|
|
||||||
- name: Configure journald log limits
|
- name: Configure journald log limits
|
||||||
ansible.builtin.lineinfile:
|
ansible.builtin.lineinfile:
|
||||||
path: /etc/systemd/journald.conf
|
path: /etc/systemd/journald.conf
|
||||||
|
|||||||
@ -6,4 +6,13 @@ storagebox_password: "{{ vault_storagebox_password }}"
|
|||||||
iklim_password: "{{ vault_iklim_password }}"
|
iklim_password: "{{ vault_iklim_password }}"
|
||||||
swarm_manager_ip: "10.10.10.11"
|
swarm_manager_ip: "10.10.10.11"
|
||||||
admin_allowed_cidrs: "78.187.87.109/32 95.70.151.248/32"
|
admin_allowed_cidrs: "78.187.87.109/32 95.70.151.248/32"
|
||||||
|
admin_ssh_public_key_path: "~/.ssh/id_rsa.pub"
|
||||||
timezone: "Europe/Istanbul"
|
timezone: "Europe/Istanbul"
|
||||||
|
|
||||||
|
# DB Stack
|
||||||
|
db_postgres_image: "postgis/postgis:17-3.5"
|
||||||
|
db_mongo_image: "mongo:8"
|
||||||
|
db_postgres_root_user: "{{ vault_postgres_root_user }}"
|
||||||
|
db_postgres_password: "{{ vault_postgres_password }}"
|
||||||
|
db_mongo_root_user: "{{ vault_mongo_root_user }}"
|
||||||
|
db_mongo_root_password: "{{ vault_mongo_root_password }}"
|
||||||
|
|||||||
@ -1,25 +1,30 @@
|
|||||||
$ANSIBLE_VAULT;1.1;AES256
|
$ANSIBLE_VAULT;1.1;AES256
|
||||||
32653536356331386232373033363738363336323461363432653031666166343462393737643730
|
63323534653836623136643065383166323661663339653335373139663436316433396137343739
|
||||||
3162386266326333386533373630663563386337613338310a376137623835333461363662323035
|
3039383336313861616236336565323664613333383262610a363436376132316437656239633334
|
||||||
65636332376331643335323265336439613331613238393363626330313831653233373864313033
|
63633863643938373537333562346433313766393732616362306132313430333964373031313962
|
||||||
3430303335306366660a636139623264386437383763316665373230643939653039633330623834
|
3230393837316434650a323933313934316334633931323165633730373933326564316661666332
|
||||||
64636564313232626462373638653538393261323031616563653164323961393664656439393639
|
36323735323736656662366463383431393433643331616134623662663333313364343232653138
|
||||||
37313335313739353564626364313663363038316132633739623338343436303337643162396635
|
61316165636431663230376234626532663431373632393731383434386435353638363365323861
|
||||||
34323838346664303464396438393534636265636262323364643364323163653464303931626130
|
33373462333966663033666463303032343961653533343932363462623637616232666561646335
|
||||||
37663138363966386530323133613661316230303362323937313132306236323339323839633139
|
36623039353633343035353765326339616233666562636438636137303835643736386633623139
|
||||||
34633733333531373233386436313837343364326334386535626262356537376137646163326666
|
66656137646461363165313937306266393035383339363233303066396564346638643539313361
|
||||||
38306238666639623639393137623266363465313264326566663839303664303233666335663731
|
38653930393766656634343334373961323031333938663636623138666661346133316631393231
|
||||||
32633232376164383265313835326433366134613230613164373034663931396161623631666236
|
36393237313439313435363866333364343231613330373439626462356139303061313632343338
|
||||||
37613631353233346464363236383539663461333739396432626638323134383230343163396335
|
38633364343663333139396431663938653263633739383036613935373332653666656633323331
|
||||||
64363333396130326463316538306162363034353936383063333531396233356437333064613230
|
37316535386139633263633266353739386164666564666136643665353135356231323633373363
|
||||||
63353337306632323364336233313836663365623436336532623239633434656563666637333636
|
36646464383766663532353132326162363734366337373537656132366139386362616438616531
|
||||||
31343836353230306461613936383766636138663361343864623466376235666536306133306435
|
34386234306231376162643934643565343364336530616562303739363935353636343633376464
|
||||||
65666338333465653434386166366633383539323566613935363434363735313231336166626364
|
34333835363666303236313363663665653566326365386439653362663462343136316664613036
|
||||||
65353033363366386432306434333135653862616635373837376233326262646330326363626134
|
37616163653561633030376534393533653466373839633661653338313166383332613234666164
|
||||||
32343735386137363334306464383935613531373533363330363635633236313930373865393738
|
37343737316139393930313739366562643539326233366334353566633339333130366263663030
|
||||||
38363564663066363439396532656236656636646365363038393535303632356364613538353737
|
63393437383566393932353230396534383330646364646561323631653338396132303461613636
|
||||||
32636434383766343765643634633464353262396466393265643963383634323730343162323837
|
37306533663732626532393130323933633365336233613334666330343436326137306666636234
|
||||||
39343139613538653531616466303638336133396165646138663463383238616431613563343031
|
30623831303632613866333734306337623230373433373332646534306135333039343231643536
|
||||||
39333139643033326630343630366630633766383861353663353534633436646363356334626438
|
30356238323263653236326662303365343464356264376565326432323335323862366365666561
|
||||||
62306661376339343437643732333032373362633062326365666430616634613537316635653465
|
32316633396430376234636661623464316135333862623531393661343332303033323636393736
|
||||||
64306362386339333562
|
37653830393665363330393135616465363161623861343531636130636132663263613836646264
|
||||||
|
66373962313263643334373664303338636232643535313164343434653532303261346566623232
|
||||||
|
30363662393764316534393030303137663534613564656531616466396232323561623939303733
|
||||||
|
30383637376432346138333365376431396236356263333634613462316131343634663861356564
|
||||||
|
39613965333334303036626237373534333337633261353065336534373732306166643666323435
|
||||||
|
36666239653536653838623864396635663764313738303533323163633261613665
|
||||||
|
|||||||
7
ansible/test/host_vars/iklim-app-01/vault.yml
Normal file
7
ansible/test/host_vars/iklim-app-01/vault.yml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
$ANSIBLE_VAULT;1.1;AES256
|
||||||
|
35336562303132663037626538366261663764666633306237386564303161633730666336643237
|
||||||
|
6563346339646130666531323165316561653861346663610a353036636565333138373139383438
|
||||||
|
33386634306666373932353134323830343666653266343262373236306631613735636430663838
|
||||||
|
3338643164613532370a323935383938383331303036353238376332616130383935623362626235
|
||||||
|
35653566383764303765373866376636323461383332346661363866623962643439376439363432
|
||||||
|
3335613733386536613765396136316364333934643465653234
|
||||||
7
ansible/test/host_vars/iklim-db-01/vault.yml
Normal file
7
ansible/test/host_vars/iklim-db-01/vault.yml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
$ANSIBLE_VAULT;1.1;AES256
|
||||||
|
37303034646630363834303561383932623131306331326530383861633838353039633364326162
|
||||||
|
6237613235633062356633346663336137353331653866640a333663646539646435363031343034
|
||||||
|
30633662633838376130656462646566366633333734333761616563333861386166313832333332
|
||||||
|
3733363866323036660a373966373766393965623231656266323630376133303963363639383631
|
||||||
|
37393539363765336632333162623065363537613862356261666636366261313136373266623364
|
||||||
|
3338646231343632336234303436636235633363646661656339
|
||||||
19
ansible/test/test-app-post-stack.yml
Normal file
19
ansible/test/test-app-post-stack.yml
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
---
|
||||||
|
# 05 · Test runner ve deploy ön koşulları
|
||||||
|
#
|
||||||
|
# Ön koşul: Gitea arayüzünden (Organization → Settings → Actions → Runners)
|
||||||
|
# bir Registration Token alın ve group_vars/all/vault.yml içindeki
|
||||||
|
# vault_gitea_runner_token değişkenine ekleyin.
|
||||||
|
#
|
||||||
|
# ansible-playbook test-app-post-stack.yml --vault-password-file=.vault_pass
|
||||||
|
#
|
||||||
|
# Token tanımlı değilse kurulum tamamlanır ancak kayıt adımı atlanır.
|
||||||
|
# Sonraki çalıştırmada .runner dosyası varsa kayıt tekrar yapılmaz (idempotent).
|
||||||
|
|
||||||
|
- name: "App Node -Gitea runner ve deploy ön koşulları"
|
||||||
|
hosts: app
|
||||||
|
become: true
|
||||||
|
|
||||||
|
roles:
|
||||||
|
- role: act_runner
|
||||||
|
tags: [act_runner]
|
||||||
14
ansible/test/test-db-post-stack.yml
Normal file
14
ansible/test/test-db-post-stack.yml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
---
|
||||||
|
- name: DB Node - StorageBox Dizinleri ve MongoDB Konfigürasyonu
|
||||||
|
hosts: db
|
||||||
|
become: yes
|
||||||
|
roles:
|
||||||
|
- role: db_stack
|
||||||
|
tags: [db_stack]
|
||||||
|
|
||||||
|
- name: App Node - DB Stack Deploy
|
||||||
|
hosts: app
|
||||||
|
become: yes
|
||||||
|
roles:
|
||||||
|
- role: db_stack
|
||||||
|
tags: [db_stack]
|
||||||
131
facts/firewall.md
Normal file
131
facts/firewall.md
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
# Firewall Mimarisi
|
||||||
|
|
||||||
|
## Genel Bakış
|
||||||
|
|
||||||
|
Trafik filtreleme iki katmanda uygulanıyor. Bir paket sunucuya ulaşmadan önce Hetzner Cloud Firewall'dan geçmek zorunda; geçse bile sunucu içinde firewalld tarafından tekrar denetleniyor.
|
||||||
|
|
||||||
|
```
|
||||||
|
İnternet → Hetzner Cloud Firewall (Terraform) → firewalld (Ansible) → Uygulama
|
||||||
|
```
|
||||||
|
|
||||||
|
| Katman | Araç | Yönetim | Kapsam |
|
||||||
|
|--------|------|---------|--------|
|
||||||
|
| 1. Hetzner Cloud Firewall | Terraform | `terraform/hetzner/{test,prod}/firewall.tf` | Ağ seviyesi, sunucuya ulaşmadan drop |
|
||||||
|
| 2. firewalld | Ansible | `ansible/roles/hardening/tasks/main.yml` | İşletim sistemi seviyesi, default zone: drop |
|
||||||
|
|
||||||
|
Admin IP'leri her iki katmanda da aynı değişkenden besleniyor:
|
||||||
|
- **Terraform:** `var.admin_allowed_cidrs` → `terraform.tfvars`
|
||||||
|
- **Ansible:** `admin_allowed_cidrs` → `group_vars/all/vars.yml`
|
||||||
|
|
||||||
|
Mevcut admin CIDR'ları: `78.187.87.109/32`, `95.70.151.248/32`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Katman 1 — Hetzner Cloud Firewall (Terraform)
|
||||||
|
|
||||||
|
Her ortam için iki ayrı firewall tanımı var: `app` ve `db` node'larına uygulanıyor.
|
||||||
|
|
||||||
|
### Test Ortamı
|
||||||
|
|
||||||
|
Subnet'ler: app `10.10.10.0/24`, db `10.10.20.0/24`
|
||||||
|
|
||||||
|
#### App Firewall (`iklim-test-firewall-app`)
|
||||||
|
|
||||||
|
| Port | Protokol | Kaynak | Açıklama |
|
||||||
|
|------|----------|--------|----------|
|
||||||
|
| 22 | TCP | admin CIDRs | SSH |
|
||||||
|
| 80 | TCP | 0.0.0.0/0, ::/0 | HTTP public |
|
||||||
|
| 443 | TCP | 0.0.0.0/0, ::/0 | HTTPS public |
|
||||||
|
| 2377 | TCP | 10.10.10.0/24, 10.10.20.0/24 | Docker Swarm control plane |
|
||||||
|
| 7946 | TCP/UDP | 10.10.10.0/24, 10.10.20.0/24 | Docker Swarm node discovery |
|
||||||
|
| 4789 | UDP | 10.10.10.0/24, 10.10.20.0/24 | Docker Swarm VXLAN overlay |
|
||||||
|
| 8200 | TCP | 10.10.10.0/24 | Vault API |
|
||||||
|
| 6379 | TCP | 10.10.10.0/24 | Redis |
|
||||||
|
| 5672 | TCP | 10.10.10.0/24 | RabbitMQ AMQP |
|
||||||
|
| 61613 | TCP | 10.10.10.0/24 | RabbitMQ STOMP |
|
||||||
|
| 15674 | TCP | 10.10.10.0/24 | RabbitMQ Web STOMP |
|
||||||
|
| 15672 | TCP | 10.10.10.0/24 | RabbitMQ Management (SWAG üzerinden 443) |
|
||||||
|
| 9000 | TCP | 10.10.10.0/24 | APISIX Dashboard (SWAG üzerinden 443, IP kısıtlı) |
|
||||||
|
| 9180 | TCP | 10.10.10.0/24 | APISIX Admin API (sadece Docker overlay) |
|
||||||
|
| 9090 | TCP | 10.10.10.0/24 | Prometheus (SWAG üzerinden 443) |
|
||||||
|
| 3000 | TCP | 10.10.10.0/24 | Grafana (SWAG üzerinden 443, IP kısıtlı) |
|
||||||
|
|
||||||
|
#### DB Firewall (`iklim-test-firewall-db`)
|
||||||
|
|
||||||
|
| Port | Protokol | Kaynak | Açıklama |
|
||||||
|
|------|----------|--------|----------|
|
||||||
|
| 22 | TCP | admin CIDRs | SSH |
|
||||||
|
| 5432 | TCP | 10.10.10.0/24 | PostgreSQL (app'ten) |
|
||||||
|
| 27017 | TCP | 10.10.10.0/24 | MongoDB (app'ten) |
|
||||||
|
| 2377 | TCP | 10.10.10.0/24 | Docker Swarm control plane |
|
||||||
|
| 7946 | TCP/UDP | 10.10.10.0/24 | Docker Swarm node discovery |
|
||||||
|
| 4789 | UDP | 10.10.10.0/24 | Docker Swarm VXLAN overlay |
|
||||||
|
|
||||||
|
### Prod Ortamı
|
||||||
|
|
||||||
|
Subnet'ler: app `10.20.10.0/24`, db `10.20.20.0/24`
|
||||||
|
|
||||||
|
App firewall test ile aynı kurallara sahip (kaynak IP'ler prod subnet'leri).
|
||||||
|
|
||||||
|
#### DB Firewall (`iklim-prod-firewall-db`) — test'ten farklı kurallar
|
||||||
|
|
||||||
|
| Port | Protokol | Kaynak | Açıklama |
|
||||||
|
|------|----------|--------|----------|
|
||||||
|
| 5432 | TCP | 10.20.20.0/24 | PostgreSQL replikasyon (DB subnet içi) |
|
||||||
|
| 27017 | TCP | 10.20.20.0/24 | MongoDB replica set internal |
|
||||||
|
| 2379 | TCP | 10.20.20.0/24 | etcd client |
|
||||||
|
| 2380 | TCP | 10.20.20.0/24 | etcd peer |
|
||||||
|
| 8008 | TCP | 10.20.20.0/24 | Patroni REST API |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Katman 2 — firewalld (Ansible)
|
||||||
|
|
||||||
|
Tüm ortamlarda `hardening` role tarafından uygulanıyor. Default zone `drop` — listelenmeyen her trafik reddedilir.
|
||||||
|
|
||||||
|
| Port | Protokol | Kaynak | Açıklama |
|
||||||
|
|------|----------|--------|----------|
|
||||||
|
| 22 | TCP | admin CIDRs | SSH (rich rule, zone: drop) |
|
||||||
|
|
||||||
|
SSH rich rule örneği:
|
||||||
|
```
|
||||||
|
rule family="ipv4" source address="78.187.87.109/32" service name="ssh" accept
|
||||||
|
```
|
||||||
|
|
||||||
|
### SSH Sertleştirme (sshd_config)
|
||||||
|
|
||||||
|
| Parametre | Değer | Açıklama |
|
||||||
|
|-----------|-------|----------|
|
||||||
|
| PasswordAuthentication | no | Sadece key ile giriş |
|
||||||
|
| PermitRootLogin | prohibit-password | Root key ile girebilir, şifre ile giremez |
|
||||||
|
| PermitEmptyPasswords | no | Boş şifre yasak |
|
||||||
|
| MaxAuthTries | 3 | 3 başarısız denemede bağlantı kesilir |
|
||||||
|
|
||||||
|
> **Not:** `MaxAuthTries 3` ssh-agent'ta birden fazla key varken "Too many authentication failures" hatasına yol açar. `~/.ssh/config`'de `IdentitiesOnly yes` ile doğru key'i belirtmek gerekir.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kural Güncelleme Rehberi
|
||||||
|
|
||||||
|
### Admin IP değiştiğinde
|
||||||
|
|
||||||
|
İki dosyayı güncelle:
|
||||||
|
|
||||||
|
```
|
||||||
|
terraform/hetzner/test/terraform.tfvars → admin_allowed_cidrs
|
||||||
|
ansible/test/group_vars/all/vars.yml → admin_allowed_cidrs
|
||||||
|
```
|
||||||
|
|
||||||
|
Sonra uygula:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Terraform
|
||||||
|
cd terraform/hetzner/test && terraform apply
|
||||||
|
|
||||||
|
# Ansible
|
||||||
|
cd ansible/test && ansible-playbook test-bootstrap.yml --tags hardening
|
||||||
|
```
|
||||||
|
|
||||||
|
### Yeni port açılacaksa
|
||||||
|
|
||||||
|
Hetzner seviyesinde `firewall.tf`'e kural ekle, Terraform ile uygula. Sunucu içinde firewalld'da açmak gerekiyorsa hardening role'una da ekle.
|
||||||
76
facts/swarm-node-recovery.md
Normal file
76
facts/swarm-node-recovery.md
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
# Docker Swarm — Node Recovery
|
||||||
|
|
||||||
|
Test ortamında tek manager (`iklim-app-01`) ve tek worker (`iklim-db-01`) bulunur. Hangi node'un yeniden kurulduğuna göre recovery süreci farklılaşır.
|
||||||
|
|
||||||
|
## Senaryo 1: `iklim-app-01` (Manager) Yeniden Kurulur
|
||||||
|
|
||||||
|
### Sorun
|
||||||
|
|
||||||
|
Yeni `iklim-app-01` üzerinde `docker swarm init` farklı cluster ID ile yeni bir küme başlatır. `iklim-db-01` hâlâ eski kümeye bağlıdır. Ansible `swarm` role'u `iklim-db-01`'de Swarm'ı `active` görür, join denemez. İki node iki ayrı kümede kalır.
|
||||||
|
|
||||||
|
### Çözüm
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. iklim-db-01 üzerinde — eski kümeden çık
|
||||||
|
docker swarm leave --force
|
||||||
|
|
||||||
|
# 2. Ansible ile her iki node'u yeniden kur
|
||||||
|
cd ansible/test
|
||||||
|
ansible-playbook -i inventory/generated/test.yml test-bootstrap.yml --ask-vault-pass
|
||||||
|
|
||||||
|
# 3. DB stack'i yeniden deploy et
|
||||||
|
ansible-playbook -i inventory/generated/test.yml test-db-post-stack.yml --ask-vault-pass
|
||||||
|
```
|
||||||
|
|
||||||
|
DB verileri `iklim-db-01`'deki named volume'larda korunur, kayıp yaşanmaz.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Senaryo 2: `iklim-db-01` (Worker) Yeniden Kurulur
|
||||||
|
|
||||||
|
### Durum
|
||||||
|
|
||||||
|
Yeni `iklim-db-01` Swarm'dan habersiz başlar (`inactive`). Manager (`iklim-app-01`) eski dead node kaydını tutar.
|
||||||
|
|
||||||
|
### Çözüm
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Ansible bootstrap — yeni node otomatik join olur
|
||||||
|
cd ansible/test
|
||||||
|
ansible-playbook -i inventory/generated/test.yml test-bootstrap.yml --ask-vault-pass
|
||||||
|
|
||||||
|
# 2. iklim-app-01 üzerinde — eski dead node kaydını temizle
|
||||||
|
docker node ls # eski node ID'yi bul
|
||||||
|
docker node rm <eski-node-id>
|
||||||
|
|
||||||
|
# 3. DB stack'i yeniden deploy et (backup'tan restore sonrası)
|
||||||
|
ansible-playbook -i inventory/generated/test.yml test-db-post-stack.yml --ask-vault-pass
|
||||||
|
```
|
||||||
|
|
||||||
|
Ansible `swarm` role'u `inactive` durumu gördüğü için token alıp join eder, `role=db` label'ını uygular. DB servisleri placement constraint sayesinde yeni node'a schedule edilir.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Senaryo 3: Her İki Node Yeniden Kurulur
|
||||||
|
|
||||||
|
Her şey sıfırdan kurulur, Swarm uyumsuzluğu yaşanmaz.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ansible/test
|
||||||
|
ansible-playbook -i inventory/generated/test.yml test-bootstrap.yml --ask-vault-pass
|
||||||
|
ansible-playbook -i inventory/generated/test.yml test-db-post-stack.yml --ask-vault-pass
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Özet
|
||||||
|
|
||||||
|
| Senaryo | Manuel Adım | Ansible Yeterli mi? |
|
||||||
|
|---|---|---|
|
||||||
|
| Manager (`iklim-app-01`) ölür | `docker swarm leave --force` (worker'da) | Sonrasında evet |
|
||||||
|
| Worker (`iklim-db-01`) ölür | `docker node rm <id>` (manager'da) | Büyük ölçüde evet |
|
||||||
|
| Her ikisi ölür | Yok | Evet |
|
||||||
|
|
||||||
|
## Neden Prod'da Bu Sorun Yok
|
||||||
|
|
||||||
|
Prod ortamında birden fazla manager node (en az 3) çalıştırılır. Tek manager düşse diğerleri liderliği devralır, küme sağlıklı kalmaya devam eder.
|
||||||
@ -4,18 +4,18 @@ Bu aşamanın amacı `iklim-db-01` node'unu Swarm'a worker olarak eklemek ve Pos
|
|||||||
|
|
||||||
## Mimari Karar
|
## Mimari Karar
|
||||||
|
|
||||||
Yol haritasında DB'lerin "manuel" kurulacağı belirtilmiştir. Test ortamında bu "manuel" süreç, DB'lerin işletim sistemine doğrudan kurulması yerine, **Swarm Worker** üzerinde Docker konteynerleri olarak ayağa kaldırılması şeklinde uygulanacaktır.
|
Yol haritasında DB'lerin "manuel" kurulacağı belirtilmiştir. Test ortamında bu "manuel" süreç, DB'lerin işletim sistemine doğrudan kurulması yerine, **Swarm Worker** üzerinde Docker konteynerleri olarak ayağa kaldırılması şeklinde uygulanacaktır. Kurulum **Ansible** ile otomatize edilmiştir (`test-db-post-stack.yml`).
|
||||||
|
|
||||||
**Neden?**
|
**Neden?**
|
||||||
1. **Yönetim Kolaylığı:** Docker ile versiyon geçişleri ve konfigürasyon yönetimi çok daha hızlıdır.
|
1. **Yönetim Kolaylığı:** Docker ile versiyon geçişleri ve konfigürasyon yönetimi çok daha hızlıdır.
|
||||||
2. **Overlay Network:** Uygulama servisleri (`iklim-app-01`), DB'lere `iklimco-net` overlay network üzerinden şifreli ve izole bir şekilde erişebilir.
|
2. **Overlay Network:** Uygulama servisleri (`iklim-app-01`), DB'lere `iklimco-net` overlay network üzerinden şifreli ve izole bir şekilde erişebilir.
|
||||||
3. **Veri Kalıcılığı:** Veriler Hetzner StorageBox (`/mnt/storagebox`) üzerinde saklanarak host bağımsızlığı sağlanır.
|
3. **Veri Kalıcılığı:** Veriler `iklim-db-01` üzerindeki Docker named volume'larında saklanır. StorageBox yalnızca backup için kullanılır.
|
||||||
|
|
||||||
## Ön Koşullar
|
## Ön Koşullar
|
||||||
|
|
||||||
- `03-test-ansible-bootstrap.md` her iki node'da tamamlanmış olmalı.
|
- `03-test-ansible-bootstrap.md` her iki node'da tamamlanmış olmalı.
|
||||||
- StorageBox `/mnt/storagebox` olarak her iki node'da mount edilmiş olmalı.
|
|
||||||
- Docker `iklim-db-01` üzerinde kurulu olmalı (Bootstrap role bunu yapar).
|
- Docker `iklim-db-01` üzerinde kurulu olmalı (Bootstrap role bunu yapar).
|
||||||
|
- Ansible vault'unda `vault_postgres_root_user`, `vault_postgres_password`, `vault_mongo_root_user`, `vault_mongo_root_password` tanımlı olmalı.
|
||||||
|
|
||||||
## 1. Firewall Güncellemesi
|
## 1. Firewall Güncellemesi
|
||||||
|
|
||||||
@ -34,109 +34,54 @@ cd terraform/hetzner/test
|
|||||||
terraform apply
|
terraform apply
|
||||||
```
|
```
|
||||||
|
|
||||||
## 2. DB Node'u Swarm'a Ekleme
|
## 2. Vault Güncellemesi
|
||||||
|
|
||||||
**iklim-app-01 üzerinde (Manager)** join token alın:
|
|
||||||
```bash
|
```bash
|
||||||
docker swarm join-token worker
|
cd ansible/test
|
||||||
|
ansible-vault edit group_vars/all/vault.yml
|
||||||
```
|
```
|
||||||
|
|
||||||
**iklim-db-01 üzerinde (Worker)** Swarm'a katılın:
|
Şu değişkenleri ekle:
|
||||||
```bash
|
|
||||||
docker swarm join --token <TOKEN> 10.10.10.11:2377
|
|
||||||
```
|
|
||||||
|
|
||||||
**iklim-app-01 üzerinde** node'u etiketleyin:
|
|
||||||
```bash
|
|
||||||
docker node update --label-add role=db iklim-db-01
|
|
||||||
```
|
|
||||||
|
|
||||||
## 3. StorageBox Dizin Yapısı
|
|
||||||
|
|
||||||
**iklim-db-01 üzerinde:**
|
|
||||||
```bash
|
|
||||||
mkdir -p /mnt/storagebox/test/db/postgresql/data
|
|
||||||
mkdir -p /mnt/storagebox/test/db/mongodb/data
|
|
||||||
mkdir -p /mnt/storagebox/test/db/mongodb/log
|
|
||||||
mkdir -p /mnt/storagebox/test/db/mongodb/config
|
|
||||||
```
|
|
||||||
|
|
||||||
## 4. Veritabanı Konfigürasyonları
|
|
||||||
|
|
||||||
### MongoDB Config (`mongod.conf`)
|
|
||||||
`/mnt/storagebox/test/db/mongodb/config/mongod.conf` dosyasını oluşturun:
|
|
||||||
```yaml
|
```yaml
|
||||||
storage:
|
vault_postgres_root_user: "postgres"
|
||||||
dbPath: /data/db
|
vault_postgres_password: "GÜÇLÜ_ŞİFRE"
|
||||||
journal:
|
vault_mongo_root_user: "mongoadmin"
|
||||||
enabled: true
|
vault_mongo_root_password: "GÜÇLÜ_ŞİFRE"
|
||||||
systemLog:
|
|
||||||
destination: file
|
|
||||||
logAppend: true
|
|
||||||
path: /data/log/mongod.log
|
|
||||||
net:
|
|
||||||
port: 27017
|
|
||||||
bindIp: 0.0.0.0
|
|
||||||
security:
|
|
||||||
authorization: enabled
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## 5. DB Stack Kurulumu
|
## 3. Ansible ile Kurulum
|
||||||
|
|
||||||
`/opt/iklimco/stacks/db.yml` (iklim-app-01 üzerinde):
|
|
||||||
```yaml
|
|
||||||
version: "3.8"
|
|
||||||
|
|
||||||
networks:
|
|
||||||
iklimco-net:
|
|
||||||
external: true
|
|
||||||
|
|
||||||
services:
|
|
||||||
postgresql:
|
|
||||||
image: postgis/postgis:17-3.5
|
|
||||||
environment:
|
|
||||||
POSTGRES_USER: "${DATABASE_POSTGRES_ROOT_USER}"
|
|
||||||
POSTGRES_PASSWORD: "${POSTGRES_PASSWORD}"
|
|
||||||
POSTGRES_DB: postgres
|
|
||||||
PGDATA: /var/lib/postgresql/data/pgdata
|
|
||||||
volumes:
|
|
||||||
- /mnt/storagebox/test/db/postgresql/data:/var/lib/postgresql/data
|
|
||||||
networks:
|
|
||||||
- iklimco-net
|
|
||||||
deploy:
|
|
||||||
placement:
|
|
||||||
constraints:
|
|
||||||
- node.labels.role == db
|
|
||||||
|
|
||||||
mongodb:
|
|
||||||
image: mongo:8
|
|
||||||
environment:
|
|
||||||
MONGO_INITDB_ROOT_USERNAME: "${DATABASE_MONGO_ROOT_USER}"
|
|
||||||
MONGO_INITDB_ROOT_PASSWORD: "${MONGO_ROOT_PASSWORD}"
|
|
||||||
volumes:
|
|
||||||
- /mnt/storagebox/test/db/mongodb/data:/data/db
|
|
||||||
- /mnt/storagebox/test/db/mongodb/log:/data/log
|
|
||||||
- /mnt/storagebox/test/db/mongodb/config/mongod.conf:/etc/mongod.conf
|
|
||||||
command: ["--config", "/etc/mongod.conf"]
|
|
||||||
networks:
|
|
||||||
- iklimco-net
|
|
||||||
deploy:
|
|
||||||
placement:
|
|
||||||
constraints:
|
|
||||||
- node.labels.role == db
|
|
||||||
```
|
|
||||||
|
|
||||||
### Deploy
|
|
||||||
```bash
|
```bash
|
||||||
# .env dosyasını oluşturun (Hassas veriler için)
|
cd ansible/test
|
||||||
# DATABASE_POSTGRES_ROOT_USER, POSTGRES_PASSWORD, DATABASE_MONGO_ROOT_USER, MONGO_ROOT_PASSWORD
|
ansible-playbook -i inventory/generated/test.yml test-db-post-stack.yml --ask-vault-pass
|
||||||
|
|
||||||
docker stack deploy -c /opt/iklimco/stacks/db.yml iklim-db
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## 6. Kabul Kriterleri
|
**Playbook ne yapar?**
|
||||||
|
|
||||||
|
`iklim-db-01` üzerinde:
|
||||||
|
- `/opt/iklimco/db/mongodb/config/` dizinini oluşturur
|
||||||
|
- `mongod.conf` dosyasını yerleştirir
|
||||||
|
|
||||||
|
`iklim-app-01` üzerinde:
|
||||||
|
- `/opt/iklimco/stacks/db.yml` stack dosyasını oluşturur (şifreler vault'tan enjekte edilir)
|
||||||
|
- `docker stack deploy` ile PostgreSQL ve MongoDB servislerini başlatır
|
||||||
|
|
||||||
|
## 4. Volume ve Veri Yapısı
|
||||||
|
|
||||||
|
DB verileri `iklim-db-01` üzerindeki Docker named volume'larında tutulur:
|
||||||
|
|
||||||
|
| Volume | İçerik |
|
||||||
|
|---|---|
|
||||||
|
| `iklim-db_postgresql_data` | PostgreSQL veri dosyaları |
|
||||||
|
| `iklim-db_mongodb_data` | MongoDB veri dosyaları |
|
||||||
|
|
||||||
|
MongoDB log'ları stdout'a yazılır (`docker logs` ile izlenir). Konfigürasyon: `/opt/iklimco/db/mongodb/config/mongod.conf`
|
||||||
|
|
||||||
|
> StorageBox DB verisi için **kullanılmaz**. Yalnızca backup stratejisinde görev alır.
|
||||||
|
|
||||||
|
## 5. Kabul Kriterleri
|
||||||
|
|
||||||
- `docker node ls` komutunda `iklim-db-01` Ready ve Active görünür.
|
- `docker node ls` komutunda `iklim-db-01` Ready ve Active görünür.
|
||||||
- `docker stack services iklim-db` her iki servisi 1/1 replica ile gösterir.
|
- `docker stack services iklim-db` her iki servisi 1/1 replica ile gösterir.
|
||||||
- Uygulama node'undan `iklim-db_postgresql` ve `iklim-db_mongodb` DNS isimleriyle erişim sağlanır.
|
- Uygulama node'undan `iklim-db_postgresql` ve `iklim-db_mongodb` DNS isimleriyle erişim sağlanır.
|
||||||
- Reboot sonrası veriler `/mnt/storagebox` üzerinden korunur.
|
- Reboot sonrası veriler named volume'lardan korunur (`docker volume ls` ile kontrol).
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user