Sprint 0: multi-stage Dockerfile vpn-gateway (awg-tools + runtime alpine + супервизор) #18

Open
opened 2026-10-21 23:24:17 +03:00 by embeddevio · 2 comments
Owner

Owner: devops · Est: 5 SP · Priority: P0 · Sprint: 0 · Deps: —
Refs #15. Референс: Dockerfile из embeddevio/amneziawg-docker-gateway.

Что сделать

  • Multi-stage: builder на golang:alpine собирает amneziawg-go и amneziawg-tools (awg); runtime alpine:3.21.
  • Runtime-пакеты: iptables, ip6tables, iproute2, ipset, dnsmasq, curl, python3 + venv приложения.
  • Два пользователя: awg-agent (root, сеть/iptables/ipset/awg) и awg-api (непривилегированный, FastAPI+UI+статика); супервизор в deploy/entrypoint.sh запускает оба процесса и прокидывает unix-socket.
  • HEALTHCHECK на /api/v1/health; EXPOSE 8080; объявление VOLUME /config, /data.

Acceptance criteria

  • GIVEN собранный образ, WHEN docker run --rm image awg --version && ipset --version, THEN обе команды завершаются с кодом 0.
  • GIVEN манифест, WHEN docker inspect, THEN HEALTHCHECK задан и HEALTHCHECK не требует привилегий для /api/v1/health.
  • GIVEN образ, WHEN измерен размер, THEN ≤ 250 MB.
  • GIVEN контейнер без --cap-add=NET_ADMIN, WHEN стартует, THEN падает с явным сообщением о нехватке привилегий, а не с тихой ошибкой.

DoD

Тесты на новый код ≥ 70 %, CI green, PR с ревью владельца роли.

**Owner:** devops · **Est:** 5 SP · **Priority:** P0 · **Sprint:** 0 · **Deps:** — Refs #15. Референс: `Dockerfile` из `embeddevio/amneziawg-docker-gateway`. ### Что сделать - Multi-stage: builder на `golang:alpine` собирает `amneziawg-go` и `amneziawg-tools` (`awg`); runtime `alpine:3.21`. - Runtime-пакеты: iptables, ip6tables, iproute2, ipset, dnsmasq, curl, python3 + venv приложения. - Два пользователя: `awg-agent` (root, сеть/iptables/ipset/awg) и `awg-api` (непривилегированный, FastAPI+UI+статика); супервизор в `deploy/entrypoint.sh` запускает оба процесса и прокидывает unix-socket. - `HEALTHCHECK` на `/api/v1/health`; `EXPOSE 8080`; объявление VOLUME `/config`, `/data`. ### Acceptance criteria - GIVEN собранный образ, WHEN `docker run --rm image awg --version && ipset --version`, THEN обе команды завершаются с кодом 0. - GIVEN манифест, WHEN `docker inspect`, THEN HEALTHCHECK задан и `HEALTHCHECK` не требует привилегий для `/api/v1/health`. - GIVEN образ, WHEN измерен размер, THEN ≤ 250 MB. - GIVEN контейнер без `--cap-add=NET_ADMIN`, WHEN стартует, THEN падает с явным сообщением о нехватке привилегий, а не с тихой ошибкой. ### DoD Тесты на новый код ≥ 70 %, CI green, PR с ревью владельца роли.
embeddevio added this to the Sprint 0 — Фундамент: монорепо, CI, Docker-образ milestone 2026-10-21 23:24:17 +03:00
embeddevio added the devopsstatus/ready labels 2026-10-21 23:24:17 +03:00
Author
Owner

TechLead: артефакт готов в ветке feat/18-docker-runtime, PR #49 (3 файла, база main). Статус → status/review.

Состав: deploy/Dockerfile (multi-stage: golang builder → alpine runtime, venv, пользователь awg, VOLUME /config /data, HEALTHCHECK на /api/v1/health, tini), deploy/entrypoint.sh, deploy/awg0.conf.example.

Проверено:

  • deploy/entrypoint.sh — sh -n OK, dash -n OK; git-blob-sha1 файла в рабочей копии совпадает с blob в ветке (5fd7db…ac91), т.е. проверен именно закоммиченный байт-в-байт файл.
  • shellcheck в окружении агента отсутствует — статические проверки шире sh -n не выполнены.

НЕ проверено (блокирующее для закрытия задачи): сборка образа. На хосте TechLead-агента нет бинарника docker, поэтому AC #18 (awg --version, ipset --version, HEALTHCHECK в манифесте, размер ≤ 250 MB, падение без NET_ADMIN) не подтверждён. Требуется исполнение там, где есть Docker: CI runner (#17) или dev-стенд (#21).

Перед релизом ревизии amneziawg-go / amneziawg-tools из build-args нужно запинить на тег — учтено в #45.

**TechLead:** артефакт готов в ветке `feat/18-docker-runtime`, PR **#49** (3 файла, база `main`). Статус → `status/review`. Состав: `deploy/Dockerfile` (multi-stage: golang builder → alpine runtime, venv, пользователь `awg`, VOLUME /config /data, HEALTHCHECK на `/api/v1/health`, tini), `deploy/entrypoint.sh`, `deploy/awg0.conf.example`. **Проверено:** - `deploy/entrypoint.sh` — `sh -n` OK, `dash -n` OK; git-blob-sha1 файла в рабочей копии совпадает с blob в ветке (`5fd7db…ac91`), т.е. проверен именно закоммиченный байт-в-байт файл. - `shellcheck` в окружении агента отсутствует — статические проверки шире `sh -n` не выполнены. **НЕ проверено (блокирующее для закрытия задачи):** сборка образа. На хосте TechLead-агента нет бинарника `docker`, поэтому AC #18 (``awg --version``, ``ipset --version``, HEALTHCHECK в манифесте, размер ≤ 250 MB, падение без `NET_ADMIN`) не подтверждён. Требуется исполнение там, где есть Docker: CI runner (#17) или dev-стенд (#21). Перед релизом ревизии `amneziawg-go` / `amneziawg-tools` из build-args нужно запинить на тег — учтено в #45.
embeddevio added status/review and removed status/ready labels 2026-10-21 23:31:40 +03:00
Author
Owner

TechLead — AC #18 подтверждён на реальном Docker-хосте (192.168.1.147, Docker 29.4.1, сборка через SSH).

Контекст сборки = объединённое состояние PR #47 + PR #49 (main + каркас + deploy). Все 5 файлов сверены по git-blob-sha1 с деревьями веток (несоответствий нет).

Три дефекта, которые выявила именно сборка (исправлены в ветке feat/18-docker-runtime)

  1. GO_IMAGE=golang:1.23-alpine → go: go.mod requires go >= 1.25.0 (running go 1.23.12). Фикс: golang:1.25-alpine.
  2. В amneziawg-tools/src цель make собирает бинарь wg, а не awg → cp awg падало (can't stat 'awg'). Фикс: cp wg /usr/local/bin/awg (+ awg-quick при наличии).
  3. /etc/iproute2/rt_tables в Alpine отсутствует → запись таблицы 100 падала с can't create ... nonexistent directory. Фикс: mkdir -p /etc/iproute2 && touch ….

Результаты проверок

AC Команда Результат
сборка docker build -f deploy/Dockerfile BUILD3_EXIT=0, image sha256:47b38a6515…
размер ≤ 250 MB docker image ls 202 MB ✓
awg в образе --entrypoint awg awg --version amneziawg-tools v3.1.20260812, rc=0 ✓
ipset в образе --cap-add=NET_ADMIN --entrypoint ipset ipset --version ipset v7.22, rc=0 ✓
userspace fallback --entrypoint amneziawg-go --version amneziawg-go v3.1.20260828, rc=0 ✓
HEALTHCHECK docker inspect .Config.Healthcheck задан: CMD-SHELL curl -fsS .../api/v1/health, 30s/5s/20s/retries=3 ✓
без NET_ADMIN — явный отказ docker run --device=/dev/net/tun … FATAL: iptables недоступен: нужен --cap-add=NET_ADMIN, rc=1 ✓
с NET_ADMIN — preflight проходит --device=/dev/net/tun --cap-add=NET_ADMIN preflight ok, rt_tables пишется без ошибок, контейнер в ожидании (ждёт #22/#31)
python-окружение импорт fastapi в venv fastapi 0.159.0 ✓

Замечания для последующих задач

  • ipset --version без NET_ADMIN возвращает rc=1 (Kernel error: Operation not permitted) — в тестах вызывать только с NET_ADMIN.
  • net.ipv4.ip_forward в непривилегированном контейнере не включается — в runbook (#45) нужен --sysctl net.ipv4.ip_forward=1 или --privileged; предупреждение в entrypoint теперь прямо это говорит.
  • PR #49 standalone не собирается: в контексте нужны requirements.txt и backend/ из PR #47 → порядок мержа: #47 → #49.
  • Готовый образ остался на хосте: awg-dash:dev (202 MB, sha256:47b38a6515685f204db60d8d91f202beec5bf450fdde0bfd8fa40929d2cb0230) — пригодится для стенда #21.
  • Ревизии amneziawg-go/amneziawg-tools по-прежнему master → запинить на теги перед релизом (#45); версии, на которых проверено: tools v3.1.20260812, go v3.1.20260828.
**TechLead — AC #18 подтверждён на реальном Docker-хосте (192.168.1.147, Docker 29.4.1, сборка через SSH).** Контекст сборки = объединённое состояние PR #47 + PR #49 (main + каркас + deploy). Все 5 файлов сверены по git-blob-sha1 с деревьями веток (несоответствий нет). ### Три дефекта, которые выявила именно сборка (исправлены в ветке `feat/18-docker-runtime`) 1. `GO_IMAGE=golang:1.23-alpine` → `go: go.mod requires go >= 1.25.0 (running go 1.23.12)`. Фикс: `golang:1.25-alpine`. 2. В `amneziawg-tools/src` цель `make` собирает бинарь **`wg`**, а не `awg` → `cp awg` падало (`can't stat 'awg'`). Фикс: `cp wg /usr/local/bin/awg` (+ `awg-quick` при наличии). 3. `/etc/iproute2/rt_tables` в Alpine отсутствует → запись таблицы 100 падала с `can't create ... nonexistent directory`. Фикс: `mkdir -p /etc/iproute2 && touch …`. ### Результаты проверок | AC | Команда | Результат | |---|---|---| | сборка | `docker build -f deploy/Dockerfile` | `BUILD3_EXIT=0`, image `sha256:47b38a6515…` | | размер ≤ 250 MB | `docker image ls` | **202 MB** ✓ | | `awg` в образе | `--entrypoint awg awg --version` | `amneziawg-tools v3.1.20260812`, rc=0 ✓ | | `ipset` в образе | `--cap-add=NET_ADMIN --entrypoint ipset ipset --version` | `ipset v7.22`, rc=0 ✓ | | userspace fallback | `--entrypoint amneziawg-go --version` | `amneziawg-go v3.1.20260828`, rc=0 ✓ | | HEALTHCHECK | `docker inspect .Config.Healthcheck` | задан: `CMD-SHELL curl -fsS .../api/v1/health`, 30s/5s/20s/retries=3 ✓ | | без NET_ADMIN — явный отказ | `docker run --device=/dev/net/tun …` | `FATAL: iptables недоступен: нужен --cap-add=NET_ADMIN`, rc=1 ✓ | | с NET_ADMIN — preflight проходит | `--device=/dev/net/tun --cap-add=NET_ADMIN` | preflight ok, `rt_tables` пишется без ошибок, контейнер в ожидании (ждёт #22/#31) | | python-окружение | импорт fastapi в venv | `fastapi 0.159.0` ✓ | ### Замечания для последующих задач - `ipset --version` **без** NET_ADMIN возвращает rc=1 (`Kernel error: Operation not permitted`) — в тестах вызывать только с NET_ADMIN. - `net.ipv4.ip_forward` в непривилегированном контейнере не включается — в runbook (#45) нужен `--sysctl net.ipv4.ip_forward=1` или `--privileged`; предупреждение в entrypoint теперь прямо это говорит. - **PR #49 standalone не собирается**: в контексте нужны `requirements.txt` и `backend/` из PR #47 → порядок мержа: #47 → #49. - Готовый образ остался на хосте: `awg-dash:dev` (202 MB, `sha256:47b38a6515685f204db60d8d91f202beec5bf450fdde0bfd8fa40929d2cb0230`) — пригодится для стенда #21. - Ревизии `amneziawg-go`/`amneziawg-tools` по-прежнему `master` → запинить на теги перед релизом (#45); версии, на которых проверено: tools `v3.1.20260812`, go `v3.1.20260828`.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: embeddevio/awg-dash#18