Add DB-specific StorageBox ownership variables and make the davfs mount role honor configurable uid and gid values so database containers can access mounted files. Extend the prod DB node role to sync StorageBox writes, generate and distribute the MongoDB replica set keyfile, wait for the keyfile on each node, and enforce keyfile permissions. Tune MongoDB and Patroni templates for quieter logging, correct secret variable names, local bootstrap trust, and production network pg_hba coverage. Refresh the production setup history with the current bootstrap sequence, DB stack deployment workflow, MongoDB replica set initialization, Patroni validation, and completed DB cluster status.
5.5 KiB
Prod Ortamı Kurulum Geçmişi
Prod kurulum adımları ve mevcut yapı.
Terraform
Hetzner Cloud Yapılandırması
Test ve prod ayrı Hetzner Cloud projelerinde çalışır; her proje için ayrı API token kullanılır. terraform/hetzner/prod/terraform.tfvars içindeki hcloud_token değeri iklim_prod projesinin token'ına aittir.
Prod sunucuları lifecycle { prevent_destroy = true } ile korunur.
Inventory Üretimi
cd Environment_Infrastructure/terraform/hetzner/prod
mkdir -p ../../../ansible/prod/inventory/generated
terraform output -raw ansible_inventory_yaml > ../../../ansible/prod/inventory/generated/prod.yml
Ansible
Yapılandırma Notları
group_vars/all/vars.yml içindeki admin_allowed_cidrs tüm admin IP'lerini boşlukla ayrılmış string olarak içerir ve Terraform terraform.tfvars ile birebir uyumludur:
admin_allowed_cidrs: "78.187.87.109/32 95.70.151.248/32"
admin_ssh_public_key_path: "~/.ssh/id_rsa.pub"
Hardening rolü PermitRootLogin prohibit-password uygular — key tabanlı root girişi açık, parola ile root girişi kapalıdır.
vault_iklim_password per-host host_vars/<hostname>/vault.yml dosyalarında tanımlıdır, her sunucu farklı şifreye sahiptir:
prod/
host_vars/
iklim-app-01/vault.yml
iklim-app-02/vault.yml
iklim-app-03/vault.yml
iklim-db-01/vault.yml
iklim-db-02/vault.yml
iklim-db-03/vault.yml
StorageBox Mount
StorageBox WebDAV mount (/mnt/storagebox) davfs2 ile yapılır. DB node'larında uid=999,gid=999 parametreleriyle mount edilir (PostgreSQL/MongoDB container uid'i ile uyumlu). group_vars/db/vars.yml içinde tanımlanır:
storagebox_uid: "999"
storagebox_gid: "999"
Bootstrap Çalıştırma Sırası
cd Environment_Infrastructure/ansible/prod
# 1. Tüm node'lar — base, hardening, docker, dizinler, storagebox
ansible-playbook prod-bootstrap.yml \
--tags base,hardening,docker,node_dirs,storagebox,storagebox_ssh_key \
--vault-password-file=../.vault_pass
# 2. Swarm kurulumu
ansible-playbook prod-bootstrap.yml \
--tags swarm \
--vault-password-file=../.vault_pass
# 3. DB node label'ları
ansible-playbook prod-bootstrap.yml \
--tags db_labels \
--vault-password-file=../.vault_pass
# 4. DB node konfigürasyonu (StorageBox dizinleri, patroni.yml, mongod.conf, keyfile)
ansible-playbook prod-bootstrap.yml \
--tags db_stack \
--limit db \
--vault-password-file=../.vault_pass
# 5. Act runner kurulumu
ansible-playbook prod-bootstrap.yml \
--tags act_runner \
--vault-password-file=../.vault_pass
DB Stack Deploy
Custom Image Build
build/patroni-postgis/ altında PostGIS + Patroni imajı bulunur (registry.tarla.io/iklimco/custom-patroni-postgis:18-3.6). ops/push-harbor-custom-images.sh ile Harbor'a push edilir.
Stack Deploy
# Lokal → app-01
scp ./docker-stack-* root@178.104.210.41:/home/iklim/
# app-01'de
cd /home/iklim
# password; 'https://passwords.tarla.io' içinde "tarla.io›[Hetzner] Utils Server" klasörünün altında
scp -P 23 u469968@u469968.your-storagebox.de:prod/secrets/iklim.co/.env.secrets.shared \
/tmp/.env.secrets.shared
chmod 600 /tmp/.env.secrets.shared
scp -P 23 u469968@u469968.your-storagebox.de:prod/secrets/iklim.co/.env.secrets \
/tmp/.env
chmod 600 /tmp/.env
export $(grep -v '^\s*#' /tmp/.env.secrets.shared | grep -v '^\s*$' | xargs)
export $(grep -v '^\s*#' /tmp/.env | grep -v '^\s*$' | xargs)
docker stack deploy --with-registry-auth -c docker-stack-db.prod.yml iklim-db
# deploy başarılı bir şekilde tamamlanınca
rm /tmp/.env
rm /tmp/.env.secrets.shared
history -c && history -w
MongoDB Replica Set Init
ssh root@<db-01-ip>
# password; 'https://passwords.tarla.io' içinde "tarla.io›[Hetzner] Utils Server" klasörünün altında
scp -P 23 u469968@u469968.your-storagebox.de:prod/secrets/iklim.co/.env.secrets.shared \
/tmp/.env.secrets.shared
chmod 600 /tmp/.env.secrets.shared
scp -P 23 u469968@u469968.your-storagebox.de:prod/secrets/iklim.co/.env.secrets \
/tmp/.env
chmod 600 /tmp/.env
export $(grep -v '^\s*#' /tmp/.env.secrets.shared | grep -v '^\s*$' | xargs)
export $(grep -v '^\s*#' /tmp/.env | grep -v '^\s*$' | xargs)
MONGO_CID=$(docker ps --filter name=iklim-db_mongodb-01 --format "{{.ID}}" | head -1)
docker exec -it $MONGO_CID mongosh \
-u "$DATABASE_MONGODB_ROOT_USER" \
-p "$DATABASE_MONGODB_ROOT_PASSWD" \
--authenticationDatabase admin --eval '
rs.initiate({
_id: "rs0",
members: [
{ _id: 0, host: "mongodb-01:27017" },
{ _id: 1, host: "mongodb-02:27017" },
{ _id: 2, host: "mongodb-03:27017" }
]
})'
rm /tmp/.env
rm /tmp/.env.secrets.shared
history -c && history -w
Patroni Cluster Doğrulama
# app-01'den
curl -s http://10.20.20.11:8008/cluster | python3 -m json.tool
Mevcut Durum (2026-05-21)
| Adım | Durum |
|---|---|
| Terraform — 6 sunucu, ağ, firewall, floating IP | ✅ |
| Ansible base + hardening + docker + node_dirs | ✅ |
| Ansible storagebox + storagebox_ssh_key | ✅ |
| Ansible swarm (3 manager app + 3 worker db) | ✅ |
| Ansible db_labels | ✅ |
| Ansible db_stack (StorageBox DB dizinleri + config) | ✅ |
| Ansible act_runner (3 prod runner Gitea'da Idle) | ✅ |
| DB stack deploy (etcd + MongoDB + Patroni) | ✅ |
| MongoDB replica set init (rs0: 1 primary, 2 secondary) | ✅ |
| Patroni HA cluster (1 leader, 2 replica, lag=0) | ✅ |
| Ana infra stack deploy (docker-stack-infra.prod.yml) | ⏳ bekliyor |
| Deploy pipeline ilk çalışma | ⏳ bekliyor |