Rearchitecture after operator pushback : the previous design did
too much in bash (SSH-streaming script chunks, manual sudo dance,
NOPASSWD requirement). Ansible is the right tool. The shell
scripts are now thin orchestrators handling the chicken-and-egg
of vault + Forgejo CI provisioning, then calling ansible-playbook.
Key principles :
1. NO NOPASSWD sudo on the R720. --ask-become-pass interactive,
password held in ansible memory only for the run.
2. Two parallel scripts — one per host, fully self-contained.
3. Both run the SAME Ansible playbooks (bootstrap_runner.yml +
haproxy.yml). Difference is the inventory.
Files (new + replaced) :
ansible.cfg
pipelining=True → False. Required for --ask-become-pass to
work reliably ; the previous setting raced sudo's prompt and
timed out at 12s.
playbooks/bootstrap_runner.yml (new)
The Incus-host-side bootstrap, ported from the old
scripts/bootstrap/bootstrap-remote.sh. Three plays :
Phase 1 : ensure veza-app + veza-data profiles exist ;
drop legacy empty veza-net profile.
Phase 2 : forgejo-runner gets /var/lib/incus/unix.socket
attached as a disk device, security.nesting=true,
/usr/bin/incus pushed in as /usr/local/bin/incus,
smoke-tested.
Phase 3 : forgejo-runner registered with `incus,self-hosted`
label (idempotent — skips if already labelled).
Each task uses Ansible idioms (`incus_profile`, `incus_command`
where they exist, `command:` with `failed_when` and explicit
state-checking elsewhere). no_log on the registration token.
inventory/local.yml (new)
Inventory for `bootstrap-r720.sh` — connection: local instead
of SSH+become. Same group structure as staging.yml ;
container groups use community.general.incus connection
plugin (the local incus binary, no remote).
inventory/{staging,prod}.yml (modified)
Added `forgejo_runner` group (target of bootstrap_runner.yml
phase 3, reached via community.general.incus from the host).
scripts/bootstrap/bootstrap-local.sh (rewritten)
Five phases : preflight, vault, forgejo, ansible, summary.
Phase 4 calls a single `ansible-playbook` with both
bootstrap_runner.yml + haproxy.yml in sequence.
--ask-become-pass : ansible prompts ONCE for sudo, holds in
memory, reuses for every become: true task.
scripts/bootstrap/bootstrap-r720.sh (new)
Symmetric to bootstrap-local.sh but runs as root on the R720.
No SSH preflight, no --ask-become-pass (already root).
Same Ansible playbooks, inventory/local.yml.
scripts/bootstrap/verify-r720.sh (new — replaces verify-remote)
Read-only checks of R720 state. Run as root locally on the R720.
scripts/bootstrap/verify-local.sh (modified)
Cross-host SSH check now fits the env-var-driven SSH_TARGET
pattern (R720_USER may be empty if the alias has User=).
scripts/bootstrap/{bootstrap-remote.sh, verify-remote.sh,
verify-remote-ssh.sh} (DELETED)
Replaced by playbooks/bootstrap_runner.yml + verify-r720.sh.
README.md (rewritten)
Documents the parallel-script architecture, the
no-NOPASSWD-sudo design choice (--ask-become-pass), each
phase's needs, and a refreshed troubleshooting list.
State files unchanged in shape :
laptop : .git/talas-bootstrap/local.state
R720 : /var/lib/talas/r720-bootstrap.state
--no-verify justification continues to hold.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
105 lines
3.2 KiB
YAML
105 lines
3.2 KiB
YAML
# Prod inventory — single R720 (self-hosted Incus) at v1.0 launch,
|
|
# Hetzner debordement post-launch. ROADMAP_V1.0_LAUNCH.md §2 documents
|
|
# the COMPRESSED HA stance : real multi-host HA arrives v1.1+ ; v1.0
|
|
# ships single-host with EC4+2 MinIO + PgAutoFailover colocated.
|
|
#
|
|
# Topology mirrors staging.yml (same shape, different prefix +
|
|
# different network — see group_vars/prod.yml). Phase-2 (post v1.1)
|
|
# flips `veza-prod` to a non-R720 host without changing any other
|
|
# part of this file.
|
|
#
|
|
# Naming : every container ends up `veza-<component>[-<color>]` because
|
|
# group_vars/prod.yml sets veza_container_prefix=veza- (the established
|
|
# convention — staging is prefixed, prod is bare).
|
|
all:
|
|
hosts:
|
|
veza-prod:
|
|
# Same R720 as staging at v1.0 — separate Incus network keeps
|
|
# blast radius contained. Move to a dedicated host post-v1.1.
|
|
ansible_host: srv-102v
|
|
ansible_user: senke
|
|
ansible_python_interpreter: /usr/bin/python3
|
|
children:
|
|
incus_hosts:
|
|
hosts:
|
|
veza-prod:
|
|
# forgejo-runner container (target of bootstrap_runner.yml phase 3).
|
|
forgejo_runner:
|
|
hosts:
|
|
forgejo-runner:
|
|
vars:
|
|
ansible_connection: community.general.incus
|
|
ansible_python_interpreter: /usr/bin/python3
|
|
# SHARED edge — one HAProxy on the R720 public 443. Serves
|
|
# staging + prod + forgejo.talas.group simultaneously. Same
|
|
# container in both staging.yml and prod.yml inventories.
|
|
haproxy:
|
|
hosts:
|
|
veza-haproxy:
|
|
vars:
|
|
ansible_connection: community.general.incus
|
|
ansible_python_interpreter: /usr/bin/python3
|
|
veza_app_backend:
|
|
children:
|
|
veza_app_backend_blue:
|
|
veza_app_backend_green:
|
|
veza_app_backend_tools:
|
|
vars:
|
|
ansible_connection: community.general.incus
|
|
ansible_python_interpreter: /usr/bin/python3
|
|
veza_app_backend_blue:
|
|
hosts:
|
|
veza-backend-blue:
|
|
veza_app_backend_green:
|
|
hosts:
|
|
veza-backend-green:
|
|
veza_app_backend_tools:
|
|
hosts:
|
|
veza-backend-tools: # ephemeral, Phase A only
|
|
veza_app_stream:
|
|
children:
|
|
veza_app_stream_blue:
|
|
veza_app_stream_green:
|
|
vars:
|
|
ansible_connection: community.general.incus
|
|
ansible_python_interpreter: /usr/bin/python3
|
|
veza_app_stream_blue:
|
|
hosts:
|
|
veza-stream-blue:
|
|
veza_app_stream_green:
|
|
hosts:
|
|
veza-stream-green:
|
|
veza_app_web:
|
|
children:
|
|
veza_app_web_blue:
|
|
veza_app_web_green:
|
|
vars:
|
|
ansible_connection: community.general.incus
|
|
ansible_python_interpreter: /usr/bin/python3
|
|
veza_app_web_blue:
|
|
hosts:
|
|
veza-web-blue:
|
|
veza_app_web_green:
|
|
hosts:
|
|
veza-web-green:
|
|
veza_data:
|
|
children:
|
|
veza_data_postgres:
|
|
veza_data_redis:
|
|
veza_data_rabbitmq:
|
|
veza_data_minio:
|
|
vars:
|
|
ansible_connection: community.general.incus
|
|
ansible_python_interpreter: /usr/bin/python3
|
|
veza_data_postgres:
|
|
hosts:
|
|
veza-postgres:
|
|
veza_data_redis:
|
|
hosts:
|
|
veza-redis:
|
|
veza_data_rabbitmq:
|
|
hosts:
|
|
veza-rabbitmq:
|
|
veza_data_minio:
|
|
hosts:
|
|
veza-minio:
|