Restructure setup documentation and refine environment bootstrapping

This commit introduces a reordered and renumbered set of setup documentation files to better reflect the deployment stages for both test and production environments.

Key changes include:
*   A new `setup-vs-roadmap-map.md` file to provide a clear mapping between roadmap tasks and their corresponding setup phases.
*   Significantly expanded Ansible bootstrap documentation for both test and production, detailing Docker, Swarm, security hardening, and StorageBox SSH key management roles.
*   Formalized database Docker and Swarm cluster setup instructions for test and production, including explicit steps for Swarm worker integration of DB nodes.
*   Updated roadmap documentation (`roadmap/prod-env/*`) to align with the refined setup, incorporating correct private IP addresses for Swarm joins, new node labels, and floating IP usage for GoDaddy DNS records.
This commit is contained in:
Murat ÖZDEMİR 2026-05-11 17:47:30 +03:00
parent 42dfe76487
commit bf8f011e43
12 changed files with 606 additions and 567 deletions

View File

@ -46,7 +46,7 @@ Save this token — needed on iklim-app-02 and iklim-app-03.
SSH into iklim-app-02 and iklim-app-03, run: SSH into iklim-app-02 and iklim-app-03, run:
```bash ```bash
docker swarm join --token <MANAGER_TOKEN> 10.10.10.11:2377 docker swarm join --token <MANAGER_TOKEN> 10.20.10.11:2377
``` ```
## Step 4 — Label app nodes ## Step 4 — Label app nodes
@ -70,7 +70,7 @@ docker swarm join-token worker
SSH into each DB node and join: SSH into each DB node and join:
```bash ```bash
docker swarm join --token <WORKER_TOKEN> 10.10.10.11:2377 docker swarm join --token <WORKER_TOKEN> 10.20.10.11:2377
``` ```
Then label them on iklim-app-01: Then label them on iklim-app-01:
@ -98,7 +98,7 @@ docker node inspect iklim-app-01 --format '{{.Spec.Labels}}'
docker node inspect iklim-db-01 --format '{{.Spec.Labels}}' docker node inspect iklim-db-01 --format '{{.Spec.Labels}}'
``` ```
Expected: `map[role:service]` for app nodes, `map[role:db]` for DB nodes. Expected: `map[type:service]` for app nodes, `map[role:db]` for DB nodes.
## Step 7 — Confirm `init/swarm-init.sh` multi-node awareness ## Step 7 — Confirm `init/swarm-init.sh` multi-node awareness

View File

@ -42,20 +42,18 @@ chmod 600 /opt/iklimco/swag/dns-conf/godaddy.ini
## Step 4 — GoDaddy A records for prod subdomains ## Step 4 — GoDaddy A records for prod subdomains
In GoDaddy DNS panel for `iklim.co`, add/update A records pointing to iklim-app-01's public IP: In GoDaddy DNS panel for `iklim.co`, add/update A records pointing to the **Floating IP** (`iklim-prod-app-fip`).
Floating IP değerini almak için: `terraform output prod_floating_ip`
| Record | Value | | Record | Value |
|--------|-------| |--------|-------|
| `api` | `<iklim-app-01-public-ip>` | | `api` | `<iklim-prod-app-fip>` |
| `apigw` | `<iklim-app-01-public-ip>` | | `apigw` | `<iklim-prod-app-fip>` |
| `rabbitmq` | `<iklim-app-01-public-ip>` | | `rabbitmq` | `<iklim-prod-app-fip>` |
| `grafana` | `<iklim-app-01-public-ip>` | | `grafana` | `<iklim-prod-app-fip>` |
> Swarm's routing mesh means any node IP would work, but iklim-app-01 is the designated > Floating IP `iklim-app-01`'e atanmıştır (`06-prod-terraform-iaac.md``floating_ip.tf`).
> entry point (runs SWAG). Using a single IP keeps DNS simple. > Failover gerekirse Floating IP başka bir app node'una taşınabilir; DNS değişmez.
>
> For HA: add a load balancer or use Hetzner's floating IP in front of the 3 service nodes.
> DNS then points to the floating IP. This is a future improvement.
## Notes ## Notes
- Test and prod SWAG instances both obtain `*.iklim.co` independently from Let's Encrypt. - Test and prod SWAG instances both obtain `*.iklim.co` independently from Let's Encrypt.

View File

@ -93,11 +93,13 @@ docker service ps iklim-patroni_patroni-02
docker service ps iklim-patroni_patroni-03 docker service ps iklim-patroni_patroni-03
# etcd cluster (for Patroni) # etcd cluster (for Patroni)
docker stack services iklim-db-etcd docker stack services iklim-etcd
# MongoDB replica set # MongoDB replica set
docker stack services iklim-db docker stack services iklim-db
docker service ps iklim-db_mongodb docker service ps iklim-db_mongodb-01
docker service ps iklim-db_mongodb-02
docker service ps iklim-db_mongodb-03
``` ```
All tasks should show node names matching `iklim-db-01`, `iklim-db-02`, or `iklim-db-03` with placement constraint `role=db`. All tasks should show node names matching `iklim-db-01`, `iklim-db-02`, or `iklim-db-03` with placement constraint `role=db`.

View File

@ -5,55 +5,61 @@ Terraform/Ansible setup aşamalarından hangisinde ele alındığını gösterir
## TEST ortamı ## TEST ortamı
| Roadmap adımı | Hangi aşamada ele alınmalı | | Roadmap adımı | Hangi aşamada ele alınmalı |
| ---------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | | --- | --- |
| Hetzner firewall (sadece 22/80/443) | **Terraform `01-test-terraform-iaac.md`**`firewall.tf` | | Hetzner firewall (sadece 22/80/443) | **Terraform `02-test-terraform-iaac.md`**`firewall.tf` |
| Sunucu oluşturma (`iklim-app-01`, `iklim-db-01`) | **Terraform `01-test-terraform-iaac.md`**`servers.tf` | | Sunucu oluşturma (`iklim-app-01`, `iklim-db-01`) | **Terraform `02-test-terraform-iaac.md`**`servers.tf` |
| Private network + placement group (`iklim-test-spread`) | **Terraform `01-test-terraform-iaac.md`**`network.tf`, `placement.tf` | | Private network + placement group (`iklim-test-spread`) | **Terraform `02-test-terraform-iaac.md`**`network.tf`, `placement.tf` |
| Floating IP (`iklim-test-app-fip`) | **Terraform `01-test-terraform-iaac.md`**`floating_ip.tf` | | Floating IP (`iklim-test-app-fip`) | **Terraform `02-test-terraform-iaac.md`**`floating_ip.tf` |
| Docker Engine kurulumu | **Ansible `02-test-ansible-bootstrap.md`**`docker` role | | Docker Engine kurulumu (app + db node) | **Ansible `03-test-ansible-bootstrap.md`**`docker` role |
| Security hardening (SSH, firewalld, fail2ban) | **Ansible `02-test-ansible-bootstrap.md`**`hardening` role | | Security hardening (SSH, firewalld, fail2ban) | **Ansible `03-test-ansible-bootstrap.md`**`hardening` role |
| Docker Swarm init (`init/swarm-init.sh`) | **Ansible `02-test-ansible-bootstrap.md`**`swarm` role (pipeline script idempotent çalışmaya devam eder) | | Docker Swarm init + `iklim-db-01` worker join | **Ansible `03-test-ansible-bootstrap.md`**`swarm` role |
| `type=service` node label | **Ansible `02-test-ansible-bootstrap.md`**`swarm` role | | `type=service` ve `role=db` node label'ları | **Ansible `03-test-ansible-bootstrap.md`**`swarm` role |
| `/opt/iklimco/...` dizinleri | **Ansible `02-test-ansible-bootstrap.md`**`node_dirs` role | | `/opt/iklimco/...` dizinleri | **Ansible `03-test-ansible-bootstrap.md`**`node_dirs` role |
| StorageBox DAVFS mount (`u469968-sub1`) | **Ansible `02-test-ansible-bootstrap.md`**`storagebox` role | | StorageBox DAVFS mount (`u469968-sub4`) | **Ansible `03-test-ansible-bootstrap.md`**`storagebox` role |
| `act_runner` systemd kurulumu | **Ansible `03-test-runner-ve-deploy-onkosullari.md`**`gitea_runner` role | | DB stack deploy (PostgreSQL + MongoDB on `iklim-db-01`) | **Manuel `04-test-db-docker-kurulum.md`** |
| GoDaddy credentials storagebox'a yükleme | **Manuel kalır** — secret yönetimi, Terraform/Ansible dışı | | `act_runner` systemd kurulumu | **Ansible `05-test-runner-ve-deploy-onkosullari.md`**`gitea_runner` role |
| GoDaddy credentials storagebox'a yükleme | **Manuel kalır** — secret yönetimi, Terraform/Ansible dışı |
## PROD ortamı ## PROD ortamı
| Roadmap adımı | Hangi aşamada ele alınmalı | | Roadmap adımı | Hangi aşamada ele alınmalı |
| -------------------------------------------------------------------- | ------------------------------------------------------------------------ | | --- | --- |
| 6 sunucu oluşturma (`iklim-app-01/02/03`, `iklim-db-01/02/03`) | **Terraform `04-prod-terraform-iaac.md`**`servers.tf` | | 6 sunucu oluşturma (`iklim-app-01/02/03`, `iklim-db-01/02/03`) | **Terraform `06-prod-terraform-iaac.md`**`servers.tf` |
| Private network + 2 placement group | **Terraform `04-prod-terraform-iaac.md`**`network.tf`, `placement.tf` | | Private network + 2 placement group | **Terraform `06-prod-terraform-iaac.md`**`network.tf`, `placement.tf` |
| Firewall (sadece 22/80/443 public) | **Terraform `04-prod-terraform-iaac.md`**`firewall.tf` | | Firewall (sadece 22/80/443 public; private port matrisi) | **Terraform `06-prod-terraform-iaac.md`**`firewall.tf` |
| Floating IP (`iklim-prod-app-fip`, `iklim-app-01`'e atanır) | **Terraform `04-prod-terraform-iaac.md`**`floating_ip.tf` | | Floating IP (`iklim-prod-app-fip`, `iklim-app-01`'e atanır) | **Terraform `06-prod-terraform-iaac.md`**`floating_ip.tf` |
| Docker Engine kurulumu (`iklim-app-*`) | **Ansible `05-prod-ansible-bootstrap.md`**`docker` role | | Docker Engine kurulumu (tüm node'lar — app ve db) | **Ansible `07-prod-ansible-bootstrap.md`**`docker` role |
| Security hardening (tüm node'lar) | **Ansible `05-prod-ansible-bootstrap.md`**`hardening` role | | Security hardening (tüm node'lar) | **Ansible `07-prod-ansible-bootstrap.md`**`hardening` role |
| Swarm init (`iklim-app-01`) | **Ansible `05-prod-ansible-bootstrap.md`**`swarm` role | | Swarm init (`iklim-app-01`) + manager join (`iklim-app-02/03`) | **Ansible `07-prod-ansible-bootstrap.md`**`swarm` role |
| Manager join (`iklim-app-02`, `iklim-app-03`) | **Ansible `05-prod-ansible-bootstrap.md`**`swarm` role | | `type=service` node label (3 app node) | **Ansible `07-prod-ansible-bootstrap.md`**`swarm` role |
| `type=service` node label (3 swarm node) | **Ansible `05-prod-ansible-bootstrap.md`**`swarm` role | | `/opt/iklimco/...` dizinleri + `/opt/iklimco/stacks` | **Ansible `07-prod-ansible-bootstrap.md`**`node_dirs` role |
| `/opt/iklimco/...` dizinleri | **Ansible `05-prod-ansible-bootstrap.md`**`node_dirs` role | | StorageBox DAVFS mount (`u469968-sub5`) | **Ansible `07-prod-ansible-bootstrap.md`**`storagebox` role |
| StorageBox DAVFS mount (`u469968-sub2`) | **Ansible `05-prod-ansible-bootstrap.md`**`storagebox` role | | DB node'larını Swarm'a worker olarak join et | **Manuel `08-prod-db-cluster-kurulum.md`** — Bölüm 2 |
| 3× `act_runner` systemd (HA runner) | **Ansible `06-prod-runner-ha-ve-swarm.md`**`gitea_runner` role | | `role=db` node label (3 db node) | **Manuel `08-prod-db-cluster-kurulum.md`** — Bölüm 2 |
| GoDaddy credentials storagebox'a yükleme | **Manuel kalır** — secret yönetimi, Terraform/Ansible dışı | | etcd cluster deploy (Patroni için) | **Manuel `08-prod-db-cluster-kurulum.md`** — Bölüm 5.2 |
| DB node'ları Swarm'a join | **Kapsam dışı** — DB cluster ayrı yönetilir | | MongoDB replica set deploy | **Manuel `08-prod-db-cluster-kurulum.md`** — Bölüm 4 |
| Patroni + PostgreSQL HA deploy | **Manuel `08-prod-db-cluster-kurulum.md`** — Bölüm 5.4 |
| 3× `act_runner` systemd (HA runner) | **Ansible `09-prod-runner-ha-ve-swarm.md`**`gitea_runner` role |
| GoDaddy credentials storagebox'a yükleme | **Manuel kalır** — secret yönetimi, Terraform/Ansible dışı |
## Klasör yapısı ## Klasör yapısı
``` ```
Environment_Infrastructure/ Environment_Infrastructure/
setup/ ← Terraform + Ansible aşama dokümanları setup/ ← Terraform + Ansible aşama dokümanları
00-genel-yol-haritasi.md 00-genel-yol-haritasi.md
01-test-terraform-iaac.md 01-private-network-port-matrisi.md
02-test-ansible-bootstrap.md 02-test-terraform-iaac.md
03-test-runner-ve-deploy-onkosullari.md 03-test-ansible-bootstrap.md
04-prod-terraform-iaac.md 04-test-db-docker-kurulum.md
05-prod-ansible-bootstrap.md 05-test-runner-ve-deploy-onkosullari.md
06-prod-runner-ha-ve-swarm.md 06-prod-terraform-iaac.md
07-private-network-port-matrisi.md 07-prod-ansible-bootstrap.md
08-prod-db-cluster-kurulum.md
09-prod-runner-ha-ve-swarm.md
roadmap/ roadmap/
test-env/ ← Test ortamı Roadmap adımları test-env/ ← Test ortamı Roadmap adımları
prod-env/ ← Prod Roadmap adımları prod-env/ ← Prod Roadmap adımları
setup-vs-roadmap-map.md ← Bu dosya setup-vs-roadmap-map.md ← Bu dosya
``` ```

View File

@ -1,4 +1,4 @@
# 01 - Test Terraform IaC # 02 - Test Terraform IaC
Bu asamanin amaci test Hetzner Cloud Project icinde minimum IaaS kaynaklarini Terraform ile olusturmaktir. Bu dokuman tek basina uygulanabilir olacak sekilde yazilmistir. Bu asamanin amaci test Hetzner Cloud Project icinde minimum IaaS kaynaklarini Terraform ile olusturmaktir. Bu dokuman tek basina uygulanabilir olacak sekilde yazilmistir.
@ -37,6 +37,7 @@ terraform/
firewall.tf firewall.tf
placement.tf placement.tf
servers.tf servers.tf
floating_ip.tf
outputs.tf outputs.tf
terraform.tfvars.example terraform.tfvars.example
``` ```
@ -51,7 +52,7 @@ Minimum degiskenler:
hcloud_token = "secret" hcloud_token = "secret"
location = "fsn1" location = "fsn1"
image = "rocky-10" image = "rocky-10"
server_type_swarm = "cpx42" server_type_app = "cpx42"
server_type_db = "cpx42" server_type_db = "cpx42"
admin_ssh_public_key_path = "~/.ssh/id_ed25519.pub" admin_ssh_public_key_path = "~/.ssh/id_ed25519.pub"
admin_allowed_cidrs = ["X.X.X.X/32"] admin_allowed_cidrs = ["X.X.X.X/32"]
@ -161,6 +162,10 @@ output "test_private_ips" {
output "test_public_ips" { output "test_public_ips" {
sensitive = false sensitive = false
} }
output "test_floating_ip" {
sensitive = false
}
``` ```
Inventory output'u daha sonra `ansible/inventory/generated/test.yml` dosyasina yazilabilir. Inventory dosyasinda secret bulunmayacaksa commit edilebilir; secret veya token icerirse commit edilmeyecek. Inventory output'u daha sonra `ansible/inventory/generated/test.yml` dosyasina yazilabilir. Inventory dosyasinda secret bulunmayacaksa commit edilebilir; secret veya token icerirse commit edilmeyecek.

View File

@ -1,26 +1,99 @@
# 02 - Test Ansible Bootstrap # 03 - Test Ansible Bootstrap
Bu asamanin amaci Terraform ile olusturulan test makinelerini Linux, hardening, Docker ve Swarm acisindan hazir hale getirmektir. DB yazilimi kurulumu bu asamanin disindadir. Bu aşamanın amacı Terraform ile oluşturulan test makinelerini Linux, hardening, Docker ve Swarm açısından hazır hale getirmektir. DB yazılımı kurulumu bu aşamanın dışındadır.
## Ansible Kurulumu
Ansible, kontrol makinesinde (kendi bilgisayarınızda) yüklü olmalıdır. Hedef sunuculara herhangi bir ajan kurulmaz, sadece SSH erişimi yeterlidir.
### İşletim Sistemine Göre Kurulum
- **Ubuntu / Debian:**
```bash
sudo apt update
sudo apt install -y pipx python3-venv
pipx ensurepath
export PATH="$HOME/.local/bin:$PATH"
pipx install --include-deps ansible
```
> Not: `sudo apt install ansible` komutu bazı Ubuntu/Debian sürümlerinde eski Ansible paketlerini kurabilir. Bu nedenle güncel Ansible kullanımı için `pipx` yöntemi tercih edilmelidir.
- **Fedora / Rocky Linux / RHEL:**
```bash
sudo dnf install -y pipx python3-virtualenv
pipx ensurepath
export PATH="$HOME/.local/bin:$PATH"
pipx install --include-deps ansible
```
- **macOS (Homebrew):**
```bash
brew install ansible
```
- **Python Pip ile (Her platformda):**
```bash
pipx install --include-deps ansible
```
### Kurulumun Doğrulanması
Hangi yöntemle kurarsanız kurun, kurulumun başarılı olduğunu doğrulamak için aşağıdaki komutları kullanın:
```bash
# Ansible versiyonunu ve yapılandırma yollarını kontrol edin
ansible --version
# Ansible binarysinin hangi konumdan çalıştığını kontrol edin
which -a ansible
```
## Ansible Komutlarını Çalıştırma
Tüm komutlar projenin `ansible/` dizini altından çalıştırılmalıdır.
### 1. Bağlantı Testi (Ping)
Sunuculara erişimi doğrulamak için:
```bash
ansible -i inventory/generated/test.yml all -m ping
```
### 2. Bootstrap Playbook'unu Çalıştırma
Tüm rolleri (base, hardening, docker, swarm vb.) uygulamak için:
```bash
ansible-playbook -i inventory/generated/test.yml playbooks/test-bootstrap.yml --ask-vault-pass
```
*Not: `--ask-vault-pass` parametresi, hassas verilerin (StorageBox şifresi vb.) çözülmesi için gereken Ansible Vault parolasını soracaktır.*
### 3. Sadece Belirli Bir Rolü Çalıştırma (Tags)
Sadece belirli bir kısmı güncellemek isterseniz (örneğin sadece hardening):
```bash
ansible-playbook -i inventory/generated/test.yml playbooks/test-bootstrap.yml --tags "hardening" --ask-vault-pass
```
## Hedef Makineler ## Hedef Makineler
| Host | Rol | | Host | Rol |
| --- | --- | | --- | --- |
| `iklim-app-01` | Swarm manager + app worker | | `iklim-app-01` | Swarm manager + app worker |
| `iklim-db-01` | Manuel DB kurulumu icin OS-hardening uygulanmis DB node | | `iklim-db-01` | Manuel DB kurulumu için OS-hardening uygulanmış DB node |
## Onerilen Dosya Yapisi ## Önerilen Dosya Yapısı
```text ```text
ansible/ ansible/
ansible.cfg test/
inventory/ ansible.cfg
generated/ inventory/
generated/
test.yml
group_vars/
all.yml
test.yml test.yml
group_vars/
all.yml
test.yml
playbooks/
test-bootstrap.yml test-bootstrap.yml
roles/ roles/
base/ base/
@ -29,15 +102,16 @@ ansible/
swarm/ swarm/
node_dirs/ node_dirs/
storagebox/ storagebox/
storagebox_ssh_key/
``` ```
## Base Role ## Base Role
Tum test node'larina uygulanir: Tüm test node'larına uygulanır:
- `dnf update` - `dnf update`
- temel paketler (sirasıyla kurulur): - temel paketler (sırasıyla kurulur):
- `epel-release` — fail2ban ve davfs2 bu repo'dan gelir; once kurulur - `epel-release` — fail2ban ve davfs2 bu repo'dan gelir; önce kurulur
- `curl` - `curl`
- `wget` - `wget`
- `git` - `git`
@ -45,46 +119,48 @@ Tum test node'larina uygulanir:
- `tar` - `tar`
- `unzip` - `unzip`
- `bash-completion` - `bash-completion`
- `gettext` — envsubst icin; CI/CD deploy pipeline'larinda gerekli - `gettext` — envsubst için; CI/CD deploy pipeline'larında gerekli
- `tree` - `tree`
- `ca-certificates` - `ca-certificates`
- `fail2ban` - `fail2ban`
- `chrony` - `chrony`
- `python3` - `python3`
- `python3-pip` - `python3-pip`
- `htop` — interaktif proses izleme (EPEL)
- `btop` — kaynak monitörü, grafik arayüz (EPEL)
- timezone: `Europe/Istanbul` - timezone: `Europe/Istanbul`
- hostname ayari - hostname ayarı
- sistem reboot gerekiyorsa kontrollu reboot - sistem reboot gerekiyorsa kontrollü reboot
## Security Hardening Role ## Security Hardening Role
Tum test node'larina uygulanir: Tüm test node'larına uygulanır:
- SSH password login kapatilir. - SSH password login kapatılır.
- Root SSH login kapatilir. - Root SSH login kapatılır.
- Sadece SSH key ile login kalir. - Sadece SSH key ile login kalır.
- `PermitEmptyPasswords no` - `PermitEmptyPasswords no`
- `MaxAuthTries 3` - `MaxAuthTries 3`
- `fail2ban` SSH jail aktif edilir. - `fail2ban` SSH jail aktif edilir.
- `dnf-automatic` ile otomatik guvenlik guncellestirmeleri aktif edilir. - `dnf-automatic` ile otomatik güvenlik güncelleştirmeleri aktif edilir.
- `firewalld` default: - `firewalld` default:
- incoming: deny (drop zone) - incoming: deny (drop zone)
- outgoing: allow - outgoing: allow
- Public SSH sadece admin CIDR'dan acilir. - Public SSH sadece admin CIDR'dan açılır.
### SELinux Karari ### SELinux Kararı
Rocky Linux 10 SELinux enforcing modda gelir. Karar: **disabled**. Rocky Linux 10 SELinux enforcing modda gelir. Karar: **disabled**.
Gerekce: Gerekçe:
- Hetzner Cloud firewall (dis perimeter) + firewalld (host) iki katman ag guvenligini saglar. - Hetzner Cloud firewall (dış perimeter) + firewalld (host) iki katman ağ güvenliğini sağlar.
- Docker + davfs2 + firewalld kombinasyonu SELinux enforcing modda ek policy ve volume label yonetimi gerektirir. - Docker + davfs2 + firewalld kombinasyonu SELinux enforcing modda ek policy ve volume label yönetimi gerektirir.
- Utils VPS'te de disabled yapilmis; tutarlilik saglanir. - Utils VPS'te de disabled yapılmış; tutarlılık sağlanır.
```bash ```bash
# /etc/selinux/config icinde: # /etc/selinux/config içinde:
SELINUX=disabled SELINUX=disabled
# Degisiklik reboot sonrasi aktif olur # Değişiklik reboot sonrası aktif olur
reboot reboot
``` ```
@ -101,9 +177,9 @@ Ansible'da:
when: selinux_change.changed when: selinux_change.changed
``` ```
### fail2ban Konfigurasyonu ### fail2ban Konfigürasyonu
`/etc/fail2ban/jail.local` icerigi: `/etc/fail2ban/jail.local` içeriği:
```ini ```ini
[DEFAULT] [DEFAULT]
@ -119,19 +195,19 @@ enabled = true
``` ```
- `bantime`: 6 saat ban - `bantime`: 6 saat ban
- `findtime`: 5 dakika icinde - `findtime`: 5 dakika içinde
- `maxretry`: 5 basarisiz giris → ban - `maxretry`: 5 başarısız giriş → ban
- `ignoreip`: admin CIDR'lari ban'dan muaf tutar - `ignoreip`: admin CIDR'ları ban'dan muaf tutar
Ansible'da `admin_allowed_cidrs` listesi space-separated stringe donusturulup template'e basilir. Ansible'da `admin_allowed_cidrs` listesi space-separated stringe dönüştürülüp template'e basılır.
Not: Docker iptables kurallari firewalld ile etkilesebilir. Hetzner Cloud firewall asil dis perimeter kabul edilir; firewalld host icinde ikinci katman olarak kullanilir. Not: Docker iptables kuralları firewalld ile etkileşebilir. Hetzner Cloud firewall asıl dış perimeter kabul edilir; firewalld host içinde ikinci katman olarak kullanılır.
## Docker Role ## Docker Role
Sadece `iklim-app-01` uzerinde zorunludur. `iklim-db-01` uzerinde DB manual kurulum stratejisine gore opsiyonel tutulabilir. Her iki node (`iklim-app-01` ve `iklim-db-01`) üzerinde de zorunludur. DB node'u Swarm Worker olarak ağa dahil olacağı için Docker Engine her iki makinede de kurulu olmalıdır.
Docker kurulumu resmi Docker dnf repository uzerinden yapilir: Docker kurulumu resmi Docker dnf repository üzerinden yapılır:
- Docker GPG key + dnf repository (`https://download.docker.com/linux/rhel/docker-ce.repo`) - Docker GPG key + dnf repository (`https://download.docker.com/linux/rhel/docker-ce.repo`)
- paketler: - paketler:
@ -142,30 +218,26 @@ Docker kurulumu resmi Docker dnf repository uzerinden yapilir:
- `docker-compose-plugin` - `docker-compose-plugin`
- Docker servisi enabled + started - Docker servisi enabled + started
Docker convenience script kullanilmayacak. Production benzeri test ortami icin paket repository yolu tercih edilir. Docker convenience script kullanılmayacak. Production benzeri test ortamıin paket repository yolu tercih edilir.
## Swarm Role ## Swarm Role
`iklim-app-01` uzerinde: - `iklim-app-01` üzerinde Swarm Manager olarak init edilir.
- `iklim-db-01` üzerinde Swarm Worker olarak join edilir (Overlay network erişimi için).
- `docker swarm init` - advertise addr: `10.10.10.11` (manager için)
- advertise addr: `10.10.10.11`
- data path addr: `10.10.10.11`
- overlay network: - overlay network:
- `iklimco-net` - `iklimco-net`
- driver: `overlay` - driver: `overlay`
- attachable: `true` - attachable: `true`
- Node `type=service` label'i ile isaretlenir: - Node etiketleri:
```bash - `iklim-app-01` -> `type=service`
docker node update --label-add type=service iklim-app-01 - `iklim-db-01` -> `role=db`
``` - `iklim-app-01` üzerinde hem manager hem worker (Active) görevini sürdürür.
- Node `AVAILABILITY=Active` kalir (drain edilmez); tek node hem manager hem worker'dir.
Test tek node Swarm oldugu icin join token kullanimi yoktur.
## Node Directory Role ## Node Directory Role
`iklim-app-01` uzerinde deploy on kosullari: `iklim-app-01` üzerinde deploy ön koşulları:
```text ```text
/opt/iklimco /opt/iklimco
@ -175,7 +247,7 @@ Test tek node Swarm oldugu icin join token kullanimi yoktur.
/opt/iklimco/init/mongodb /opt/iklimco/init/mongodb
``` ```
DB node uzerinde manuel DB kurulumu icin minimum: DB node üzerinde manuel DB kurulumu için minimum:
```text ```text
/opt/iklimco /opt/iklimco
@ -185,57 +257,57 @@ DB node uzerinde manuel DB kurulumu icin minimum:
## StorageBox DAVFS Mount Role ## StorageBox DAVFS Mount Role
Her iki node'a uygulanir (`iklim-app-01` ve `iklim-db-01`). Her iki node'a uygulanır (`iklim-app-01` ve `iklim-db-01`).
### Amac ### Amaç
Hetzner StorageBox'u WebDAV (DAVFS) protokolü üzerinden `/mnt/storagebox` olarak mount eder. Docker volume'lari bu dizine baglanarak veri kaliciligini ve yedeklemeyi saglar. Hetzner StorageBox'u WebDAV (DAVFS) protokolü üzerinden `/mnt/storagebox` olarak mount eder. Docker volume'ları bu dizine bağlanarak veri kalıcılığını ve yedeklemeyi sağlar.
### Test Ortami Sub-Account ### Test Ortamı Sub-Account
| Parametre | Degisken | Deger | | Parametre | Değişken | Değer |
| --- | --- | --- | | --- | --- | --- |
| Ana hesap | `storagebox_account` | `u469968` | | Ana hesap | `storagebox_account` | `u469968` |
| Sub-account | `storagebox_user` | `u469968-sub1` | | Sub-account | `storagebox_user` | `u469968-sub4` |
| WebDAV URL | `storagebox_url` | `https://u469968-sub1.your-storagebox.de/` | | WebDAV URL | `storagebox_url` | `https://u469968-sub4.your-storagebox.de/` |
| Mount point | `storagebox_mount_point` | `/mnt/storagebox` | | Mount point | `storagebox_mount_point` | `/mnt/storagebox` |
### Role Degiskenleri ### Role Değişkenleri
`group_vars/all.yml` — tum ortamlar icin ortak: `group_vars/all.yml` — tüm ortamlar için ortak:
```yaml ```yaml
storagebox_account: "u469968" storagebox_account: "u469968"
``` ```
`group_vars/test.yml` — test ortamina ozgu; user ve url account'tan turetilir: `group_vars/test.yml` — test ortamına özgü; user ve url account'tan türetilir:
```yaml ```yaml
storagebox_user: "{{ storagebox_account }}-sub1" storagebox_user: "{{ storagebox_account }}-sub1"
storagebox_url: "https://{{ storagebox_user }}.your-storagebox.de/" storagebox_url: "https://{{ storagebox_user }}.your-storagebox.de/"
storagebox_password: "{{ vault_storagebox_password }}" # Ansible Vault ile saklanir storagebox_password: "{{ vault_storagebox_password }}" # Ansible Vault ile saklanır
storagebox_mount_point: "/mnt/storagebox" storagebox_mount_point: "/mnt/storagebox"
``` ```
Prod ortaminda yalnizca suffix degisir (`sub1``sub2`), geri kalan her sey turetilir. Prod ortamında yalnızca suffix değişir (`sub4``sub5`), geri kalan her şey türetilir.
`vault_storagebox_password` degeri Ansible Vault ile sifreli `group_vars/test-vault.yml` icinde tutulur: `vault_storagebox_password` değeri Ansible Vault ile şifreli `group_vars/test-vault.yml`inde tutulur:
```bash ```bash
# Sifreleme # Sifreleme
ansible-vault encrypt group_vars/test-vault.yml ansible-vault encrypt group_vars/test-vault.yml
# Duzenleme # Düzenleme
ansible-vault edit group_vars/test-vault.yml ansible-vault edit group_vars/test-vault.yml
``` ```
`test-vault.yml` icerigi: `test-vault.yml` içeriği:
```yaml ```yaml
vault_storagebox_password: "SUB_ACCOUNT_PAROLASI" vault_storagebox_password: "SUB_ACCOUNT_PAROLASI"
``` ```
### Adimlar ### Adımlar
1. **davfs2 kurulumu** 1. **davfs2 kurulumu**
@ -246,7 +318,7 @@ vault_storagebox_password: "SUB_ACCOUNT_PAROLASI"
state: present state: present
``` ```
2. **Kimlik bilgileri dosyasi** (`/etc/davfs2/secrets`) 2. **Kimlik bilgileri dosyası** (`/etc/davfs2/secrets`)
```yaml ```yaml
- name: Configure davfs2 secrets - name: Configure davfs2 secrets
@ -259,7 +331,7 @@ vault_storagebox_password: "SUB_ACCOUNT_PAROLASI"
group: root group: root
``` ```
3. **Mount point olustur** 3. **Mount point oluştur**
```yaml ```yaml
- name: Create mount point - name: Create mount point
@ -290,7 +362,7 @@ vault_storagebox_password: "SUB_ACCOUNT_PAROLASI"
creates: "{{ storagebox_mount_point }}/.mounted_marker" creates: "{{ storagebox_mount_point }}/.mounted_marker"
``` ```
Mount basarisi icin dizine bir marker dosyasi yazilabilir: Mount başarısı için dizine bir marker dosyası yazılabilir:
```yaml ```yaml
- name: Write mount marker - name: Write mount marker
@ -302,58 +374,58 @@ vault_storagebox_password: "SUB_ACCOUNT_PAROLASI"
### Notlar ### Notlar
- `davfs2` paketi EPEL repository'sinde bulunur; base role `epel-release`'i zaten kurar. - `davfs2` paketi EPEL repository'sinde bulunur; base role `epel-release`'i zaten kurar.
- StorageBox sifreleri asla plaintext olarak repository'e eklenmez; Ansible Vault zorunludur. - StorageBox şifreleri asla plaintext olarak repository'e eklenmez; Ansible Vault zorunludur.
- Mount noktasi reboot'ta `_netdev` flag'i sayesinde network hazir olduktan sonra otomatik mount edilir. - Mount noktası reboot'ta `_netdev` flag'ı sayesinde network hazır olduktan sonra otomatik mount edilir.
- Docker Swarm servisleri `/mnt/storagebox/<env>/<service>/` altindaki dizinleri bind mount olarak kullanir. - Docker Swarm servisleri `/mnt/storagebox/<env>/<service>/` altındaki dizinleri bind mount olarak kullanır.
## StorageBox SSH Key Role ## StorageBox SSH Key Role
Her iki node'a uygulanir (`iklim-app-01` ve `iklim-db-01`). Her iki node'a uygulanır (`iklim-app-01` ve `iklim-db-01`).
### Amac ### Amaç
Sunucu uzerinde ed25519 SSH anahtar cifti uretilir ve StorageBox ana hesabina yuklenir. Sunucu üzerinde ed25519 SSH anahtar çifti üretilir ve StorageBox ana hesabına yüklenir.
Bu sayede CI/CD pipeline'lari `STORAGEBOX_SSH_PRIV` Gitea secret'ini kullanarak Bu sayede CI/CD pipeline'ları `STORAGEBOX_SSH_PRIV` Gitea secret'ini kullanarak
sifre girmeden StorageBox'a erisebilir. şifresiz erişim sağlayabilir.
### Adimlar ### Adımlar
1. **SSH key uret** (eger yoksa) 1. **SSH Key üretimi**
```yaml ```yaml
- name: Generate SSH key for storagebox - name: Generate SSH key for StorageBox
ansible.builtin.user: ansible.builtin.user:
name: root name: root
generate_ssh_key: yes generate_ssh_key: yes
ssh_key_type: ed25519 ssh_key_type: ed25519
ssh_key_file: /root/.ssh/id_ed25519_storagebox ssh_key_file: .ssh/id_ed25519_storagebox
ssh_key_comment: "{{ inventory_hostname }}-storagebox" ssh_key_comment: "{{ inventory_hostname }}-storagebox"
``` ```
2. **Public key'i StorageBox'a yukle** 2. **Public key'i StorageBox'a yükle**
Bu adim manuel yapilir (ilk kez sifre gerektirir): Bu adım manuel yapılır (ilk kez şifre gerektirir):
```bash ```bash
cat /root/.ssh/id_ed25519_storagebox.pub | ssh -p23 u469968-sub1@u469968-sub1.your-storagebox.de install-ssh-key cat /root/.ssh/id_ed25519_storagebox.pub | ssh -p23 u469968-sub4@u469968-sub4.your-storagebox.de install-ssh-key
``` ```
Sonraki erisimler sifresiz calisir: Sonraki erişimler şifresiz çalışır:
```bash ```bash
sftp -P23 u469968-sub1@u469968-sub1.your-storagebox.de sftp -P23 u469968-sub4@u469968-sub4.your-storagebox.de
``` ```
3. **Private ve public key'leri Gitea'ya ekle** 3. **Private ve public key'leri Gitea'ya ekle**
Gitea → Organization Settings → Actions → Secrets: Gitea → Organization Settings → Actions → Secrets:
| Secret Adi | Deger | | Secret Adı | Değer |
| --- | --- | | --- | --- |
| `STORAGEBOX_SSH_PRIV` | `/root/.ssh/id_ed25519_storagebox` icerigi | | `STORAGEBOX_SSH_PRIV` | `/root/.ssh/id_ed25519_storagebox` içeriği |
| `STORAGEBOX_SSH_PUB` | `/root/.ssh/id_ed25519_storagebox.pub` icerigi | | `STORAGEBOX_SSH_PUB` | `/root/.ssh/id_ed25519_storagebox.pub` içeriği |
Key icerigini almak icin: Key içeriğini almak için:
```bash ```bash
cat /root/.ssh/id_ed25519_storagebox cat /root/.ssh/id_ed25519_storagebox
@ -362,18 +434,7 @@ sifre girmeden StorageBox'a erisebilir.
### Notlar ### Notlar
- Her sunucu icin ayri key uretilir; tum public key'ler StorageBox ana hesabina yuklenir. - Her sunucu için ayrı key üretilir; tüm public key'ler StorageBox ana hesabına yüklenir.
- Private key asla repo'ya commit edilmez; yalnizca Gitea secret olarak saklanir. - Private key asla repo'ya commit edilmez; yalnızca Gitea secret olarak saklanır.
## Kabul Kriterleri ## Kabul Kriterleri
- `ansible -i inventory/generated/test.yml all -m ping` basarili olur.
- `iklim-app-01` uzerinde `docker info` calisir.
- `iklim-app-01` uzerinde Swarm active olur; node `AVAILABILITY=Active` (drain degil).
- `docker network ls` icinde `iklimco-net` gorulur.
- `docker node inspect iklim-app-01 --format '{{.Spec.Labels}}'` ciktisi `map[type:service]` icerir.
- `iklim-db-01` uzerinde public DB portu acik degildir.
- Public portlar Hetzner firewall + firewalld seviyesinde `22`, `80`, `443` ile sinirlidir.
- Her iki node'da `mount | grep storagebox` StorageBox mount'unu gosterir.
- `ls /mnt/storagebox/.mounted_marker` basarili olur.
- Reboot sonrasi mount otomatik olarak geri gelir.

View File

@ -1,112 +1,34 @@
# 08 - Test DB Docker Kurulumu (Swarm) # 04 - Test DB Docker Kurulumu (Swarm Worker)
Bu asamanin amaci `iklim-db-01` node'unu Swarm'a worker olarak eklemek ve PostgreSQL ile MongoDB'yi Swarm servisi olarak calistirmaktir. Veri kaliciligini StorageBox saglar. Bu aşamanın amacı `iklim-db-01` node'unu Swarm'a worker olarak eklemek ve PostgreSQL ile MongoDB'yi Swarm servisi olarak çalıştırmaktır.
DB yazilimi Ansible tarafindan kurulmaz; bu belge DB node uzerinde elle veya ayri bir Ansible role ile uygulanir. `03-test-ansible-bootstrap.md` tamamlandiktan sonra baslayiniz. ## Mimari Karar
## Mimari 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.
``` **Neden?**
iklim-app-01 (Swarm manager, 10.10.10.11) 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.
|-- iklimco-net (overlay) 3. **Veri Kalıcılığı:** Veriler Hetzner StorageBox (`/mnt/storagebox`) üzerinde saklanarak host bağımsızlığı sağlanır.
|
iklim-db-01 (Swarm worker, 10.10.20.11) [role=db]
|-- postgresql-v17 (Swarm service, placement: role=db)
|-- mongo-v8 (Swarm service, placement: role=db)
|
/mnt/storagebox/test/db/
postgresql/data/
mongodb/data/
mongodb/log/
mongodb/config/
```
## On Kosullar ## Ön Koşullar
- `03-test-ansible-bootstrap.md` her iki node'da tamamlanmis olmali. - `03-test-ansible-bootstrap.md` her iki node'da tamamlanmış olmalı.
- StorageBox `/mnt/storagebox` olarak her iki node'da mount edilmis olmali. - StorageBox `/mnt/storagebox` olarak her iki node'da mount edilmiş olmalı.
- Docker `iklim-db-01` uzerinde kurulu olmali (bootstrap role bunu yapar). - Docker `iklim-db-01` üzerinde kurulu olmalı (Bootstrap role bunu yapar).
## 1. Firewall Guncellemesi ## 1. Firewall Güncellemesi
`iklim-db-01`'in Swarm'a katilabilmesi icin ek kurallara ihtiyac var. `iklim-db-01`'in Swarm'a katılabilmesi ve uygulama trafiğini kabul etmesi için `terraform/hetzner/test/firewall.tf` dosyasına kurallar eklenmelidir.
`terraform/hetzner/test/firewall.tf` dosyasina asagidaki kurallari ekle:
`hcloud_firewall.swarm` icine (DB subnet'ten Swarm portlarina erisim): ### Swarm İletişimi (App Subnet <-> DB Subnet)
Swarm yönetimi için `2377/tcp`, `7946/tcp/udp` ve `4789/udp` portları her iki subnet arasında karşılıklıık olmalıdır.
```hcl ### DB Erişimi (App Subnet -> DB Subnet)
rule { - **PostgreSQL:** `5432/tcp`
direction = "in" - **MongoDB:** `27017/tcp`
protocol = "tcp"
port = "2377"
source_ips = [local.db_subnet_cidr]
description = "Docker Swarm control plane from DB subnet"
}
rule {
direction = "in"
protocol = "tcp"
port = "7946"
source_ips = [local.db_subnet_cidr]
description = "Docker Swarm node discovery (TCP) from DB subnet"
}
rule {
direction = "in"
protocol = "udp"
port = "7946"
source_ips = [local.db_subnet_cidr]
description = "Docker Swarm node discovery (UDP) from DB subnet"
}
rule {
direction = "in"
protocol = "udp"
port = "4789"
source_ips = [local.db_subnet_cidr]
description = "Docker Swarm VXLAN overlay from DB subnet"
}
```
`hcloud_firewall.db` icine (app subnet'ten Swarm portlarina erisim):
```hcl
rule {
direction = "in"
protocol = "tcp"
port = "2377"
source_ips = [local.app_subnet_cidr]
description = "Docker Swarm control plane from app subnet"
}
rule {
direction = "in"
protocol = "tcp"
port = "7946"
source_ips = [local.app_subnet_cidr]
description = "Docker Swarm node discovery (TCP) from app subnet"
}
rule {
direction = "in"
protocol = "udp"
port = "7946"
source_ips = [local.app_subnet_cidr]
description = "Docker Swarm node discovery (UDP) from app subnet"
}
rule {
direction = "in"
protocol = "udp"
port = "4789"
source_ips = [local.app_subnet_cidr]
description = "Docker Swarm VXLAN overlay from app subnet"
}
```
Sonra uygula:
Güncellemeyi yaptıktan sonra:
```bash ```bash
cd terraform/hetzner/test cd terraform/hetzner/test
terraform apply terraform apply
@ -114,29 +36,24 @@ terraform apply
## 2. DB Node'u Swarm'a Ekleme ## 2. DB Node'u Swarm'a Ekleme
**iklim-app-01 uzerinde** join token al: **iklim-app-01 üzerinde (Manager)** join token alın:
```bash ```bash
docker swarm join-token worker docker swarm join-token worker
``` ```
**iklim-db-01 uzerinde** Swarm'a katil: **iklim-db-01 üzerinde (Worker)** Swarm'a katılın:
```bash ```bash
docker swarm join --token <TOKEN> 10.10.10.11:2377 docker swarm join --token <TOKEN> 10.10.10.11:2377
``` ```
**iklim-app-01 uzerinde** node'u etiketle: **iklim-app-01 üzerinde** node'u etiketleyin:
```bash ```bash
docker node update --label-add role=db iklim-db-01 docker node update --label-add role=db iklim-db-01
docker node ls
``` ```
## 3. StorageBox Dizin Yapisi ## 3. StorageBox Dizin Yapısı
**iklim-db-01 uzerinde:**
**iklim-db-01 üzerinde:**
```bash ```bash
mkdir -p /mnt/storagebox/test/db/postgresql/data mkdir -p /mnt/storagebox/test/db/postgresql/data
mkdir -p /mnt/storagebox/test/db/mongodb/data mkdir -p /mnt/storagebox/test/db/mongodb/data
@ -144,36 +61,29 @@ mkdir -p /mnt/storagebox/test/db/mongodb/log
mkdir -p /mnt/storagebox/test/db/mongodb/config mkdir -p /mnt/storagebox/test/db/mongodb/config
``` ```
## 4. PostgreSQL Stack ## 4. Veritabanı Konfigürasyonları
### mongod.conf
`/mnt/storagebox/test/db/mongodb/config/mongod.conf` dosyasini olustur:
### MongoDB Config (`mongod.conf`)
`/mnt/storagebox/test/db/mongodb/config/mongod.conf` dosyasını oluşturun:
```yaml ```yaml
processManagement: storage:
pidFilePath: "/data/db/mongod.pid" dbPath: /data/db
journal:
enabled: true
systemLog:
destination: file
logAppend: true
path: /data/log/mongod.log
net: net:
port: 27017 port: 27017
storage: bindIp: 0.0.0.0
engine: "wiredTiger"
dbPath: "/data/db"
directoryPerDB: true
systemLog:
verbosity: 0
timeStampFormat: "iso8601-local"
destination: file
path: "/data/log/mongo.log"
logAppend: true
logRotate: rename
security: security:
authorization: enabled authorization: enabled
``` ```
### Stack Dosyasi ## 5. DB Stack Kurulumu
`/opt/iklimco/stacks/db.yml`:
`/opt/iklimco/stacks/db.yml` (iklim-app-01 üzerinde):
```yaml ```yaml
version: "3.8" version: "3.8"
@ -189,98 +99,44 @@ services:
POSTGRES_PASSWORD: "${POSTGRES_PASSWORD}" POSTGRES_PASSWORD: "${POSTGRES_PASSWORD}"
POSTGRES_DB: postgres POSTGRES_DB: postgres
PGDATA: /var/lib/postgresql/data/pgdata PGDATA: /var/lib/postgresql/data/pgdata
TZ: "Europe/Istanbul"
volumes: volumes:
- /mnt/storagebox/test/db/postgresql/data:/var/lib/postgresql/data - /mnt/storagebox/test/db/postgresql/data:/var/lib/postgresql/data
- /opt/iklimco/init/postgresql:/docker-entrypoint-initdb.d:ro
networks: networks:
- iklimco-net - iklimco-net
deploy: deploy:
replicas: 1
placement: placement:
constraints: constraints:
- node.labels.role == db - node.labels.role == db
restart_policy:
condition: on-failure
mongodb: mongodb:
image: mongo:8 image: mongo:8
environment: environment:
MONGO_INITDB_ROOT_USERNAME: mongo-root MONGO_INITDB_ROOT_USERNAME: "${DATABASE_MONGO_ROOT_USER}"
MONGO_INITDB_ROOT_PASSWORD: "${MONGO_ROOT_PASSWORD}" MONGO_INITDB_ROOT_PASSWORD: "${MONGO_ROOT_PASSWORD}"
volumes: volumes:
- /mnt/storagebox/test/db/mongodb/data:/data/db - /mnt/storagebox/test/db/mongodb/data:/data/db
- /mnt/storagebox/test/db/mongodb/log:/data/log - /mnt/storagebox/test/db/mongodb/log:/data/log
- /mnt/storagebox/test/db/mongodb/config:/data/configdb - /mnt/storagebox/test/db/mongodb/config/mongod.conf:/etc/mongod.conf
command: ["--config", "/etc/mongod.conf"]
networks: networks:
- iklimco-net - iklimco-net
command: ["--config", "/data/configdb/mongod.conf"]
deploy: deploy:
replicas: 1
placement: placement:
constraints: constraints:
- node.labels.role == db - node.labels.role == db
restart_policy:
condition: on-failure
``` ```
### .env Dosyasi ### Deploy
`/opt/iklimco/stacks/.env` (repo'ya commit edilmez):
```env
DATABASE_POSTGRES_ROOT_USER=<kullanici-adi>
POSTGRES_PASSWORD=<guclu-sifre>
MONGO_ROOT_PASSWORD=<guclu-sifre>
```
## 5. Deploy
```bash ```bash
# iklim-app-01 uzerinde (Swarm manager) # .env dosyasını oluşturun (Hassas veriler için)
docker stack deploy --compose-file /opt/iklimco/stacks/db.yml \ # DATABASE_POSTGRES_ROOT_USER, POSTGRES_PASSWORD, DATABASE_MONGO_ROOT_USER, MONGO_ROOT_PASSWORD
--with-registry-auth \
$(set -a; source /opt/iklimco/stacks/.env; set +a; echo "") \ docker stack deploy -c /opt/iklimco/stacks/db.yml iklim-db
iklim-db
``` ```
Alternatif olarak env-file destegi icin: ## 6. Kabul Kriterleri
```bash - `docker node ls` komutunda `iklim-db-01` Ready ve Active görünür.
docker stack deploy \ - `docker stack services iklim-db` her iki servisi 1/1 replica ile gösterir.
--compose-file <(docker-compose -f /opt/iklimco/stacks/db.yml config) \ - Uygulama node'undan `iklim-db_postgresql` ve `iklim-db_mongodb` DNS isimleriyle erişim sağlanır.
iklim-db - Reboot sonrası veriler `/mnt/storagebox` üzerinden korunur.
```
Kontrol:
```bash
docker stack services iklim-db
docker service logs iklim-db_postgresql
docker service logs iklim-db_mongodb
```
## 6. App Servislerinden Erisim
Overlay network (`iklimco-net`) uzerinden servis adlariyla erisim:
| Servis | Host (overlay DNS) | Port |
| --- | --- | --- |
| PostgreSQL | `iklim-db_postgresql` | `5432` |
| MongoDB | `iklim-db_mongodb` | `27017` |
Spring Boot vb. uygulama konfigurasyon ornegi:
```
spring.datasource.url=jdbc:postgresql://iklim-db_postgresql:5432/iklimdb
spring.data.mongodb.uri=mongodb://mongo-root:<sifre>@iklim-db_mongodb:27017/iklimdb?authSource=admin
```
## Kabul Kriterleri
- `docker stack services iklim-db` her iki servisi `1/1` olarak gosterir.
- `iklim-app-01` uzerinden `postgresql` servisine TCP 5432 overlay ile ulasilabilir.
- `iklim-app-01` uzerinden `mongodb` servisine TCP 27017 overlay ile ulasilabilir.
- `/mnt/storagebox/test/db/postgresql/data/` dizininde veri dosyalari olusur.
- Servis yeniden baslatildiginda veri korunur.
- `5432` ve `27017` portlari public internet'ten kapalidir.

View File

@ -1,154 +1,95 @@
# 03 - Test Runner ve Deploy On Kosullari # 05 - Test Runner ve Deploy Ön Koşulları
Bu asamanin amaci test ortaminda Gitea Actions runner'i systemd servisi olarak kurmak ve mevcut test CI/CD pipeline'larinin calisabilecegi host on kosullarini hazirlamaktir. Bu aşamanın amacı test ortamında Gitea Actions runner'ı (`act_runner`) systemd servisi olarak kurmak ve CI/CD pipeline'larının çalışabileceği ortamı hazırlamaktır.
## Runner Yerlesimi ## Runner Yerleşimi
Test ortaminda tek runner yeterlidir: Test ortamında maliyet ve basitlik için tek runner kullanılır:
| Host | Runner | | Host | Servis Adı | Label |
| --- | --- |
| `iklim-app-01` | `act_runner` systemd servisi |
Runner Docker container olarak calistirilmayacak. `/var/run/docker.sock` bir runner container'ina mount edilmeyecek.
## Neden Systemd Runner
Mevcut CI/CD akisinda Gitea job'lari gerekli hazirliklari kendi icinde yapip deploy komutlarini calistiriyor. Runner'in Docker container olmasi, Docker socket mount edilmesini gerektirir ve bu model ekstra yetki riski uretir. Systemd runner modelinde socket mount yoktur; ancak runner host uzerinde Docker kullanacagi icin runner kullanicisinin Docker erisimi yine yuksek yetki kabul edilir.
Bu nedenle:
- Runner sadece guvenilir Gitea instance/repo icin kullanilir.
- Runner token Ansible Vault veya CI secret olarak saklanir.
- Runner config ve token repo'ya commit edilmez.
## Runner Kullanicisi
Ansible `gitea_runner` role'u:
- `gitea-runner` sistem kullanicisi olusturur.
- Kullanici shell'i ihtiyaca gore `/bin/bash` olabilir.
- Kullanici Docker kullanacaksa `docker` grubuna eklenir.
- Home dizini: `/var/lib/gitea-runner`
- Config dizini: `/etc/gitea-act-runner`
Docker group root seviyesine yakin yetki verdigi icin bu karar bilincli kabul edilir.
## Runner Binary Kurulumu
Kurulum adimlari:
1. `act_runner` Linux amd64 binary indirilir.
2. `/usr/local/bin/act_runner` olarak yerlestirilir.
3. Executable permission verilir.
4. Config uretilir veya template ile yazilir.
5. Runner register edilir.
6. Systemd unit enabled + started edilir.
## Runner Label PolitikasI
Test runner label'lari:
```text
test-runner
iklim-app-01
ubuntu-24.04
docker
swarm-manager
```
Mevcut workflow'larda `runs-on` degeri test icin bu label'lardan biriyle uyumlu hale getirilmelidir. Eski `ubuntu-latest` kullanimi self-hosted Gitea runner eslesmesi icin yeterli olmayabilir; bu durum Gitea Actions label konfigurasyonuna gore netlestirilmelidir.
## Deploy On Kosullari
Test deploy pipeline'lari icin `iklim-app-01` uzerinde bulunmasi gerekenler:
- Docker Engine
- Docker Compose plugin
- Git
- curl
- jq
- gettext/envsubst
- tree
- ssh/scp client
- Harbor registry erisimi
- StorageBox erisimi
- Gitea reposuna erisim
- Swarm manager yetkisi
- `iklimco-net` overlay network
CI/CD DB altyapisini kurmayacak. Test DB node hazir olacak; DB yazilimi ve cluster/manual setup ayridir.
## Deploy Lock Notu
Test ortaminda tek runner oldugu icin runner'lar arasi deploy yarismasi beklenmez.
Yine de ayni branch'e arka arkaya push edilmesi veya manuel yeniden calistirma gibi
durumlarda ayni servis deploy'u ust uste binebilir.
Test icin lock zorunlu degildir; ancak prod ile ayni aliskanligi kazanmak istenirse
StorageBox uzerinde su path kullanilabilir:
```text
test/locks/test-deploy.lock
test/locks/services/<service-name>.lock
```
Lock manuel olusturulmaz. Workflow basinda atomik `mkdir`, bitiste `rmdir` kullanilir.
## Secret Gereksinimleri
Runner kurulumu ve pipeline calismasi icin secret'lar:
- Gitea runner registration token
- Harbor username/password veya token
- StorageBox SSH key (priv + pub)
- SSH deploy key
- Hetzner token gerekmez; Terraform asamasinda kullanilir
Bu secret'lar repo'ya yazilmayacak.
## Gitea Organizasyon Secret'lari
Gitea → `git.tarla.io` → Organization → **Settings****Actions****Secrets** altina eklenir.
| Secret | Aciklama | Kaynak |
| --- | --- | --- | | --- | --- | --- |
| `STORAGEBOX_SSH_PRIV` | StorageBox erisimi icin private SSH key | Her sunucuda `/root/.ssh/id_ed25519_storagebox` | | `iklim-app-01` | `gitea-act-runner` | `test-runner`, `iklim-app-01`, `docker` |
| `STORAGEBOX_SSH_PUB` | Eslesen public key | Her sunucuda `/root/.ssh/id_ed25519_storagebox.pub` |
| `REPO_ACCESS_TOKEN` | Pipeline'in Gitea API'sini cagirabileceği token | Gitea → User Settings → Applications → Access Tokens |
Workflow'da kullanim ornegi: ## 1. Runner Kullanıcısı ve Yetkiler
```yaml Runner, host üzerinde Docker komutlarını çalıştırabilmelidir.
- name: Set up StorageBox SSH key
run: |
mkdir -p ~/.ssh
echo "${{ secrets.STORAGEBOX_SSH_PRIV }}" > ~/.ssh/id_ed25519_storagebox
echo "${{ secrets.STORAGEBOX_SSH_PUB }}" > ~/.ssh/id_ed25519_storagebox.pub
chmod 600 ~/.ssh/id_ed25519_storagebox
ssh-keyscan -p 23 u469968-sub1.your-storagebox.de >> ~/.ssh/known_hosts
```
### Ansible Vault Secret'lari
CI/CD disindaki secret'lar `ansible/group_vars/test-vault.yml` icinde Ansible Vault ile sifrelenir:
```bash ```bash
ansible-vault edit ansible/group_vars/test-vault.yml # Kullanıcıyı oluştur
sudo useradd -m -s /bin/bash gitea-runner
# Docker grubuna ekle
sudo usermod -aG docker gitea-runner
``` ```
Icerik: ## 2. act_runner Kurulumu
```yaml ### Binary İndirme
vault_storagebox_password: "SUB_ACCOUNT_PAROLASI" ```bash
vault_gitea_runner_token: "RUNNER_REGISTRATION_TOKEN" wget -O act_runner https://dl.gitea.com/act_runner/0.2.10/act_runner-0.2.10-linux-amd64
sudo mv act_runner /usr/local/bin/
sudo chmod +x /usr/local/bin/act_runner
``` ```
### Kayıt (Registration)
Gitea arayüzünden (Organization -> Settings -> Actions -> Runners) bir **Registration Token** alın.
```bash
# Config dosyasını oluştur
act_runner generate-config > config.yaml
# Kayıt işlemini gerçekleştir
act_runner register --instance https://git.tarla.io --token <TOKEN> --no-interactive
```
*Not: Kayıt sırasında label olarak `test-runner,iklim-app-01,docker` girildiğinden emin olun.*
## 3. Systemd Servisi
`/etc/systemd/system/gitea-act-runner.service` dosyasını oluşturun:
```ini
[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
WorkingDirectory=/var/lib/gitea-runner
User=gitea-runner
Group=gitea-runner
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
```
Servisi başlatın:
```bash
sudo systemctl daemon-reload
sudo systemctl enable --now gitea-act-runner
```
## 4. Deploy Ön Koşulları
Pipeline'ın `iklim-app-01` üzerinde başarılı deploy yapabilmesi için şu araçların kurulu olması şarttır:
- `docker-ce` ve `docker-compose-plugin`
- `gettext` (`envsubst` komutu için)
- `jq`
- `git`
## 5. Gitea Organization Secrets
Pipeline'ların çalışması için Gitea Organization seviyesinde şu secret'lar tanımlanmalıdır:
| Secret | Açıklama |
| --- | --- |
| `STORAGEBOX_SSH_PRIV` | StorageBox'a erişim için private key |
| `HARBOR_USERNAME` | Container registry kullanıcı adı |
| `HARBOR_PASSWORD` | Container registry şifresi |
## Kabul Kriterleri ## Kabul Kriterleri
- `systemctl status gitea-act-runner` active gorunur. 1. Gitea Runners sayfasında `iklim-app-01` statusü **Idle** (yeşil) görünür.
- Gitea UI icinde test runner online gorunur. 2. Bir test workflow'u (`runs-on: test-runner`) başarıyla tetiklenir.
- Runner label'lari test workflow `runs-on` ile eslesir. 3. Runner, host üzerindeki Docker daemon'a erişip konteyner oluşturabilir.
- Basit bir test workflow runner uzerinde calisir. 4. `8200/tcp` (Vault) portu public internete kapalıdır.
- Runner job'u Docker komutu calistirabiliyorsa deploy on kosulu saglanmistir.
- `8200/tcp` public internete acik degildir.

View File

@ -1,4 +1,4 @@
# 04 - Prod Terraform IaC # 06 - Prod Terraform IaC
Bu asamanin amaci prod Hetzner Cloud Project icinde HA odakli IaaS kaynaklarini Terraform ile olusturmaktir. Bu dokuman prod Terraform ajanina tek basina verilebilir. Bu asamanin amaci prod Hetzner Cloud Project icinde HA odakli IaaS kaynaklarini Terraform ile olusturmaktir. Bu dokuman prod Terraform ajanina tek basina verilebilir.
@ -29,6 +29,13 @@ Terraform prod ortaminda sunlari olusturur:
DB cluster yazilimi Terraform ile kurulmayacak. DB node'lari sadece makine, network ve firewall seviyesinde hazirlanacak. DB cluster yazilimi Terraform ile kurulmayacak. DB node'lari sadece makine, network ve firewall seviyesinde hazirlanacak.
## Versiyon Gereksinimleri
```text
Terraform >= 1.6
hcloud provider ~> 1.49
```
## Onerilen Dosya Yapisi ## Onerilen Dosya Yapisi
```text ```text
@ -174,11 +181,16 @@ DB subnet kaynakli (`iklim-db-*` node'lari Swarm'a worker olarak katildigi icin)
### DB Firewall — Private Ingress ### DB Firewall — Private Ingress
Admin erisimi:
| Port | Servis | Kaynak |
| --- | --- | --- |
| `22/tcp` | SSH | `admin_allowed_cidrs` |
App subnet kaynakli (`10.20.10.0/24`): App subnet kaynakli (`10.20.10.0/24`):
| Port | Servis | Not | | Port | Servis | Not |
| --- | --- | --- | | --- | --- | --- |
| `22/tcp` | SSH | `admin_allowed_cidrs` |
| `5432/tcp` | PostgreSQL (Patroni primary) | App subnet erisimi | | `5432/tcp` | PostgreSQL (Patroni primary) | App subnet erisimi |
| `27017/tcp` | MongoDB replica set endpoint | App subnet erisimi | | `27017/tcp` | MongoDB replica set endpoint | App subnet erisimi |
| `2377/tcp` | Docker Swarm control plane | App subnet icinden | | `2377/tcp` | Docker Swarm control plane | App subnet icinden |
@ -197,6 +209,24 @@ DB subnet icindeki karsilikli erisim (`10.20.20.0/24`):
IP kisitlamasi Hetzner firewall'da degil, SWAG nginx konfigurasyonunda yapilir. IP kisitlamasi Hetzner firewall'da degil, SWAG nginx konfigurasyonunda yapilir.
## Outputs
`terraform apply` veya `terraform output` sonrasi asagidaki degerler alinabilir:
| Output | Aciklama |
| --- | --- |
| `ansible_inventory_yaml` | Ansible inventory YAML — `ansible/inventory/generated/prod.yml` dosyasina yazilir |
| `prod_private_ips` | Tum node'larin private IP haritasi (`swarm` ve `db` alt anahtarlari) |
| `prod_public_ips` | Tum node'larin public IPv4 haritasi |
| `prod_floating_ip` | Swarm giris noktasi icin Floating IP adresi (DNS A kaydi bu IP'ye yonlendirilir) |
Ansible inventory cikarmak icin:
```bash
terraform output -raw ansible_inventory_yaml > \
../../ansible/inventory/generated/prod.yml
```
## Lifecycle ve Resize Politikasi ## Lifecycle ve Resize Politikasi
### server_type Degisikligi (Yeniden Boyutlandirma) ### server_type Degisikligi (Yeniden Boyutlandirma)
@ -232,6 +262,78 @@ ayri resource tanimlanir:
Her sunucuya `lifecycle { prevent_destroy = true }` eklenir. Kasitli silmek icin Her sunucuya `lifecycle { prevent_destroy = true }` eklenir. Kasitli silmek icin
once lifecycle blogunu gecici olarak kaldir. once lifecycle blogunu gecici olarak kaldir.
## Nasil Calistirilir
### Hazirlik
**1. tfvars olustur (bir kere):**
```bash
cd Environment_Infrastructure/terraform/hetzner/prod
cp terraform.tfvars.example terraform.tfvars
# terraform.tfvars icerigini gercek degerlerle doldur
# (hcloud_token, admin_allowed_cidrs, vb.)
```
`terraform.tfvars` commit edilmez — `.gitignore` ile korunur.
**2. Provider yukle (bir kere):**
```bash
terraform init
```
### Ilk Uygulama
```bash
# Nelerin olusacagini goster — bozma yapma
terraform plan
# Onayla ve olustur
terraform apply
```
`apply` sonrasi 6 sunucu, 2 firewall, 1 floating IP ve network kaynaklari Hetzner'da gorunur.
### Ansible Inventory Alma
```bash
terraform output -raw ansible_inventory_yaml > \
../../ansible/inventory/generated/prod.yml
```
### Resize (Server Type Degistirme)
`terraform.tfvars` icinde `server_type_swarm` veya `server_type_db` degerini degistir:
```bash
terraform apply
```
Sunucu durdurulur, Hetzner Resize API cagirilir, yeniden baslatilir. Disk ve Docker volumes korunur. Downtime olur.
### Sunucu Silme (Zorla)
`prevent_destroy = true` oldugu icin normal `terraform destroy` hata verir. Once `servers.tf` icindeki `lifecycle` blogunu gecici kaldir:
```hcl
# lifecycle {
# prevent_destroy = true
# }
```
Sonra:
```bash
terraform destroy -target=hcloud_server.swarm["iklim-app-01"]
```
Islemi tamamladiktan sonra lifecycle blogunu geri ekle.
### State Yonetimi
Simdilik local state kullanilmaktadir (`terraform.tfstate`). State dosyasi repo'ya commit edilmez. Ekipte birden fazla kisi calisiyorsa Hetzner Object Storage veya HCP Terraform remote state kullanilmalidir.
## Kabul Kriterleri ## Kabul Kriterleri
- `terraform plan` sadece prod Hetzner Project token'i ile calisir. - `terraform plan` sadece prod Hetzner Project token'i ile calisir.

View File

@ -1,6 +1,71 @@
# 05 - Prod Ansible Bootstrap # 07 - Prod Ansible Bootstrap
Bu asamanin amaci Terraform ile olusturulan prod makinelerini Linux, security hardening, Docker ve Swarm acisindan hazir hale getirmektir. DB cluster yazilimi manuel kurulacaktir; bu playbook DB node'larinda sadece OS ve temel guvenlik hazirligini yapar. Bu aşamanın amacı Terraform ile oluşturulan prod makinelerini Linux, security hardening, Docker ve Swarm açısından hazır hale getirmektir. DB cluster yazılımı bu playbook tarafından kurulmaz; ancak DB node'ları Swarm'a worker olarak katılır.
## Ansible Kurulumu
Ansible, kontrol makinesinde (kendi bilgisayarınızda) yüklü olmalıdır. Hedef sunuculara herhangi bir ajan kurulmaz, sadece SSH erişimi yeterlidir.
### İşletim Sistemine Göre Kurulum
- **Ubuntu / Debian:**
```bash
sudo apt update
sudo apt install -y pipx python3-venv
pipx ensurepath
export PATH="$HOME/.local/bin:$PATH"
pipx install --include-deps ansible
```
- **Fedora / Rocky Linux / RHEL:**
```bash
sudo dnf install -y pipx python3-virtualenv
pipx ensurepath
export PATH="$HOME/.local/bin:$PATH"
pipx install --include-deps ansible
```
- **macOS (Homebrew):**
```bash
brew install ansible
```
- **Python Pip ile (Her platformda):**
```bash
pipx install --include-deps ansible
```
### Kurulumun Doğrulanması
Hangi yöntemle kurarsanız kurun, kurulumun başarılı olduğunu doğrulamak için aşağıdaki komutları kullanın:
```bash
# Ansible versiyonunu ve yapılandırma yollarını kontrol edin
ansible --version
# Ansible binarysinin hangi konumdan çalıştığını kontrol edin
which -a ansible
```
## Ansible Komutlarını Çalıştırma
Tüm komutlar projenin `ansible/` dizini altından çalıştırılmalıdır.
### 1. Bağlantı Testi (Ping)
Sunuculara erişimi doğrulamak için:
```bash
ansible -i inventory/generated/prod.yml all -m ping
```
### 2. Bootstrap Playbook'unu Çalıştırma
Tüm rolleri (base, hardening, docker, swarm vb.) uygulamak için:
```bash
ansible-playbook -i inventory/generated/prod.yml playbooks/prod-bootstrap.yml --ask-vault-pass
```
## Hedef Makineler ## Hedef Makineler
@ -13,18 +78,18 @@ Bu asamanin amaci Terraform ile olusturulan prod makinelerini Linux, security ha
| `iklim-db-02` | Manuel DB cluster node | | `iklim-db-02` | Manuel DB cluster node |
| `iklim-db-03` | Manuel DB cluster node | | `iklim-db-03` | Manuel DB cluster node |
## Onerilen Dosya Yapisi ## Önerilen Dosya Yapısı
```text ```text
ansible/ ansible/
ansible.cfg prod/
inventory/ ansible.cfg
generated/ inventory/
generated/
prod.yml
group_vars/
all.yml
prod.yml prod.yml
group_vars/
all.yml
prod.yml
playbooks/
prod-bootstrap.yml prod-bootstrap.yml
roles/ roles/
base/ base/
@ -32,15 +97,16 @@ ansible/
docker/ docker/
swarm/ swarm/
node_dirs/ node_dirs/
storagebox/
``` ```
## Base Role ## Base Role
Tum prod node'larina uygulanir: Tüm prod node'larına uygulanır:
- Paket cache update - Paket cache update
- Temel paketler (sirasıyla kurulur): - Temel paketler (sırasıyla kurulur):
- `epel-release` — fail2ban ve davfs2 bu repo'dan gelir; once kurulur - `epel-release` — fail2ban ve davfs2 bu repo'dan gelir; önce kurulur
- `curl` - `curl`
- `wget` - `wget`
- `git` - `git`
@ -48,7 +114,7 @@ Tum prod node'larina uygulanir:
- `tar` - `tar`
- `unzip` - `unzip`
- `bash-completion` - `bash-completion`
- `gettext` — envsubst icin; CI/CD deploy pipeline'larinda gerekli - `gettext` — envsubst için; CI/CD deploy pipeline'larında gerekli
- `tree` - `tree`
- `ca-certificates` - `ca-certificates`
- `fail2ban` - `fail2ban`
@ -56,30 +122,32 @@ Tum prod node'larina uygulanir:
- `chrony` - `chrony`
- `python3` - `python3`
- `python3-pip` - `python3-pip`
- `htop` — interaktif proses izleme (EPEL)
- `btop` — kaynak monitörü, grafik arayüz (EPEL)
- timezone: `Europe/Istanbul` - timezone: `Europe/Istanbul`
- hostname ayari - hostname ayarı
- chrony/NTP aktif - chrony/NTP aktif
## Security Hardening Role ## Security Hardening Role
Tum prod node'larina uygulanir: Tüm prod node'larına uygulanır:
- SSH password auth kapatilir. - SSH password auth kapatılır.
- Root SSH login kapatilir. - Root SSH login kapatılır.
- Sadece SSH key auth kalir. - Sadece SSH key auth kalır.
- `PermitEmptyPasswords no` - `PermitEmptyPasswords no`
- `MaxAuthTries 3` - `MaxAuthTries 3`
- `fail2ban` aktif edilir. - `fail2ban` aktif edilir.
- `unattended-upgrades` aktif edilir. - `dnf-automatic` ile otomatik güvenlik güncelleştirmeleri aktif edilir.
- UFW default incoming deny, outgoing allow. - `firewalld` default: incoming deny (drop zone), outgoing allow.
- SSH sadece admin CIDR'dan acilir. - SSH sadece admin CIDR'dan açılır.
- DB portlari public acilmaz. - DB portları public açılmaz.
Hetzner Cloud Firewall asil perimeter kabul edilir. UFW host uzerinde ikinci savunma katmanidir. Hetzner Cloud Firewall asıl perimeter kabul edilir. firewalld host üzerinde ikinci savunma katmanıdır.
## Docker Role ## Docker Role
Sadece `iklim-app-*` node'larinda zorunludur. Tüm prod node'larında (hem app hem db) zorunludur. DB node'ları Swarm Worker olarak ağa dahil olacağı için Docker Engine her makinede kurulu olmalıdır.
Kurulacak paketler: Kurulacak paketler:
@ -89,61 +157,60 @@ Kurulacak paketler:
- `docker-buildx-plugin` - `docker-buildx-plugin`
- `docker-compose-plugin` - `docker-compose-plugin`
Kurulum resmi Docker apt repository uzerinden yapilacak. Convenience script kullanilmayacak. Kurulum resmi Docker dnf repository üzerinden yapılacak (`https://download.docker.com/linux/rhel/docker-ce.repo`).
DB node'larinda Docker zorunlu degildir. DB manuel kurulum stratejisi container tabanli olacaksa daha sonra ayri DB dokumaninda ele alinmalidir.
## Swarm Role ## Swarm Role
Prod Swarm 3 manager ile kurulacak: Prod Swarm 3 manager ile kurulacak:
1. `iklim-app-01` uzerinde `docker swarm init` 1. `iklim-app-01` üzerinde `docker swarm init` (Advertise/data path addr: `10.20.10.11`)
2. Advertise/data path addr: `10.20.10.11` 2. `iklim-app-02` ve `iklim-app-03` manager olarak join olur.
3. Manager join token alinir. 3. `iklim-db-01/02/03` worker olarak join olur.
4. `iklim-app-02` ve `iklim-app-03` manager olarak join olur. 4. Overlay network oluşturulur: `iklimco-net`
5. Overlay network olusturulur: 5. Node etiketleri:
- `iklimco-net` - `iklim-app-*` -> `type=service`
- driver: `overlay` - `iklim-db-*` -> `role=db`
- attachable: `true` 6. Tüm node'lar `AVAILABILITY=Active` kalır.
6. Tum 3 node `type=service` label'i ile isaretlenir:
```bash
for node in iklim-app-01 iklim-app-02 iklim-app-03; do
docker node update --label-add type=service "$node"
done
```
7. Hicbir node drain edilmez. 3 node da `AVAILABILITY=Active` kalir; hem manager hem app worker olarak calisir.
> DB node'lari (`iklim-db-*`) Swarm'a join ettirilmez. DB cluster ayri yonetilir.
## Node Directory Role ## Node Directory Role
Tum `iklim-app-*` node'larinda: Tüm `iklim-app-*` node'larında:
```text ```text
/opt/iklimco
/opt/iklimco/ssl /opt/iklimco/ssl
/opt/iklimco/init /opt/iklimco/init
/opt/iklimco/init/postgresql /opt/iklimco/stacks
/opt/iklimco/init/mongodb
``` ```
DB node'larinda manuel DB kurulumu icin: DB node'larında:
```text ```text
/opt/iklimco
/opt/iklimco/db /opt/iklimco/db
/opt/iklimco/backup /opt/iklimco/backup
``` ```
## StorageBox DAVFS Mount Role
Her node'a uygulanır (tüm `iklim-app-*` ve `iklim-db-*`).
### Prod Sub-Account
| Parametre | Değişken | Değer |
| --- | --- | --- |
| Ana hesap | `storagebox_account` | `u469968` |
| Sub-account | `storagebox_user` | `u469968-sub5` |
| WebDAV URL | `storagebox_url` | `https://u469968-sub5.your-storagebox.de/` |
| Mount point | `storagebox_mount_point` | `/mnt/storagebox` |
## StorageBox SSH Key Role
Her node'a uygulanır. Sunucu üzerinde ed25519 SSH anahtar çifti üretilir ve StorageBox ana hesabına yüklenir.
## Kabul Kriterleri ## Kabul Kriterleri
- `ansible -i inventory/generated/prod.yml all -m ping` basarili olur. - `ansible -i inventory/generated/prod.yml all -m ping` başarılı olur.
- 3 Swarm node `docker node ls` icinde manager olarak gorunur; hepsi `AVAILABILITY=Active`. - 3 Swarm manager node `docker node ls` içinde Leader/Reachable görünür.
- Manager quorum saglanir (3 manager, 1 kayip tolere edilir). - 3 DB node `docker node ls` içinde Worker olarak görünür.
- `iklimco-net` overlay network vardir. - Manager quorum sağlanır (3 manager, 1 kayıp tolere edilir).
- `docker node inspect iklim-app-01 --format '{{.Spec.Labels}}'` ciktisi `map[type:service]` icerir. - `iklimco-net` overlay network vardır.
- DB node'lari `docker node ls` ciktisinda gorunmez. - Node etiketleri (`type=service`, `role=db`) inspect ile doğrulanır.
- Her node'da `/mnt/storagebox` mount edilmiştir.
- Public firewall sadece `22`, `80`, `443` ingress'e izin verir. - Public firewall sadece `22`, `80`, `443` ingress'e izin verir.
- DB node'lari public DB portu acmaz.
- DB yazilimi kurulumu bu playbook tarafindan yapilmaz.

View File

@ -1,4 +1,4 @@
# 09 - Prod DB Cluster Kurulumu (Swarm) # 08 - Prod DB Cluster Kurulumu (Swarm)
Bu aşamanın amacı üç DB node'unu Docker Swarm'a worker olarak eklemek, MongoDB replica set ve Patroni + etcd ile yönetilen PostgreSQL yüksek erişilebilirlik konfigürasyonunu yapmaktır. Bu aşamanın amacı üç DB node'unu Docker Swarm'a worker olarak eklemek, MongoDB replica set ve Patroni + etcd ile yönetilen PostgreSQL yüksek erişilebilirlik konfigürasyonunu yapmaktır.
@ -31,9 +31,9 @@ DB container'ları birbirlerini overlay DNS adıyla değil, **Hetzner private IP
## 1. Firewall Güncellemesi ## 1. Firewall Güncellemesi
`terraform/hetzner/prod/firewall.tf` dosyasına aşağıdaki kuralları ekle. `terraform/hetzner/prod/firewall.tf` dosyasında aşağıdaki kuralların mevcut olduğunu doğrula; eksik varsa ekle ve `terraform apply` çalıştır.
`hcloud_firewall.swarm` içine (DB subnet'ten Swarm portlarına): `hcloud_firewall.swarm` içinde (DB subnet'ten Swarm portlarına):
```hcl ```hcl
rule { rule {
@ -69,7 +69,7 @@ rule {
} }
``` ```
`hcloud_firewall.db` içine (app subnet'ten Swarm portlarına + overlay; DB subnet içi etcd/Patroni trafiği): `hcloud_firewall.db` içinde (app subnet'ten Swarm portlarına + overlay; DB subnet içi etcd/Patroni trafiği):
```hcl ```hcl
rule { rule {
@ -131,6 +131,7 @@ rule {
```bash ```bash
cd terraform/hetzner/prod cd terraform/hetzner/prod
terraform plan
terraform apply terraform apply
``` ```

View File

@ -1,4 +1,4 @@
# 06 - Prod Runner HA ve Swarm Deploy Modeli # 09 - Prod Runner HA ve Swarm Deploy Modeli
Bu asamanin amaci prod ortaminda Gitea Actions runner'lari HA calisacak sekilde kurmak ve Swarm uzerinde servislerin 3 node'a dagitilmasina uygun on kosullari tanimlamaktir. Bu asamanin amaci prod ortaminda Gitea Actions runner'lari HA calisacak sekilde kurmak ve Swarm uzerinde servislerin 3 node'a dagitilmasina uygun on kosullari tanimlamaktir.