feat(infra): update environment infrastructure configurations
- Synchronized environment-specific settings with the new isolated architecture. - Updated network and storage definitions to match the latest Swarm stack requirements. - Harmonized configuration templates for consistent cross-environment deployment.
This commit is contained in:
parent
c568e31515
commit
ff9837ec54
@ -16,7 +16,7 @@ storagebox_managed_directories:
|
||||
mode: "0755"
|
||||
|
||||
iklim_password: "{{ vault_iklim_password }}"
|
||||
act_runner_labels: "prod-runner,ubuntu-24.04,{{ inventory_hostname }}"
|
||||
act_runner_labels: "prod-runner:docker://catthehacker/ubuntu:act-22.04,ubuntu-24.04,{{ inventory_hostname }}"
|
||||
swarm_manager_ip: "10.20.10.11"
|
||||
mongodb_replset_name: "rs0"
|
||||
admin_allowed_cidrs: "78.187.87.109/32 95.70.151.248/32"
|
||||
|
||||
3
ansible/prod/group_vars/app/vars.yml
Normal file
3
ansible/prod/group_vars/app/vars.yml
Normal file
@ -0,0 +1,3 @@
|
||||
---
|
||||
storagebox_dir_mode: "0777"
|
||||
storagebox_file_mode: "0666"
|
||||
@ -1,5 +1,5 @@
|
||||
---
|
||||
act_runner_version: "0.2.12"
|
||||
act_runner_version: "0.6.1"
|
||||
act_runner_arch: "linux-amd64"
|
||||
act_runner_gitea_url: "https://git.tarla.io"
|
||||
act_runner_name: "{{ inventory_hostname }}"
|
||||
|
||||
@ -24,6 +24,8 @@
|
||||
mode: "0755"
|
||||
owner: root
|
||||
group: root
|
||||
force: true
|
||||
notify: restart act_runner
|
||||
|
||||
- name: Create act_runner config directory
|
||||
ansible.builtin.file:
|
||||
|
||||
@ -26,13 +26,12 @@ container:
|
||||
network: "iklimco-net"
|
||||
enable_ipv6: false
|
||||
privileged: false
|
||||
options: ""
|
||||
options: "-v /mnt/storagebox:/mnt/storagebox"
|
||||
workdir_parent: ""
|
||||
valid_volumes:
|
||||
- "/var/run/docker.sock"
|
||||
# docker_host set edilince act_runner socket'i tek seferlik mount eder ve
|
||||
# DOCKER_HOST env'ini job container'a iletir; options'daki manuel mount ile
|
||||
# çakışıp "Duplicate mount point" hatasına yol açmaz.
|
||||
- "/mnt/storagebox"
|
||||
# Docker 29.5.2 ile /var/run -> /run symlink kaynaklı "mkdirat var/run: file exists"
|
||||
# hatası giderildi; socket job container'lara mount edilebilir hale geldi.
|
||||
docker_host: "unix:///var/run/docker.sock"
|
||||
force_pull: false
|
||||
force_rebuild: false
|
||||
|
||||
@ -22,7 +22,7 @@
|
||||
- name: Add fstab entry for StorageBox
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/fstab
|
||||
line: "{{ storagebox_url }} {{ storagebox_mount_point }} davfs _netdev,auto,user,rw,uid={{ storagebox_uid | default('root') }},gid={{ storagebox_gid | default('root') }} 0 0"
|
||||
line: "{{ storagebox_url }} {{ storagebox_mount_point }} davfs _netdev,auto,user,rw,uid={{ storagebox_uid | default('root') }},gid={{ storagebox_gid | default('root') }}{% if storagebox_dir_mode is defined %},dir_mode={{ storagebox_dir_mode }}{% endif %}{% if storagebox_file_mode is defined %},file_mode={{ storagebox_file_mode }}{% endif %} 0 0"
|
||||
regexp: "^{{ storagebox_url | regex_escape() }}"
|
||||
state: present
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
path: "{{ storagebox_mount_point }}"
|
||||
src: "{{ storagebox_url }}"
|
||||
fstype: davfs
|
||||
opts: "_netdev,auto,user,rw,uid={{ storagebox_uid | default('root') }},gid={{ storagebox_gid | default('root') }}"
|
||||
opts: "_netdev,auto,user,rw,uid={{ storagebox_uid | default('root') }},gid={{ storagebox_gid | default('root') }}{% if storagebox_dir_mode is defined %},dir_mode={{ storagebox_dir_mode }}{% endif %}{% if storagebox_file_mode is defined %},file_mode={{ storagebox_file_mode }}{% endif %}"
|
||||
state: mounted
|
||||
|
||||
- name: Write mount marker
|
||||
|
||||
@ -6,37 +6,114 @@ Prod kurulum adımları ve mevcut yapı.
|
||||
|
||||
### 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.
|
||||
Test ve prod ayrı Hetzner Cloud projelerinde çalışır; her proje için ayrı API token kullanılır. `terraform.tfvars.example` dosyasından kopyalanarak doldurulur:
|
||||
|
||||
Prod sunucuları `lifecycle { prevent_destroy = true }` ile korunur.
|
||||
```hcl
|
||||
hcloud_token = "<iklim_prod proje token'ı>"
|
||||
location = "fsn1"
|
||||
image = "rocky-10"
|
||||
server_type_app = "cpx42"
|
||||
server_type_db = "cpx32"
|
||||
admin_ssh_public_key_path = "~/.ssh/id_rsa.pub"
|
||||
admin_allowed_cidrs = ["78.187.87.109/32", "95.70.151.248/32"]
|
||||
```
|
||||
|
||||
`admin_allowed_cidrs` Ansible `group_vars/all/vars.yml` ile birebir uyumlu olmalıdır. Prod sunucuları `lifecycle { prevent_destroy = true }` ile korunur.
|
||||
|
||||
### Apply
|
||||
|
||||
```bash
|
||||
cd Environment_Infrastructure/terraform/hetzner/prod
|
||||
terraform init
|
||||
terraform plan
|
||||
terraform apply
|
||||
```
|
||||
|
||||
### Inventory Üretimi
|
||||
|
||||
```bash
|
||||
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ı
|
||||
### ansible.cfg
|
||||
|
||||
`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:
|
||||
`roles_path = roles:../roles` ile prod'a özgü roller (`roles/`) yanı sıra ortak roller (`../roles/`) de kullanılır.
|
||||
|
||||
```yaml
|
||||
admin_allowed_cidrs: "78.187.87.109/32 95.70.151.248/32"
|
||||
admin_ssh_public_key_path: "~/.ssh/id_rsa.pub"
|
||||
```ini
|
||||
[defaults]
|
||||
inventory = inventory/generated/prod.yml
|
||||
remote_user = root
|
||||
host_key_checking = False
|
||||
retry_files_enabled = False
|
||||
interpreter_python = auto_silent
|
||||
roles_path = roles:../roles
|
||||
|
||||
[privilege_escalation]
|
||||
become = True
|
||||
become_method = sudo
|
||||
become_user = root
|
||||
become_ask_pass = False
|
||||
```
|
||||
|
||||
Hardening rolü `PermitRootLogin prohibit-password` uygular — key tabanlı root girişi açık, parola ile root girişi kapalıdır.
|
||||
### group_vars/all/vars.yml
|
||||
|
||||
`vault_iklim_password` per-host `host_vars/<hostname>/vault.yml` dosyalarında tanımlıdır, her sunucu farklı şifreye sahiptir:
|
||||
```yaml
|
||||
storagebox_account: "u469968"
|
||||
storagebox_user: "{{ storagebox_account }}-sub5"
|
||||
storagebox_url: "https://{{ storagebox_user }}.your-storagebox.de/"
|
||||
storagebox_mount_point: "/mnt/storagebox"
|
||||
storagebox_password: "{{ vault_storagebox_password }}"
|
||||
storagebox_managed_directories:
|
||||
- path: "{{ storagebox_mount_point }}/ssl"
|
||||
mode: "0755"
|
||||
- path: "{{ storagebox_mount_point }}/swag/config"
|
||||
mode: "0755"
|
||||
- path: "{{ storagebox_mount_point }}/swag/site-confs"
|
||||
mode: "0755"
|
||||
- path: "{{ storagebox_mount_point }}/grafana/data"
|
||||
mode: "0755"
|
||||
- path: "{{ storagebox_mount_point }}/precipitation/images"
|
||||
mode: "0755"
|
||||
|
||||
iklim_password: "{{ vault_iklim_password }}"
|
||||
act_runner_labels: "prod-runner,ubuntu-24.04,{{ inventory_hostname }}"
|
||||
swarm_manager_ip: "10.20.10.11"
|
||||
mongodb_replset_name: "rs0"
|
||||
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"
|
||||
```
|
||||
|
||||
`admin_allowed_cidrs` Terraform `terraform.tfvars` ile birebir uyumlu olmalıdır.
|
||||
|
||||
### group_vars/all/vault.yml
|
||||
|
||||
Ansible Vault ile şifrelidir. Tanımlaması gereken değişken:
|
||||
|
||||
```yaml
|
||||
vault_storagebox_password: "<storagebox-sub-user-parolası>"
|
||||
```
|
||||
|
||||
### group_vars/db/vars.yml
|
||||
|
||||
DB node'larında StorageBox `uid/gid=999` ile mount edilir (MongoDB ve PostgreSQL container user'ı ile uyumlu):
|
||||
|
||||
```yaml
|
||||
storagebox_uid: "999"
|
||||
storagebox_gid: "999"
|
||||
```
|
||||
|
||||
### host_vars — Per-Host Vault
|
||||
|
||||
`vault_iklim_password` her sunucu için ayrı `host_vars/<hostname>/vault.yml` dosyasında tanımlıdır. Hardening rolü bu değeri `iklim` OS kullanıcısının sistem parolası olarak uygular (`password_hash('sha512')`). Her sunucuya farklı parola verilebilir.
|
||||
|
||||
```text
|
||||
prod/
|
||||
host_vars/
|
||||
iklim-app-01/vault.yml
|
||||
iklim-app-01/vault.yml ← vault_iklim_password: "<iklim OS kullanıcısı parolası>"
|
||||
iklim-app-02/vault.yml
|
||||
iklim-app-03/vault.yml
|
||||
iklim-db-01/vault.yml
|
||||
@ -44,6 +121,10 @@ prod/
|
||||
iklim-db-03/vault.yml
|
||||
```
|
||||
|
||||
Her dosya ayrı şifrelenir: `ansible-vault encrypt host_vars/<hostname>/vault.yml`
|
||||
|
||||
Hardening rolü `PermitRootLogin prohibit-password` uygular — key tabanlı root girişi açık, parola ile kapalıdır.
|
||||
|
||||
### 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:
|
||||
@ -103,7 +184,7 @@ cd /home/iklim
|
||||
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 \
|
||||
scp -P 23 u469968@u469968.your-storagebox.de:prod/secrets/iklim.co/.env \
|
||||
/tmp/.env
|
||||
chmod 600 /tmp/.env
|
||||
|
||||
|
||||
@ -242,7 +242,7 @@ Insert **after** `Bootstrap SWAG Certificate` and **before** `Review Environment
|
||||
|
||||
> **Prod-specific:** DB hostnames are `postgresql` and `mongodb` (Swarm VIP service names).
|
||||
> Test pipeline uses `postgresql` / `mongodb` (unqualified aliases within the same stack).
|
||||
> SQL and JS files are generated by `Prepare Init Files` step via `init_postgresql` / `init_mongodb` functions in `common-functions.sh`.
|
||||
> SQL and JS files are generated by `Prepare Init Files` step via `init_postgresql` / `init_mongodb` functions in `common-functions-prod.sh`.
|
||||
> Step is idempotent — scripts use `CREATE IF NOT EXISTS` / `createCollection` semantics.
|
||||
|
||||
## Step 8 — Microservice prod deploy overlay
|
||||
|
||||
@ -93,9 +93,6 @@ For DNS automation, `PROD_FLOATING_IP` must be defined as a Gitea project variab
|
||||
Before the infra stack is deployed, the following Docker secrets must be created on `iklim-app-01`. These secrets are referenced by `docker-stack-infra.prod.yml`; if they do not exist, stack deploy fails.
|
||||
|
||||
```bash
|
||||
# Redis password, used by Redis master, replica, and sentinel:
|
||||
openssl rand -hex 32 | docker secret create redis_password -
|
||||
|
||||
# RabbitMQ Erlang cluster cookie; must be the same on all RabbitMQ nodes:
|
||||
openssl rand -hex 32 | docker secret create rabbitmq_erlang_cookie -
|
||||
```
|
||||
@ -108,7 +105,7 @@ Verify secrets:
|
||||
|
||||
```bash
|
||||
docker secret ls
|
||||
# redis_password and rabbitmq_erlang_cookie rows must appear
|
||||
# rabbitmq_erlang_cookie row must appear
|
||||
```
|
||||
|
||||
### SWAG Nginx Configuration Templates
|
||||
@ -198,7 +195,7 @@ All prod deploy workflows, including infra and microservices, must use the same
|
||||
| 3 | Set up SSH Key and Add to known_hosts | |
|
||||
| 4 | Update Apt Repository and Install Required Tools | `gettext tree jq` — `jq` is required for the GoDaddy DNS API |
|
||||
| 5 | Fetch Service Secret Files | Fetch `.env.secrets.*` from StorageBox |
|
||||
| 6 | Initialize Workspace | Fetch `.env` and `.env.secrets.shared` from StorageBox; run `init-base.sh` |
|
||||
| 6 | Initialize Workspace | Fetch `.env` and `.env.secrets.shared` from StorageBox; run `init-infra-dev.sh` |
|
||||
| 7 | Upload Updated Secrets to Storagebox | |
|
||||
| 8 | Provision Vault AppRole IDs and Docker Secrets | |
|
||||
| 9 | Upload Updated Env to Storagebox | |
|
||||
@ -325,7 +322,7 @@ PostgreSQL and MongoDB init scripts run through Swarm overlay DNS service names
|
||||
```
|
||||
|
||||
- `postgresql` and `mongodb`: Swarm VIP service names, resolved on the `iklimco-net` overlay; Patroni primary automatic routing happens at VIP level
|
||||
- SQL files `./init/postgresql/*.sql` and JS files `./init/mongodb/*.js` are created in the `Prepare Init Files` step by the `init_postgresql`/`init_mongodb` functions in `common-functions.sh`
|
||||
- SQL files `./init/postgresql/*.sql` and JS files `./init/mongodb/*.js` are created in the `Prepare Init Files` step by the `init_postgresql`/`init_mongodb` functions in `common-functions-prod.sh`
|
||||
- Idempotent: `CREATE IF NOT EXISTS` / `createCollection` semantics; runs safely again on later deploys
|
||||
|
||||
## Swarm Service Distribution
|
||||
@ -646,7 +643,7 @@ Expected: valid JSON weather response.
|
||||
- Public ingress is limited to only `22`, `80`, and `443`.
|
||||
- `prod/secrets/iklim.co/.env.secrets.swag` exists on StorageBox and contains valid GoDaddy credentials.
|
||||
- `PROD_FLOATING_IP` project variable is defined in Gitea.
|
||||
- `redis_password` and `rabbitmq_erlang_cookie` appear in `docker secret ls`.
|
||||
- `rabbitmq_erlang_cookie` appears in `docker secret ls`.
|
||||
- The `ssl`, `swag/config`, `swag/site-confs`, `grafana/data`, and `precipitation/images` directories exist on StorageBox; see `07-prod-ansible-bootstrap.md` — StorageBox Directory Structure.
|
||||
- The `swag/site-confs/default.conf`, `api.conf.tpl`, `apigw.conf.tpl`, `rabbitmq.conf.tpl`, and `grafana.conf.tpl` template files exist in the repo.
|
||||
- StorageBox `prod/secrets/iklim.co/.env.prod` has correct values for `API_SUBDOMAIN`, `APIGW_SUBDOMAIN`, `RABBITMQ_SUBDOMAIN`, `GRAFANA_SUBDOMAIN`, `RESTRICTED_IPS`, `SWAG_CERT_DIR`, `SWAG_CONFIG_DIR`, and `SWAG_SITE_CONFS_DIR`.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user