Add stop.sh (compose down) and disable print_forge (#34)
Sync runner checkout / sync (push) Successful in 6s

## Summary
- Closes [#33](#33).
- Add `scripts/stop.sh` → `playbooks/stop-apps.yml` → `docker compose down` for one `--app` + `--env` (no `-v`; checkouts/secrets stay).
- `host_apps.enabled: false` skips deploy (including CI `--app`) so a stopped app cannot come back. Rows stay for ports and `stop.sh`.
- Disable `print_forge` beta + prod on all app hosts. After merge (or from this branch): `./scripts/stop.sh --app print_forge --env prod` and `--env beta`.

## Test plan
- [ ] `./scripts/stop.sh --help` shows required `--app` / `--env`
- [ ] `ansible-playbook playbooks/stop-apps.yml --syntax-check -e app=print_forge -e app_env=prod`
- [ ] `./scripts/stop.sh --app print_forge --env prod` compose-downs `print_forge_prod` on all webservers
- [ ] `./scripts/stop.sh --app print_forge --env beta` compose-downs `print_forge_beta` (including adama worker)
- [ ] `./scripts/deploy.sh --app print_forge --env prod --check` skips disabled rows (does not start containers)
- [ ] NPM: `print-forge-preview.aimloperations.com` will 502 until the proxy host is disabled (out of scope)

Reviewed-on: #34
This commit was merged in pull request #34.
This commit is contained in:
2026-09-16 03:11:23 -07:00
parent 94fa05a952
commit 726ad971cb
15 changed files with 307 additions and 29 deletions
+38 -8
View File
@@ -30,6 +30,7 @@ flowchart TB
|----------|------|----------|---------------|
| **Provision** | New VM, OS change, firewall, Docker install | `site.yml` | ai-server-4080 — run manually |
| **Deploy** | Green unit tests on `master` | `deploy-apps.yml` | Gitea Act runner on ai-server-4080 |
| **Stop** | Take a compose app down | `stop-apps.yml` (`scripts/stop.sh`) | ai-server-4080 — run manually |
Both pipelines share the same inventory (`inventory/hosts.yml`).
@@ -65,7 +66,8 @@ server-infra/
│ └── ai-server-4080.yml # control node / act runner / SearxNG / observability
├── playbooks/
│ ├── site.yml # Phase 1: provision
── deploy-apps.yml # Phase 2: CI deploy
── deploy-apps.yml # Phase 2: CI deploy
│ └── stop-apps.yml # compose down one app+env
├── roles/
│ ├── common/ # Base packages
│ ├── ufw/ # Firewall
@@ -80,7 +82,8 @@ server-infra/
│ └── web-static/ # nginx container serving /var/www builds
└── scripts/
├── provision.sh # Wrapper with --limit support
── deploy.sh # Wrapper for deploy playbook
── deploy.sh # Wrapper for deploy playbook
└── stop.sh # Wrapper for stop playbook (compose down)
```
## Prerequisites (One-Time Bootstrap)
@@ -174,6 +177,18 @@ New hosts need the one-time passwordless sudo bootstrap in
./scripts/deploy.sh apollo
```
### Stop a compose app
```bash
./scripts/stop.sh --app print_forge --env prod
./scripts/stop.sh --app print_forge --env beta
./scripts/stop.sh adama --app chat_backend --env beta --check
```
`stop.sh` is `docker compose down` for one `--app` + `--env` (no `-v`). Checkouts and
secrets stay. Next `deploy.sh` of that app+env starts it again unless `host_apps`
sets `enabled: false`. Node-static apps have no compose project; stop.sh skips them.
Under the hood, scripts pass `--limit <hostname>` to `ansible-playbook`.
## Phase 1: Provision (`site.yml`)
@@ -218,7 +233,7 @@ After Docker install, re-SSH so the `docker` group membership takes effect.
| `monica_site` | django (docker) | all webservers | beta + prod | active/active behind NPM; no bundled Postgres (like `scha`); dj-queue **worker singleton on adama** only (`compose --profile worker`); Ollama social drafting via `10.0.0.128:11434` |
| `url_shortening_service` | django (docker) | all webservers | beta + prod | active/active behind NPM; no bundled Postgres; **no worker**. Two public hosts, same container: short domain (`GET /`, `GET /<code>` 302) and API host (`/api/links/`, Bearer required). |
| `college_craft` | django (docker) | all webservers | beta + prod | active/active behind NPM; no bundled Postgres (like `scha` / `monica_site`); dj-queue **worker singleton on adama** only (`compose --profile worker`); Ollama social drafting via `10.0.0.128:11434`; Nominatim `http://10.0.0.128:8089`; prod `SITE_UNDER_CONSTRUCTION=true` until launch |
| `print_forge` | django (docker) | all webservers | beta + prod | active/active behind NPM; no bundled Postgres (like `scha` / `monica_site` / `college_craft`); dj-queue **worker singleton on adama** only (`compose --profile worker`); Nominatim `http://10.0.0.128:8089`; prod `SITE_UNDER_CONSTRUCTION=true` until launch; prod NPM waits until launch |
| `print_forge` | django (docker) | all webservers | beta + prod | **stopped** (`enabled: false`, [#33](https://git.aimloperations.com/ai_ml_operations/server-infra/issues/33)). Ports reserved. Re-enable + `deploy.sh` to bring back. Worker was adama-only. |
| `abc_be` | django (docker) | all webservers | **beta only** | AI Benefits Coach API; no bundled Postgres; Ollama `http://10.0.0.128:11434`; shares DB `abc_be_beta` with `abc_worker` |
| `abc_worker` | django-type compose (FastAPI) | all webservers | **beta only** | same Postgres as `abc_be`; `migrate_cmd: true`; WS on host port 8018 |
| `abc_fe` | node-static (Vite) | all webservers | **beta only** | built to `/var/www/<env>.abc.aimloperations/html`; no prod `host_apps` row |
@@ -234,6 +249,8 @@ a DB.
- `host_apps` (`host_vars/<host>.yml`) — which app+env+port runs on that host.
Optional `compose_profiles: [worker]` activates docker compose profiles on that
host only (used for `monica_site` / `college_craft` / `print_forge` dj-queue singleton on adama).
Optional `enabled: false` skips deploy (CI included) but keeps the row for ports
and `stop.sh`. Omit the key (or `true`) to deploy as before.
- Django app = one compose project per env: project name `<app>_<env>`, host port from `host_apps`.
Ports match across app hosts so NPM can balance `adama:PORT` + `roslin:PORT` + `starbuck:PORT` + `apollo:PORT`.
@@ -252,7 +269,7 @@ future beta replica.
| monica_site | 8014 | 8004 | all webservers |
| url_shortening_service | 8015 | 8005 | all webservers |
| college_craft | 8016 | 8006 | all webservers |
| print_forge | **8019** | **8007** | all webservers |
| print_forge | **8019** (*stopped*) | **8007** (*stopped*) | all webservers (`enabled: false`) |
| abc_be | **8017** | 8009 (*not deployed*) | all webservers |
| abc_worker | **8018** | 8008 (*not deployed*) | all webservers |
| dta_webapp (nginx) | 8081 | 8080 | all webservers |
@@ -285,7 +302,16 @@ chat_backend secrets must use `SEARXNG_BASE_URL=http://10.0.0.128:8088`.
--app company_site --env prod --ref "${{ gitea.sha }}"
```
3. `deploy-apps.yml` runs against `webservers`; each host deploys only the
matching app+env from its `host_apps`.
matching **enabled** app+env from its `host_apps` (`enabled: false` is skipped).
To stop a compose app without deleting inventory:
```bash
./scripts/stop.sh --app print_forge --env prod
```
Set `enabled: false` on that `host_apps` row so the next CI deploy cannot start it
again. `stop.sh` still matches disabled rows.
### `app-deploy` role behavior
@@ -329,7 +355,7 @@ point each domain at the backend(s):
| url_shortening_service (short) | `aiml.pw` and/or `cidinn.li` (pick when DNS is ready); `short-beta.aimloperations.com` (beta). Proxy `/` + `/[a-z0-9]{4,8}` only — 404 `/api/`, `/admin/`, `/debug/` | `adama:8005` / `8015` + same on roslin / starbuck / apollo / ai-server-4080 |
| url_shortening_service (API) | `shortener.aimloperations.com`; `shortener-beta.aimloperations.com` (beta). Proxy `/api/` only — 404 `/admin/` | same ports as short host (one container) |
| college_craft | `collegecraft.com` (+ www); `college-craft-preview.aimloperations.com` (beta) | `adama:8006` / `8016` + same on roslin / starbuck / apollo / ai-server-4080 |
| print_forge | `printforgeprints.com` (+ www) — **do not NPM-route prod until launch**; `print-forge-preview.aimloperations.com` (beta) | `adama:8007` / `8019` + same on roslin / starbuck / apollo / ai-server-4080 |
| print_forge | `printforgeprints.com` (+ www); `print-forge-preview.aimloperations.com` (beta) — **app stopped** (`enabled: false`). Disable NPM hosts or expect 502. | `:8007` / `:8019` reserved |
| abc_fe | `beta.abc.aimloperations.com` (beta only) | `adama:8085` + same on roslin / starbuck / apollo / ai-server-4080 |
| abc_be | `beta.abc.be.aimloperations.com` (beta only) | `adama:8017` + same on roslin / starbuck / apollo / ai-server-4080 |
| abc_worker | `beta.abc.worker.aimloperations.com` (beta only; HTTP + WebSocket upgrade) | `adama:8018` + same on roslin / starbuck / apollo / ai-server-4080 |
@@ -406,7 +432,10 @@ App-repo companion (`college_craft`, not this repo): deploy workflows still call
`--app client_site` (template leftover). They must become `--app college_craft`
before CI deploy will hit this catalog entry. Default branch is `master` (not `main`).
`print_forge` extra env (control-node secrets, not in git):
`print_forge` extra env (control-node secrets, not in git) — **currently stopped**
([#33](https://git.aimloperations.com/ai_ml_operations/server-infra/issues/33)):
`host_apps` rows stay with `enabled: false`. Bring back with `enabled` removed/true
then `deploy.sh`. Secrets kept:
`~/Documents/secrets/print_forge/print_forge_prod.env` and
`print_forge_beta.env`. Template: app repo `.env.prod.example`.
`DJANGO_ENV` / `DJANGO_ALLOWED_HOSTS` / `DATABASE_URL` / `WEB_PORT` /
@@ -421,7 +450,8 @@ on beta. Default branch is `master`.
Companion app ticket: [print_forge#1](https://git.aimloperations.com/ai_ml_operations/print_forge/issues/1)
([#27](https://git.aimloperations.com/ai_ml_operations/server-infra/issues/27)).
App Gitea workflow deploys beta on push to `master` (`--app print_forge`).
App Gitea workflow still calls `--app print_forge` on `master`; deploy **no-ops**
while `enabled: false`.
`abc_be` / `abc_worker` / `abc_fe` (GIS org, not this repo) — **beta only** ([#26](https://git.aimloperations.com/ai_ml_operations/server-infra/issues/26)):