diff --git a/README.md b/README.md index dbc7dca..46b6791 100644 --- a/README.md +++ b/README.md @@ -20,13 +20,13 @@ HTTP API control-api. | Документ | Для чего | |---|---| -| [docs/SETUP.md](docs/SETUP.md) | Развёртывание из готовых бинарников (`bin/`) или сборка из исходников, конфигурация, первый запуск стенда — с нуля | +| [docs/SETUP.md](docs/SETUP.md) | Развёртывание из готовых бинарников (`bin/`) или сборка из исходников, конфигурация, первый запуск стенда — с нуля, включая исчерпывающую инструкцию по Docker/docker-compose | | [docs/USAGE.md](docs/USAGE.md) | Повседневная работа: постановка адресов в очередь, наблюдение за статусом, разбор результатов | | [docs/API.md](docs/API.md) | Спецификация HTTP API control-api и примеры запросов (curl) | | [docs/DASHBOARD.md](docs/DASHBOARD.md) | Браузерная админ-панель (`admin-dashboard`) — то же самое API, но графически | | [docs/DIAGRAMS.md](docs/DIAGRAMS.md) | Диаграммы потоков данных: control plane, поток проверки до целевого сервера, поток телеметрии | | [docs/LOCAL_E2E.md](docs/LOCAL_E2E.md) | Полностью офлайн-прогон всей системы одним скриптом — без реального облака и интернета | -| [deploy/docker/RUN.txt](deploy/docker/RUN.txt) | Сборка и запуск каждого компонента в Docker: команды `docker build`/`docker run`, переменные окружения | +| [deploy/docker/RUN.txt](deploy/docker/RUN.txt) | Краткая шпаргалка команд `docker build`/`docker run` по компонентам (без пояснений) — подробный пошаговый разбор, включая docker-compose, см. в [docs/SETUP.md](docs/SETUP.md#развёртывание-в-docker) | | [docs/CONTROL_DATA_PLANE.html](docs/CONTROL_DATA_PLANE.html) | Презентационные схемы control plane и data plane для микросервисного (docker-compose) деплоя — открыть в браузере | ## Быстрый старт (60 секунд, без OpenStack) @@ -61,8 +61,12 @@ curl -s http://:8080/api/v1/admin/status | python3 -m json.tool ## Развёртывание в Docker Все четыре компонента можно собрать и запустить как отдельные Docker-образы -вместо systemd-юнитов — Dockerfile'ы лежат в `deploy/docker/<компонент>/`, -полные команды сборки/запуска и список переменных окружения — в +вместо systemd-юнитов — Dockerfile'ы лежат в `deploy/docker/<компонент>/`. +Исчерпывающая пошаговая инструкция (docker-compose для одного хоста и для +распределённого по нескольким хостам стенда, точечный `docker build`/`docker +run` по компоненту, обновление образов, диагностика) — +[docs/SETUP.md → «Развёртывание в Docker»](docs/SETUP.md#развёртывание-в-docker); +краткая шпаргалка тех же команд — в [deploy/docker/RUN.txt](deploy/docker/RUN.txt). - `prober`, `validator-agent`, `admin-dashboard` — конфиг генерируется diff --git a/docs/SETUP.md b/docs/SETUP.md index 898369a..210c2de 100644 --- a/docs/SETUP.md +++ b/docs/SETUP.md @@ -8,6 +8,9 @@ нужно просто быстро посмотреть систему в работе без реального OpenStack — сразу переходите к разделу [«Быстрая проверка без OpenStack»](#быстрая-проверка-без-openstack-offline-режим). +Ниже описано развёртывание как systemd-юнитами (по умолчанию), так и +Docker-контейнерами — оба пути равноправны и описаны исчерпывающе, см. +[«Развёртывание в Docker»](#развёртывание-в-docker). ## Содержание @@ -22,6 +25,13 @@ - [Развёртывание validator-agent на ВМ-валидаторах](#развёртывание-validator-agent-на-вм-валидаторах) - [Развёртывание prober на внешних площадках](#развёртывание-prober-на-внешних-площадках) - [Развёртывание admin-dashboard](#развёртывание-admin-dashboard) +- [Развёртывание в Docker](#развёртывание-в-docker) + - [Требования для Docker-развёртывания](#требования-для-docker-развёртывания) + - [Вариант 1: docker compose, один хост (знакомство/dev, mock-режим)](#вариант-1-docker-compose-один-хост-знакомстводev-mock-режим) + - [Вариант 2: docker compose, реальный стенд по нескольким хостам](#вариант-2-docker-compose-реальный-стенд-по-нескольким-хостам) + - [Вариант 3: docker build/docker run по одному компоненту](#вариант-3-docker-builddocker-run-по-одному-компоненту) + - [Обновление образов после изменения кода](#обновление-образов-после-изменения-кода) + - [Диагностика Docker-развёртывания](#диагностика-docker-развёртывания) - [Проверка после запуска](#проверка-после-запуска) - [Сетевые доступы](#сетевые-доступы) @@ -380,6 +390,349 @@ journalctl -u admin-dashboard -f страницах и о том, что дашборд может (и не может) — в [DASHBOARD.md](DASHBOARD.md). +## Развёртывание в Docker + +Альтернатива всем systemd-разделам выше — те же четыре бинарника, но +упакованные в Docker-образы. Не обязательно выбирать одно или другое — +можно, например, гонять `control-api` под systemd, а `prober` на внешней +площадке — в контейнере; главное, чтобы они видели друг друга по сети (см. +[«Сетевые доступы»](#сетевые-доступы)). + +Три способа запуска, по возрастанию гранулярности: + +1. **`docker compose`, один хост** — быстрее всего увидеть всё в работе + (mock-режим, без OpenStack). +2. **`docker compose`, несколько хостов** — реальный стенд, тот же compose + с профилями решает, какие сервисы поднимать на каждой машине. +3. **`docker build`/`docker run` по одному компоненту** — точечная отладка + одного сервиса без всего compose-стека. + +### Требования для Docker-развёртывания + +- Docker Engine и Compose plugin v2 (`docker compose version`; отдельная + утилита `docker-compose` v1 не поддерживается — команды ниже используют + синтаксис `docker compose ...`). +- Хост под управлением Docker — **linux/amd64** рекомендуется. На другой + архитектуре (например, Apple Silicon Mac) обязательно указывать + `--platform linux/amd64` при сборке/запуске (в `docker-compose.yml` он + уже прописан для каждого сервиса) — иначе получится образ, чей слой ОС + собран под архитектуру хоста, а внутри лежит скопированный amd64-бинарник + (см. ниже), и контейнер не запустится (`exec format error`). +- **Важное отличие от типичных Go-проектов: Dockerfile'ы здесь ничего не + компилируют.** `deploy/docker/<компонент>/Dockerfile` — это просто + `FROM alpine:3.20` + `COPY bin/<компонент> ...` (иногда плюс шаблон + конфига и `docker-entrypoint.sh` — см. ниже). Собственно Go-сборка + происходит заранее, отдельно от Docker (см. + [«Получение бинарников»](#получение-бинарников)) — то есть **перед + `docker build`/`docker compose build` в каталоге `bin/` уже должны лежать + актуальные бинарники под linux/amd64**: либо уже закоммиченные в + репозитории (вариант A — тогда просто `docker compose up -d --build` + сработает сразу), либо свежесобранные после правок кода (вариант B — + `go build ...`, см. [«Обновление образов после + изменения кода»](#обновление-образов-после-изменения-кода)). +- Все команды `docker build`/`docker compose build` запускаются из + каталога `deploy/docker/` (или с указанием контекста `../..`) — контекст + сборки каждого сервиса в `docker-compose.yml` это корень репозитория + (`context: ../..`), поэтому на каждом хосте, где вы собираете образы + локально, должен быть выкачан весь репозиторий (`git clone`), а не + только каталог `deploy/docker/`. + +### Вариант 1: docker compose, один хост (знакомство/dev, mock-режим) + +Самый быстрый способ увидеть всю систему целиком работающей — без +реального облака, все четыре сервиса на одной машине: + +```bash +cd deploy/docker +cp .env.example .env +cp control-api/control-api.docker.example.yaml control-api/control-api.docker.yaml +docker compose up -d --build +``` + +Что при этом происходит: + +- `docker-compose.yml` (общие определения сервисов) объединяется с + `docker-compose.override.yml` — dev-надстройка, которую `docker compose` + подхватывает **автоматически**, без явного `-f` (именно её в проде + заменяют на `docker-compose.prod.yml`, см. следующий раздел). +- `.env` (см. `.env.example`) выставляет `COMPOSE_PROFILES=control-plane, + dashboard,prober,validator` — включены все четыре профиля/сервиса сразу, + то есть весь стенд поднимается на одной машине. В реальном + распределённом развёртывании на каждом хосте включают только нужные + профили (см. вариант 2). +- `control-api.docker.yaml`, скопированный из + `control-api.docker.example.yaml`, — заранее заполненный конфиг с + `openstack.mode: "mock"` и тестовыми `validator_01`/`site-1`/тремя + IP-заглушками (`203.0.113.10-12`) — совпадает с дефолтами + `PROBER_SITE_ID`/`VALIDATOR_AGENT_VALIDATOR_ID` в `.env.example`, так что + `prober`/`validator-agent` сразу находят себя в конфиге control-api и + успешно регистрируются. Реального OpenStack и учётных данных для этого + режима не нужно. +- Dev-надстройка пробрасывает порты наружу (`8080` — control-api, `8090` — + admin-dashboard) и добавляет `depends_on: control-api: condition: + service_healthy` для `admin-dashboard`/`prober`/`validator-agent` — + они не пытаются зарегистрироваться раньше, чем `control-api` пройдёт + свой healthcheck (`GET /healthz`, настроен в базовом + `docker-compose.yml`). +- `-d` — фоновый режим; `--build` — собрать образы из `Dockerfile`, а не + пытаться скачать несуществующие в реестре. + +Проверить, что всё поднялось: + +```bash +docker compose ps +curl -s http://localhost:8080/healthz +curl -s http://localhost:8080/api/v1/admin/status | python3 -m json.tool +``` + +Открыть дашборд в браузере: `http://localhost:8090/`. + +Посмотреть логи (в т.ч. чтобы убедиться, что `prober`/`validator-agent` +успешно зарегистрировались): + +```bash +docker compose logs -f control-api +docker compose logs -f prober validator-agent admin-dashboard +``` + +Остановить: + +```bash +docker compose down # контейнеры + сеть; volume с БД (cloud-ip-validator-db) остаётся +docker compose down -v # то же самое + удалить volume с БД (полный сброс состояния) +``` + +### Вариант 2: docker compose, реальный стенд по нескольким хостам + +Та же пара файлов (`docker-compose.yml` + профили), но с +`docker-compose.prod.yml` вместо dev-надстройки и реальным конфигом +control-api вместо mock. `docker-compose.prod.yml` не публикует порты +наружу напрямую (стенд предполагается за reverse-proxy/файрволом) и не +использует `depends_on` (на разнесённом по хостам стенде профиль +`control-plane` может вообще отсутствовать в compose-вызове конкретного +хоста, и `depends_on` на неактивный профиль — ошибка конфигурации +`docker compose`); вместо этого у каждого сервиса `restart: +unless-stopped` — `prober`/`validator-agent` при недоступном на старте +`control-api` просто падают и перезапускаются политикой рестарта, пока +`control-api` не станет доступен. + +На каждом хосте — свой `.env.prod` (по образцу `.env.prod.example`) с +`COMPOSE_PROFILES`, задающим, какие сервисы именно этот хост поднимает: + +| Хост | `COMPOSE_PROFILES` | +|---|---| +| Управляющая машина (control-api + опционально дашборд) | `control-plane,dashboard` | +| Внешняя площадка (prober) | `prober` | +| ВМ-валидатор (validator-agent) | `validator` | +| Всё на одной машине (как вариант 1, но прод-режим) | `control-plane,dashboard,prober,validator` | + +**На управляющей машине** (`control-plane`/`dashboard`): + +```bash +git clone && cd /deploy/docker # если ещё не склонировано +cp .env.prod.example .env.prod +# отредактировать .env.prod: +# COMPOSE_PROFILES=control-plane,dashboard +# CONTROL_API_CONFIG_PATH=/etc/cloud-ip-validator/control-api.yaml (реальный конфиг, +# заполненный по образцу configs/control-api.example.yaml — см. +# "Подготовка конфигурации для реального стенда" выше) +# OS_AUTH_URL / OS_PROJECT_ID / OS_REGION_NAME / OS_TOKEN (или пароль-режим) — +# те же переменные, что и для systemd-развёртывания, см. раздел 2 выше +# ADMIN_DASHBOARD_CONTROL_API_URL=http://control-api:8080 (тот же docker-сеть, +# менять не нужно, если admin-dashboard в том же compose-вызове) + +docker compose -f docker-compose.yml -f docker-compose.prod.yml --env-file .env.prod up -d --build +``` + +Конфиг control-api при этом **монтируется файлом** (путь из +`CONTROL_API_CONFIG_PATH`), а не генерируется из переменных окружения, как +у остальных трёх компонентов — у него в конфиге списки (`validators`, +`sites`, `targets`, `ip_addresses`), которые не выразить одной +переменной. Данные (`control-api.db`) живут в volume `cloud-ip-validator-db` +— переживают `docker compose down` (без `-v`) и пересоздание контейнера. + +**На каждой внешней площадке** (`prober`): + +```bash +git clone && cd /deploy/docker +cp .env.prod.example .env.prod +# COMPOSE_PROFILES=prober +# PROBER_SITE_ID= +# PROBER_CONTROL_API_URL=<реальный, сетевой доступный адрес control-api, +# НЕ http://control-api:8080 — тот хост есть только внутри compose-сети +# самой управляющей машины> + +docker compose -f docker-compose.yml -f docker-compose.prod.yml --env-file .env.prod up -d --build +``` + +**На каждой ВМ-валидаторе** (`validator`) — аналогично, с +`COMPOSE_PROFILES=validator`, `VALIDATOR_AGENT_VALIDATOR_ID` (должен +совпадать с `validators[].validator_id` в конфиге control-api) и +`VALIDATOR_AGENT_CONTROL_API_URL`. + +> Полный список переменных окружения для каждого сервиса, с дефолтами — +> см. таблицы в разделе [«Вариант 3»](#вариант-3-docker-builddocker-run-по-одному-компоненту) +> ниже или прямо в `docker-compose.yml`/`.env.prod.example`. + +### Вариант 3: docker build/docker run по одному компоненту + +Для точечной пересборки/перезапуска одного сервиса напрямую, без compose +— например, обновить только `prober` на одной площадке, не трогая +остальной стенд. Все команды — из корня репозитория. + +**prober:** + +```bash +docker build --platform linux/amd64 -t cloud-ip-validator-prober -f deploy/docker/prober/Dockerfile . + +docker run -d --platform linux/amd64 --cap-add NET_RAW --name prober \ + -e PROBER_SITE_ID= \ + -e PROBER_CONTROL_API_URL= \ + cloud-ip-validator-prober +``` + +| Переменная | Обязательна | По умолчанию | +|---|---|---| +| `PROBER_SITE_ID` | да | — (должен быть зарегистрирован в control-api, `PUT /api/v1/admin/config/sites/{index}`) | +| `PROBER_CONTROL_API_URL` | да | — | +| `PROBER_POLL_INTERVAL_SECONDS` | нет | `5` | +| `PROBER_TCP_TIMEOUT_SECONDS` | нет | `5` | +| `PROBER_ICMP_TIMEOUT_SECONDS` | нет | `5` | +| `PROBER_ICMP_COUNT` | нет | `3` | + +`--cap-add NET_RAW` обязателен — без него ICMP-проверки не заработают. + +**admin-dashboard:** + +```bash +docker build --platform linux/amd64 -t cloud-ip-validator-admin-dashboard -f deploy/docker/admin-dashboard/Dockerfile . + +docker run -d --platform linux/amd64 -p 8090:8090 --name admin-dashboard \ + -e ADMIN_DASHBOARD_CONTROL_API_URL= \ + cloud-ip-validator-admin-dashboard +``` + +| Переменная | Обязательна | По умолчанию | +|---|---|---| +| `ADMIN_DASHBOARD_CONTROL_API_URL` | да | — | +| `ADMIN_DASHBOARD_LISTEN_ADDR` | нет | `:8090` | +| `ADMIN_DASHBOARD_CONTROL_API_TIMEOUT_SECONDS` | нет | `10` | +| `ADMIN_DASHBOARD_LAST_COMPLETED_COUNT` | нет | `20` | +| `ADMIN_DASHBOARD_POLL_INTERVAL_SECONDS` | нет | `5` | + +**control-api:** + +```bash +docker build --platform linux/amd64 -t cloud-ip-validator-control-api -f deploy/docker/control-api/Dockerfile . + +docker run -d --platform linux/amd64 -p 8080:8080 --name control-api \ + -v /path/to/control-api.yaml:/etc/cloud-ip-validator/control-api.yaml:ro \ + -v cloud-ip-validator-db:/var/lib/cloud-ip-validator \ + -e OS_AUTH_URL= \ + -e OS_PROJECT_ID= \ + -e OS_REGION_NAME= \ + -e OS_TOKEN= \ + cloud-ip-validator-control-api +``` + +В отличие от остальных трёх компонентов, у control-api конфиг **не** +генерируется из переменных окружения — он содержит списки +(`validators`/`sites`/`targets`/`ip_addresses`) и имена переменных для +OpenStack-креденшлов, которые проще смонтировать файлом (по образцу +`configs/control-api.example.yaml`, см. +[«Подготовка конфигурации»](#подготовка-конфигурации-для-реального-стенда)). Сама +база данных — отдельным volume (`cloud-ip-validator-db`) для +персистентности между перезапусками контейнера. При `auth_method: +password` вместо `OS_TOKEN` передайте `OS_USERNAME`, +`OS_USER_DOMAIN_NAME`, `OS_PASSWORD`; для `openstack.mode: mock` +переменные OpenStack не нужны вовсе. + +**validator-agent:** + +```bash +docker build --platform linux/amd64 -t cloud-ip-validator-validator-agent -f deploy/docker/validator-agent/Dockerfile . + +docker run -d --platform linux/amd64 --cap-add NET_RAW --name validator-agent \ + -e VALIDATOR_AGENT_VALIDATOR_ID= \ + -e VALIDATOR_AGENT_CONTROL_API_URL= \ + cloud-ip-validator-validator-agent +``` + +| Переменная | Обязательна | По умолчанию | +|---|---|---| +| `VALIDATOR_AGENT_VALIDATOR_ID` | да | — (должен совпадать с `validators[].validator_id` в конфиге control-api) | +| `VALIDATOR_AGENT_CONTROL_API_URL` | да | — | +| `VALIDATOR_AGENT_POLL_INTERVAL_SECONDS` | нет | `5` | +| `VALIDATOR_AGENT_SELF_CHECK_TIMEOUT_SECONDS` | нет | `10` | +| `VALIDATOR_AGENT_HTTPS_TIMEOUT_SECONDS` | нет | `10` | +| `VALIDATOR_AGENT_ICMP_TIMEOUT_SECONDS` | нет | `5` | +| `VALIDATOR_AGENT_ICMP_COUNT` | нет | `3` | +| `VALIDATOR_AGENT_SSH_ENABLED` | нет | `false` | +| `VALIDATOR_AGENT_SSH_TIMEOUT_SECONDS` | нет | `5` | + +`--cap-add NET_RAW` обязателен для ICMP-проверок, как и у `prober`. +`self_check.ip_echo_urls` в переменные не вынесен — при отсутствии в +конфиге агент сам подставляет дефолт (`api.ipify.org`, `ifconfig.me`); +свой список задавайте через смонтированный конфиг вместо шаблона, если +нужно переопределить. + +### Обновление образов после изменения кода + +Как уже сказано в требованиях — образы ничего не компилируют, а копируют +`bin/<компонент>`. После правок кода: + +```bash +# 1. пересобрать бинарники (из корня репозитория) +export PATH=$PATH:/usr/local/go/bin +export CGO_ENABLED=0 GOOS=linux GOARCH=amd64 +go build -trimpath -ldflags="-s -w" -o bin/control-api ./cmd/control-api +go build -trimpath -ldflags="-s -w" -o bin/validator-agent ./cmd/validator-agent +go build -trimpath -ldflags="-s -w" -o bin/prober ./cmd/prober +go build -trimpath -ldflags="-s -w" -o bin/admin-dashboard ./cmd/admin-dashboard + +# 2. пересобрать и перезапустить образы — Docker сам заметит, что +# содержимое bin/ изменилось (COPY инвалидирует кэш слоя по хэшу +# файла), отдельный --no-cache не нужен +cd deploy/docker +docker compose up -d --build +``` + +Для варианта 3 (`docker build`/`docker run` вручную) — то же самое: шаг 1 +не меняется, дальше `docker build ...` (та же команда, что и при первой +сборке) и `docker rm -f <имя> && docker run ... ` (или `docker restart`, +если менялись только переменные окружения, а не сам бинарник/образ). + +### Диагностика Docker-развёртывания + +- **Контейнер сразу падает, в логах `exec format error`** — образ собран + не под ту архитектуру: пересоберите с явным `--platform linux/amd64` + (или, если хост реально не amd64 — соберите бинарники под нужную + архитектуру, `GOARCH=arm64` и т.д., см. + [«Вариант B: сборка из исходников»](#вариант-b-сборка-из-исходников), и + уберите `--platform`/`platform:` из образов). +- **`prober`/`validator-agent`/`admin-dashboard` не стартуют, пишут + `... is required`** — не задана обязательная переменная окружения + (`PROBER_SITE_ID`, `VALIDATOR_AGENT_VALIDATOR_ID`, + `ADMIN_DASHBOARD_CONTROL_API_URL`) — см. таблицы выше/`.env`. +- **`prober`/`validator-agent` в цикле рестартов** — обычно означает, что + `control-api` недоступен по указанному URL, либо `site_id`/ + `validator_id` не зарегистрирован в конфиге control-api. Смотрите + `docker compose logs -f <сервис>` — при ошибке регистрации процесс + завершается с ненулевым кодом и в dev/prod оверлеях перезапускается + политикой `restart`. +- **`docker compose config` ругается на `depends_on` для неактивного + профиля** — это специфика `docker-compose.override.yml` (dev): он + подходит только когда все четыре профиля включены на одном хосте. Для + разнесённого по хостам стенда используйте `docker-compose.prod.yml` (в + нём `depends_on` нет намеренно, см. [вариант 2](#вариант-2-docker-compose-реальный-стенд-по-нескольким-хостам)). +- **После `docker compose down -v` пропали данные** — `-v` удаляет и volume + с базой control-api (`cloud-ip-validator-db`); без `-v` volume + сохраняется между запусками. +- Общие команды диагностики: `docker compose ps`, `docker compose logs -f + [сервис]`, `docker compose exec control-api sh`, `curl -s + http://localhost:8080/healthz`. + ## Проверка после запуска После того как control-api, все валидаторы и все три пробера запущены: