Environment_Infrastructure/facts/prod-kurulum-gecmisi.md
Murat ÖZDEMİR c568e31515 Finalize production database bootstrap automation
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.
2026-05-21 21:48:11 +03:00

5.5 KiB
Raw Blame History

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