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
|
||||
|
||||
*.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:
|
||||
- 🧱 Terraform resources for Hetzner infrastructure (`test` and `prod`)
|
||||
- 🤖 Ansible bootstrap playbooks, shared roles, and inventory targets
|
||||
- 📚 End-to-end setup guides and roadmap documents (mostly Turkish)
|
||||
- 📊 Sizing/cost analysis and supporting reference assets
|
||||
Bu depo şunları kapsar:
|
||||
- 🧱 Hetzner altyapısı için Terraform kaynakları (`test` ve `prod`)
|
||||
- 🤖 Ansible bootstrap playbook'ları, paylaşımlı roller ve envanter hedefleri
|
||||
- 📚 Uçtan uca kurulum rehberleri ve yol haritası dokümanları
|
||||
- 📊 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)
|
||||
- 🤖 **Ansible**: prepares OS, security hardening, Docker/Swarm, runner setup, and StorageBox mount workflows via in-repo playbooks and shared roles
|
||||
- 🚀 **Application/stack deployment**: handled in related deployment workflows and stack manifests referenced by roadmap docs
|
||||
- 🧱 **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**: 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
|
||||
- 🚀 **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/prod`
|
||||
- 🤖 Ansible automation assets for both environments:
|
||||
- 🤖 Her iki ortam için Ansible otomasyon varlıkları:
|
||||
- `ansible/test/test-bootstrap.yml`
|
||||
- `ansible/prod/prod-bootstrap.yml`
|
||||
- `ansible/roles/*`
|
||||
- `ansible/test/group_vars/*` and `ansible/prod/group_vars/*`
|
||||
- 📦 Inventory artifacts and output targets:
|
||||
- `ansible/test/inventory/generated/test.yml` (tracked sample)
|
||||
- `ansible/prod/inventory/generated/prod.yml` (expected output path)
|
||||
- 📘 Detailed setup phases:
|
||||
- `setup/00-genel-yol-haritasi.md` through `setup/09-prod-runner-ha-ve-swarm.md`
|
||||
- 🛣️ Environment roadmap steps:
|
||||
- `ansible/test/group_vars/*` ve `ansible/prod/group_vars/*`
|
||||
- 📦 Envanter çıktıları ve hedef yollar:
|
||||
- `ansible/test/inventory/generated/test.yml` (takip edilen örnek)
|
||||
- `ansible/prod/inventory/generated/prod.yml` (beklenen çıktı yolu)
|
||||
- 📘 Detaylı kurulum aşamaları:
|
||||
- `setup/00-genel-yol-haritasi.md` — `setup/09-prod-runner-ha-ve-swarm.md`
|
||||
- 🛣️ Ortam yol haritası adımları:
|
||||
- `roadmap/test-env/*`
|
||||
- `roadmap/prod-env/*`
|
||||
- 📈 Capacity planning and reference charts:
|
||||
- 📈 Kapasite planlama ve referans grafikler:
|
||||
- `hetzner-sizing-report.md`
|
||||
- `test-app-graphs.png`
|
||||
- `test-db-graphs.png`
|
||||
|
||||
## 🧭 Target Environment Topology
|
||||
## 🧭 Hedef Ortam Topolojisi
|
||||
|
||||
### 🧪 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-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
|
||||
|
||||
| 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-03` | Swarm manager + app worker + runner | `10.20.10.13` | `cpx42` |
|
||||
| `iklim-db-01` | DB cluster node | `10.20.20.11` | `cpx32` |
|
||||
| `iklim-db-02` | DB cluster node | `10.20.20.12` | `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.
|
||||
- Public ingress is limited to:
|
||||
- `22/tcp` (admin CIDRs only)
|
||||
- Test ve prod, ayrı Hetzner Cloud proje ve token'larıyla birbirinden yalıtılmıştır.
|
||||
- Kamuya açık gelen trafik şunlarla sınırlıdır:
|
||||
- `22/tcp` (yalnızca admin CIDR'ları)
|
||||
- `80/tcp`
|
||||
- `443/tcp`
|
||||
- Critical services remain private-only (for example Vault `8200`, PostgreSQL `5432`, MongoDB `27017`, internal observability and broker ports).
|
||||
- Placement groups are used for host-spread strategy.
|
||||
- `prevent_destroy = true` is enabled on server resources to reduce accidental deletion risk.
|
||||
- Terraform state and secret files must not be committed.
|
||||
- Kritik servisler yalnızca private ağda erişilebilir (örneğin Vault `8200`, PostgreSQL `5432`, MongoDB `27017`, iç gözlemlenebilirlik ve broker portları).
|
||||
- Host dağılımı stratejisi için placement group'lar kullanılmaktadır.
|
||||
- Sunucu kaynaklarında yanlışlıkla silinmeye karşı `prevent_destroy = true` etkinleştirilmiştir.
|
||||
- Terraform state ve gizli dosyalar commit'lenmemelidir.
|
||||
|
||||
See:
|
||||
- `setup/01-private-network-port-matrisi.md`
|
||||
Ayrıca bkz.:
|
||||
- [[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/prod/firewall.tf`
|
||||
|
||||
## 🗂️ Repository Structure
|
||||
## 🗂️ Depo Yapısı
|
||||
|
||||
```text
|
||||
Environment_Infrastructure/
|
||||
@ -123,35 +124,37 @@ Environment_Infrastructure/
|
||||
│ └── hetzner/
|
||||
│ ├── test/
|
||||
│ └── prod/
|
||||
├── facts/
|
||||
│ └── firewall.md
|
||||
├── hetzner-sizing-report.md
|
||||
├── setup-vs-roadmap-map.md
|
||||
├── test-app-graphs.png
|
||||
└── test-db-graphs.png
|
||||
```
|
||||
|
||||
## ✅ Prerequisites
|
||||
## ✅ Ön Koşullar
|
||||
|
||||
- Terraform `>= 1.6`
|
||||
- Hetzner Cloud account(s) and API token per environment
|
||||
- SSH key pair (public key path used in Terraform variables)
|
||||
- Linux/macOS shell tools (`bash`, `cp`, `sed` or editor of your choice)
|
||||
- Optional but expected in later phases: Ansible, Docker, access to Gitea/Harbor/StorageBox
|
||||
- Hetzner Cloud hesabı ve ortam başına API token
|
||||
- SSH anahtar çifti (public key yolu Terraform değişkenlerinde kullanılır)
|
||||
- Linux/macOS kabuk araçları (`bash`, `cp`, `sed` veya tercih edilen metin editörü)
|
||||
- İlerleyen aşamalarda gerekli: Ansible, Docker, Gitea/Harbor/StorageBox erişimi
|
||||
|
||||
## 🛠️ Terraform Usage
|
||||
## 🛠️ Terraform Kullanımı
|
||||
|
||||
### 1) 🧪 Test Infrastructure
|
||||
### 1) 🧪 Test Altyapısı
|
||||
|
||||
```bash
|
||||
cd terraform/hetzner/test
|
||||
cp terraform.tfvars.example terraform.tfvars
|
||||
```
|
||||
|
||||
Edit `terraform.tfvars` values:
|
||||
`terraform.tfvars` değerlerini düzenle:
|
||||
- `hcloud_token`
|
||||
- `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
|
||||
terraform init
|
||||
@ -161,19 +164,19 @@ mkdir -p ../../../ansible/test/inventory/generated
|
||||
terraform output -raw ansible_inventory_yaml > ../../../ansible/test/inventory/generated/test.yml
|
||||
```
|
||||
|
||||
### 2) 🏭 Production Infrastructure
|
||||
### 2) 🏭 Production Altyapısı
|
||||
|
||||
```bash
|
||||
cd terraform/hetzner/prod
|
||||
cp terraform.tfvars.example terraform.tfvars
|
||||
```
|
||||
|
||||
Edit `terraform.tfvars` values:
|
||||
`terraform.tfvars` değerlerini düzenle:
|
||||
- `hcloud_token` (prod token)
|
||||
- `admin_allowed_cidrs`
|
||||
- optional overrides
|
||||
- isteğe bağlı geçersiz kılmalar
|
||||
|
||||
Then run:
|
||||
Ardından çalıştır:
|
||||
|
||||
```bash
|
||||
terraform init
|
||||
@ -183,79 +186,79 @@ mkdir -p ../../../ansible/prod/inventory/generated
|
||||
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
|
||||
2. `setup/01-private-network-port-matrisi.md` — private/public port policy
|
||||
3. `setup/02-test-terraform-iaac.md` — test Terraform phase
|
||||
4. `setup/03-test-ansible-bootstrap.md` — test OS/bootstrap/hardening
|
||||
5. `setup/04-test-db-docker-kurulum.md` — test DB stack setup on Swarm
|
||||
6. `setup/05-test-runner-ve-deploy-onkosullari.md` — test runner and deploy prerequisites
|
||||
7. `setup/06-prod-terraform-iaac.md` — prod Terraform phase
|
||||
8. `setup/07-prod-ansible-bootstrap.md` — prod OS/bootstrap/hardening
|
||||
1. `setup/00-genel-yol-haritasi.md` — genel kararlar ve sınırlar
|
||||
2. `setup/01-private-network-port-matrisi.md` — private/public port politikası
|
||||
3. `setup/02-test-terraform-iaac.md` — test Terraform aşaması
|
||||
4. `setup/03-test-ansible-bootstrap.md` — test OS/bootstrap/sertleştirme
|
||||
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 ve deploy ön koşulları
|
||||
7. `setup/06-prod-terraform-iaac.md` — prod Terraform aşaması
|
||||
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)
|
||||
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/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)
|
||||
- **Prod:** `3 x cpx42` (app) + `3 x cpx32` (db)
|
||||
|
||||
Approximate monthly total in the report:
|
||||
Rapordaki yaklaşık aylık toplam:
|
||||
- Test: `$59.98`
|
||||
- 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/`
|
||||
- private keys, certificates, `.env` secrets
|
||||
- runner tokens and vault password files
|
||||
- private key'ler, sertifikalar, `.env` gizli bilgileri
|
||||
- runner token'ları ve vault parola dosyaları
|
||||
|
||||
See `.gitignore` for enforced patterns.
|
||||
Zorunlu kalıplar için `.gitignore` dosyasına bkz.
|
||||
|
||||
Recommended:
|
||||
- keep runtime secrets in secure secret stores / encrypted vault files
|
||||
- keep generated runtime artifacts outside version control unless explicitly sanitized
|
||||
Önerilen:
|
||||
- çalışma zamanı gizli bilgilerini güvenli gizli depolarda / şifreli vault dosyalarında tut
|
||||
- ü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.
|
||||
- Some roadmap steps target files under the broader `iklim.co` application repository, not this repository alone.
|
||||
- `ansible/prod/inventory/generated/prod.yml` beklenen bir çıktı yoludur; üretilene kadar mevcut olmayabilir.
|
||||
- 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
|
||||
- floating IP exists and is attached
|
||||
- firewalls expose only intended public ports
|
||||
- placement groups are assigned
|
||||
- generated inventory YAML is exported to `ansible/{test,prod}/inventory/generated/*.yml`
|
||||
- sunucular beklenen isimler ve private IP'lerle oluşturulmuş
|
||||
- floating IP mevcut ve bağlı
|
||||
- firewall'lar yalnızca amaçlanan public portları açıyor
|
||||
- placement group'lar atanmış
|
||||
- ü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
|
||||
- DB accessibility is private-only
|
||||
- Vault/API gateways follow public/private exposure rules
|
||||
- runner and deploy lock behavior align with environment policy
|
||||
- Swarm durumu ve etiketleri dökümantasyonla eşleşiyor
|
||||
- DB erişimi yalnızca private ağdan mümkün
|
||||
- Vault/API gateway'leri public/private erişim kurallarına uyuyor
|
||||
- Runner ve deploy kilit davranışı ortam politikasıyla örtüşüyor
|
||||
|
||||
## 🔗 References
|
||||
## 🔗 Referanslar
|
||||
|
||||
- Hetzner Terraform Provider: https://registry.terraform.io/providers/hetznercloud/hcloud/latest
|
||||
- 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
|
||||
notify: Restart fail2ban
|
||||
|
||||
- name: Ensure fail2ban is running and enabled
|
||||
ansible.builtin.service:
|
||||
name: fail2ban
|
||||
state: started
|
||||
enabled: yes
|
||||
|
||||
- name: Ensure firewalld is running
|
||||
ansible.builtin.service:
|
||||
name: firewalld
|
||||
@ -67,6 +73,12 @@
|
||||
create_home: yes
|
||||
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
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/systemd/journald.conf
|
||||
|
||||
@ -6,4 +6,13 @@ storagebox_password: "{{ vault_storagebox_password }}"
|
||||
iklim_password: "{{ vault_iklim_password }}"
|
||||
swarm_manager_ip: "10.10.10.11"
|
||||
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"
|
||||
|
||||
# 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
|
||||
32653536356331386232373033363738363336323461363432653031666166343462393737643730
|
||||
3162386266326333386533373630663563386337613338310a376137623835333461363662323035
|
||||
65636332376331643335323265336439613331613238393363626330313831653233373864313033
|
||||
3430303335306366660a636139623264386437383763316665373230643939653039633330623834
|
||||
64636564313232626462373638653538393261323031616563653164323961393664656439393639
|
||||
37313335313739353564626364313663363038316132633739623338343436303337643162396635
|
||||
34323838346664303464396438393534636265636262323364643364323163653464303931626130
|
||||
37663138363966386530323133613661316230303362323937313132306236323339323839633139
|
||||
34633733333531373233386436313837343364326334386535626262356537376137646163326666
|
||||
38306238666639623639393137623266363465313264326566663839303664303233666335663731
|
||||
32633232376164383265313835326433366134613230613164373034663931396161623631666236
|
||||
37613631353233346464363236383539663461333739396432626638323134383230343163396335
|
||||
64363333396130326463316538306162363034353936383063333531396233356437333064613230
|
||||
63353337306632323364336233313836663365623436336532623239633434656563666637333636
|
||||
31343836353230306461613936383766636138663361343864623466376235666536306133306435
|
||||
65666338333465653434386166366633383539323566613935363434363735313231336166626364
|
||||
65353033363366386432306434333135653862616635373837376233326262646330326363626134
|
||||
32343735386137363334306464383935613531373533363330363635633236313930373865393738
|
||||
38363564663066363439396532656236656636646365363038393535303632356364613538353737
|
||||
32636434383766343765643634633464353262396466393265643963383634323730343162323837
|
||||
39343139613538653531616466303638336133396165646138663463383238616431613563343031
|
||||
39333139643033326630343630366630633766383861353663353534633436646363356334626438
|
||||
62306661376339343437643732333032373362633062326365666430616634613537316635653465
|
||||
64306362386339333562
|
||||
63323534653836623136643065383166323661663339653335373139663436316433396137343739
|
||||
3039383336313861616236336565323664613333383262610a363436376132316437656239633334
|
||||
63633863643938373537333562346433313766393732616362306132313430333964373031313962
|
||||
3230393837316434650a323933313934316334633931323165633730373933326564316661666332
|
||||
36323735323736656662366463383431393433643331616134623662663333313364343232653138
|
||||
61316165636431663230376234626532663431373632393731383434386435353638363365323861
|
||||
33373462333966663033666463303032343961653533343932363462623637616232666561646335
|
||||
36623039353633343035353765326339616233666562636438636137303835643736386633623139
|
||||
66656137646461363165313937306266393035383339363233303066396564346638643539313361
|
||||
38653930393766656634343334373961323031333938663636623138666661346133316631393231
|
||||
36393237313439313435363866333364343231613330373439626462356139303061313632343338
|
||||
38633364343663333139396431663938653263633739383036613935373332653666656633323331
|
||||
37316535386139633263633266353739386164666564666136643665353135356231323633373363
|
||||
36646464383766663532353132326162363734366337373537656132366139386362616438616531
|
||||
34386234306231376162643934643565343364336530616562303739363935353636343633376464
|
||||
34333835363666303236313363663665653566326365386439653362663462343136316664613036
|
||||
37616163653561633030376534393533653466373839633661653338313166383332613234666164
|
||||
37343737316139393930313739366562643539326233366334353566633339333130366263663030
|
||||
63393437383566393932353230396534383330646364646561323631653338396132303461613636
|
||||
37306533663732626532393130323933633365336233613334666330343436326137306666636234
|
||||
30623831303632613866333734306337623230373433373332646534306135333039343231643536
|
||||
30356238323263653236326662303365343464356264376565326432323335323862366365666561
|
||||
32316633396430376234636661623464316135333862623531393661343332303033323636393736
|
||||
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
|
||||
|
||||
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?**
|
||||
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.
|
||||
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
|
||||
|
||||
- `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).
|
||||
- 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
|
||||
|
||||
@ -34,109 +34,54 @@ cd terraform/hetzner/test
|
||||
terraform apply
|
||||
```
|
||||
|
||||
## 2. DB Node'u Swarm'a Ekleme
|
||||
## 2. Vault Güncellemesi
|
||||
|
||||
**iklim-app-01 üzerinde (Manager)** join token alın:
|
||||
```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:
|
||||
```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:
|
||||
Şu değişkenleri ekle:
|
||||
```yaml
|
||||
storage:
|
||||
dbPath: /data/db
|
||||
journal:
|
||||
enabled: true
|
||||
systemLog:
|
||||
destination: file
|
||||
logAppend: true
|
||||
path: /data/log/mongod.log
|
||||
net:
|
||||
port: 27017
|
||||
bindIp: 0.0.0.0
|
||||
security:
|
||||
authorization: enabled
|
||||
vault_postgres_root_user: "postgres"
|
||||
vault_postgres_password: "GÜÇLÜ_ŞİFRE"
|
||||
vault_mongo_root_user: "mongoadmin"
|
||||
vault_mongo_root_password: "GÜÇLÜ_ŞİFRE"
|
||||
```
|
||||
|
||||
## 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
|
||||
# .env dosyasını oluşturun (Hassas veriler için)
|
||||
# DATABASE_POSTGRES_ROOT_USER, POSTGRES_PASSWORD, DATABASE_MONGO_ROOT_USER, MONGO_ROOT_PASSWORD
|
||||
|
||||
docker stack deploy -c /opt/iklimco/stacks/db.yml iklim-db
|
||||
cd ansible/test
|
||||
ansible-playbook -i inventory/generated/test.yml test-db-post-stack.yml --ask-vault-pass
|
||||
```
|
||||
|
||||
## 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 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.
|
||||
- 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