# Проверка dev/staging стенда (#21) — фактические прогоны на Docker-хосте Дата: 2026-10-22 · Хост: `192.168.1.147` (Debian 13, Docker 29.4.1, compose v5.1.3, kernel 6.17) Ветка: `feat/21-dev-stand`, HEAD `7af9caba` · Ref: #21, #15, #17, #18, #31 ## 0. Стенд запускает именно то, что в ветке Каталог стенда `(/opt/awg-dash-dev/repo)` не является git-чекаутом (`git clone` по HTTP обрывается на этом Gitea — `fetch-pack: invalid index-pack output`), поэтому файлы сверены побайтово через git-blob-SHA с деревом HEAD: | файл | git blob (HEAD == хост) | |---|---| | `Makefile` | `d13af0e752cb0dfc28e94ed1ad3a4ea448d58811` | | `deploy/docker-compose.dev.yml` | `6bed89a5ea2a197aa9f6fd6bcda6d8131303114d` | | `deploy/docker-compose.stub.yml` | `936efb38dfff4ba8b942c9757acd4ba9c39c4064` | | `deploy/docker-compose.test.yml` | `da01e80a459580cd063359c46560adb8285434d1` | | `deploy/verify-dev-stand.sh` | `c4e13f11f9023700be531ebb312ad33d7beea4d8` | | `deploy/api_stub.py` | `848922dc543a6a2abffa49c02efeba383f02455f` | | `tests/deploy/validate_compose.py` | `0fa8b3c02675a364f4f5b447220680a7818faa5a` | | `tests/netns/*` (10 файлов) | совпадают с деревом (см. `git ls-tree feat/21-dev-stand tests/netns`) | ## 1. Предварительные пакеты на стенд-хосте ```bash apt-get install -y make python3-yaml python3-pytest python3-pytest-cov shellcheck ``` (`make` на хосте отсутствовал — без него гейты `make *` невоспроизводимы; пакеты добавлены сверх существующего набора, ничего не удалялось и не переконфигурировалось.) ## 2. Гейты (реальные прогоны) Лог целиком: `/opt/awg-dash-dev/verify-final-1792617226.log` (на хосте). | гейт | команда | результат | |---|---|---| | манифесты | `make test-manifests` | exit 0, `validate-compose: ok (1 предупреждений)`¹ | | статический анализ шелла | `make lint-shell` | exit 0 | | unit-тесты манифестов | `python3 -m pytest tests/deploy -q --no-cov` | exit 0 | | netns-харнесс (AC-3) | `make test-netns` | exit 0, `8 ok / 0 fail / 0 err`, отчёт `/tmp/awg-netns/report.json` | | AC-1 (health 200) | `make dev-up` + `curl :8180/api/v1/health` | HTTP 200, контейнер `healthy` | | AC-2 (состояние переживает рестарт) | `make dev-verify` | `[ ok ] AC-1`, `[ ok ] AC-2` ×2, exit 0 | | логи | `make dev-logs` | стрим логов, есть `[api-stub] ... GET /api/v1/health 200` | ¹ предупреждение: `build.dockerfile deploy/Dockerfile отсутствует в дереве (ожидаемо до мержа #18)`. Образ `awg-dash:dev` для стенда собран из Dockerfile PR #49 (ветка `feat/18-docker-runtime`), в дерево этой ветки он не входит: `make build` вернёт внятную ошибку до мержа #18. Валидатор переключается в режим ошибки флагом `make test-manifests MANIFEST_ARGS=--require-dockerfile` — этот режим нужно включить в CI гейте после мержа #18. ### AC-1 — детали ``` $ make dev-up # (авто-режим: backend/awg_api/app.py отсутствует (#31) → + deploy/docker-compose.stub.yml) $ curl -s -w '\nHTTP=%{http_code}\n' http://127.0.0.1:8180/api/v1/health {"issue": "#31", "note": "заглушка dev-стенда: реальный API появится в #31", "status": "ok", "stub": true, "stub_env": "1", "uptime_s": 14.909} HTTP=200 $ docker ps --filter name=awg-dash-dev awg-dash-dev Up 15 seconds (healthy) 0.0.0.0:8180->8080/tcp, [::]:8180->8080/tcp ``` Почему с заглушкой: FastAPI-каркас (#31) ещё не реализован, сам образ HTTP не поднимает (entrypoint пишет `awg_api/app.py ещё не реализован` и ждёт). Чтобы AC-1 #21 проверялся на живом compose-стенде уже в Sprint 0, `make dev-up` добавляет оверрайд `docker-compose.stub.yml` **только пока `backend/awg_api/app.py` отсутствует**; ответ явно помечен `"stub": true`. После мержа #31 оверрайд не добавляется, `make dev-up` поднимает реальный API без правок Makefile. ### AC-2 — детали ``` $ make dev-verify [verify][ ok ] AC-1: http://127.0.0.1:8180/api/v1/health -> 200 (api=stub) [verify] AC-2: пишу маркеры в /config и /data и перезапускаю контейнер [verify][ ok ] AC-2: /config и /data пережили restart и пересоздание контейнера [verify][ ok ] AC-2: маркеры видны на хосте (/opt/awg-dash-dev/{config,data}) — это bind mount, а не слой контейнера $ ls /opt/awg-dash-dev/config /opt/awg-dash-dev/data /opt/awg-dash-dev/config/.ac2-marker (24 байта) /opt/awg-dash-dev/data/.ac2-marker (24 байта) ``` Проверяется два сценария: `docker compose restart` (как в AC) и `up -d --force-recreate` (сильнее). ### AC-3 (netns) — детали ``` [netns] создаю netns: client=awgt21-client gw=awgt21-gw uplink=awgt21-uplink [ ok ] стенд поднят: awgt21-client(10.213.0.2) -> awgt21-gw(10.213.0.1/10.214.0.1) -> awgt21-uplink(10.214.0.2) [ ok ] policy routing: fwmark 51820 -> table 51820 (default via 10.214.0.2) [ ok ] mock endpoint: udp/51820 в awgt21-uplink; детектор утечки: 198.51.100.9:9999/udp Ran 8 tests in 5.447s — OK test_01_namespaces_and_links ... test_08_killswitch_blocks_direct_egress — все ok [ ok ] топология снесена, namespace'ы удалены (ip netns list пусто) ``` `report.json`: `{"suite": "tests/netns", "tests": 8, "passed": 8, "failures": 0, "errors": 0, "skipped": 0, "returncode": 0, "duration_s": 5.447}` ## 3. Что чинилось в этой итерации | проблема | причина | правка | |---|---|---| | `make dev-up` давал `unhealthy` и AC-1 не выполнялся | API (#31) не реализован | `Makefile`: авто-подключение stub-оверрайда, пока нет `backend/awg_api/app.py`; `dev-up-app` / `dev-up-stub` для явных режимов | | `make dev-verify` печатал `[verify][fail] нет монтирования /config` при реально сохранённых томах и падал | `verify-dev-stand.sh` кэшировал id контейнера и делал `docker inspect` по нему после `--force-recreate` → `no such object` | перезапрос id (`cid()`) после пересоздания и явный `fatal_env` вместо ложного fail | | `dev-up` падал без `deploy/Dockerfile` (`--build`) | Dockerfile живёт в #18, ветка не смёржена | `--build` форсируется только при наличии `deploy/Dockerfile` | ## 4. Ограничения и что делать дальше 1. **CI-гейты (DoD) не автоматизированы:** Gitea Actions runner для `embeddevio/awg-dash` не зарегистрирован (см. отчёт в #17, run #1 остаётся `queued`). Все гейты в таблице §2 прогнаны **вручную** на стенд-хосте; после регистрации runner'а в #17 они переносятся в workflow без изменений команд. 2. **Порт:** на `192.168.1.147` хост-порт 8080 занят (`drawio`), поэтому стенд публикуется как `8180:8080` (контейнерный порт приложения — 8080, `AWG_DASH_PORT` переопределяет хост-порт). 3. **Сборка образа** — только после мержа #18; до этого образ `awg-dash:dev` собирается из ветки #18 вручную. 4. **Prod/staging:** stub-оверрайд и `deploy/api_stub.py` — DEV-ONLY. В staging/prod поднимается только `docker-compose.dev.yml` (или прод-манифест) без stub-файла. ## 5. Откат / очистка ```bash make dev-down # остановить стенд, каталоги /opt/awg-dash-dev/{config,data} сохраняются make dev-reset # + удалить осиротевшие контейнеры/сети проекта make test-netns # netns-харнесс сносит топологию сам; аварийно: bash tests/netns/topology.sh down ```