# dev/staging стенд awg-dash — runbook Задача **#21** (эпик **#15**). Стенд для локальной разработки и проверки acceptance criteria до появления staging-окружения. * Docker-хост: **192.168.1.147** (`ssh root@192.168.1.147`), Docker 29.4.x + compose v5. * Каталог состояния: **`/opt/awg-dash-dev/{config,data}`** (bind mount → `/config`, `/data`). * Compose project: **`awg-dash-dev`** (изолирован от PoC-контейнеров `amneziawg-client`). * Хост-порт приложения: **8180** (`AWG_DASH_PORT`), внутри контейнера — **8080**. Порт 8080 на dev-хосте занят другим сервисом (drawio), поэтому проброс нестандартный. ## Быстрый старт ```bash # на Docker-хосте, из корня репозитория export AWG_DASH_HOST_DIR=/opt/awg-dash-dev make dev-up # docker compose up -d --build (проект awg-dash-dev) make dev-verify # проверка AC: health 200 + состояние переживает restart curl -fsS http://127.0.0.1:8180/api/v1/health make dev-logs # логи контейнера make dev-down # остановить (каталоги состояния сохраняются) ``` `dev-up` добавляет `--build`, когда в дереве есть `deploy/Dockerfile` (после мержа #18). Если у хоста нет сети/DNS для `docker build` (офлайн-стенд, CI без прокси), сборку нужно пропустить — образ `awg-dash:dev` уже должен существовать: ```bash make dev-up DEV_SKIP_BUILD=1 # up -d --no-build — использовать готовый образ make dev-up DEV_UP_BUILD= # вообще не передавать флаги сборки ``` До реализации FastAPI-каркаса (**#31**) `/api/v1/health` не отвечает — контейнер работает как агент и помечается `unhealthy`. Чтобы проверить плумбинг стенда (порт, healthcheck, тома, restart) **до** #31, используйте health-заглушку: ```bash make dev-up-stub # + deploy/docker-compose.stub.yml (DEV-ONLY, api_stub.py) make dev-verify-stub # AC-1 проходит на заглушке, в отчёте api=stub ``` Заглушка отвечает `{"status":"ok","stub":true,...}` только на `/api/v1/health` и никогда не должна использоваться в staging/prod. ## Проверка AC (#21) | AC | Команда | Ожидание | |---|---|---| | AC-1: health 200 | `curl -fsS -o /dev/null -w '%{http_code}' http://127.0.0.1:8180/api/v1/health` | `200` (после мержа #31; до него — заглушка через `dev-verify-stub`) | | AC-2: состояние переживает restart | `make dev-verify` | маркеры в `/config` и `/data` совпадают до и после `docker compose restart` и `--force-recreate` | | AC-3: netns + мок-endpoint | `make test-netns` | 8/8 тестов, netns `awgt21-{client,gw,uplink}` создаются и сносятся | `deploy/verify-dev-stand.sh` (за `make dev-verify`) печатает отчёт и возвращает: | Код | Значение | |---|---| | 0 | AC-1 и AC-2 выполнены | | 1 | регрессия стенда (health не 200 с заглушкой, состояние не сохранилось) | | 2 | AC-1 заблокирован: API (#31) ещё не реализован, стенд при этом поднят | | 3 | заблокировано окружением: нет docker/compose или compose-файлов | ## Состав стенда | Файл | Назначение | |---|---| | `docker-compose.dev.yml` | приложение: порт 8080 (наружу `${AWG_DASH_PORT:-8180}`), bind mount `/config` `/data`, healthcheck, NET_ADMIN/NET_RAW/SYS_MODULE, `/dev/net/tun` | | `docker-compose.stub.yml` | DEV-ONLY оверрайд: health-заглушка до #31 (`api_stub.py`) | | `docker-compose.test.yml` | тестовый стенд: привилегированный `netns`-раннер + `app` для API-тестов | | `api_stub.py` | минимальный HTTP-сервер `/api/v1/health` (только dev) | | `verify-dev-stand.sh` | проверка AC на Docker-хосте + JSON-отчёт | | `../tests/netns/` | netns-харнесс: топология client/gw/uplink + мок WireGuard-endpoint | ## Переменные окружения | Переменная | По умолчанию | Назначение | |---|---|---| | `AWG_DASH_PORT` | `8180` | хост-порт приложения | | `AWG_DASH_HOST_DIR` | `/opt/awg-dash-dev` | каталог состояния на хосте | | `AWG_DASH_IMAGE` | `awg-dash:dev` | имя образа (build или pull) | | `AWG_DASH_DOCKERFILE` | `deploy/Dockerfile` | путь к Dockerfile для build | | `COMPOSE_PROJECT_NAME` | `awg-dash-dev` | изоляция от других стендов | | `AWG_LOG_LEVEL` | `info` | уровень логирования приложения | | `DEV_SKIP_BUILD` | — | `1` → `make dev-up` выполняет `up -d --no-build` (образ уже собран) | | `DEV_UP_BUILD` | авто | переопределение флагов сборки (`--build`, пусто, `--no-build`) | | `AWG_NS_EXEC_MODE` | `auto` | режим входа в netns: `auto|ip|nsenter` (issue #56) | | `NETNS_EXEC_MODE` | `auto` | make-алиас `AWG_NS_EXEC_MODE` (приоритет у `AWG_NS_EXEC_MODE`) | ## Зависимости | Зависимость | Состояние | Влияние на стенд | |---|---|---| | #16 (каркас репо, Makefile) | PR #47 | нужен `Makefile`, `requirements.txt`, `deploy/` | | #18 (образ, entrypoint) | PR #49 | нужен `deploy/Dockerfile` для `--build` | | #31 (каркас FastAPI, `/api/v1/health`) | Sprint 2 | без него AC-1 выполняется только с заглушкой | | #17 (CI-пайплайн) | Sprint 0 | гейты для пайплайна: `bash tests/netns/ci.sh` (коды 0/1/3/4), `make test-manifests`, `make test-deploy`, `make lint-shell` | ## Откат и уборка ```bash make dev-down # остановить контейнеры проекта awg-dash-dev make dev-reset # down --remove-orphans (состояние сохраняется) docker image rm awg-dash:dev # откатить образ (пересобрать из предыдущего коммита) du -sh /opt/awg-dash-dev # состояние стенда ``` Перед откатом образа проверьте проект: `docker compose -p awg-dash-dev ls`. Состояние (`/opt/awg-dash-dev`) не удаляется автоматически — это осознанно: там конфиги туннеля (`/config/awg0.conf`). Удаляйте вручную и только после бэкапа. ## Pitfalls * **Порт 8080 занят** на dev-хосте — наружу публикуется 8180. Меняйте `AWG_DASH_PORT`. * **`/dev/net/tun` обязателен**: без него entrypoint падает (`fail '/dev/net/tun не проброшен'`). * **Права на каталоги состояния**: entrypoint делает `chown awg:awg /config /data`; каталоги создаются на хосте от root — не меняйте владельца на хосте вручную. * **`docker compose restart` сохраняет тома**; `down -v` — нет. Никогда не используйте `down -v` на этом стенде: это удалит `/config` и `/data`. * **Заглушка `api_stub.py`** — только dev: она отвечает 200 на `/api/v1/health` и маскирует отсутствие API. Не включайте `docker-compose.stub.yml` в staging. * **netns-стенд вне Docker** требует root: `make test-netns` вернёт код 3, если нет CAP_NET_ADMIN/CAP_SYS_ADMIN (например, в непривилегированном CI-раннере). * **netns в контейнере (`make test-netns-ci`, `bash tests/netns/ci.sh`)**: `ip netns exec` падает (`mount of /sys failed`), харнесс сам переходит на `nsenter`; контракт кодов `0/1/3/4` действует на уровне контейнера. **make возвращает 2 на любом провале** — в CI вызывайте `bash tests/netns/ci.sh`, иначе ветки 3 и 4 неразличимы (#56). * **`--build` без сети**: после мержа #18 `dev-up` собирает образ; если на хосте нет DNS/доступа к registry, используйте `DEV_SKIP_BUILD=1` (готовый `awg-dash:dev`).