From 77ca0200aea9fc5135aa893632c8231238bff635 Mon Sep 17 00:00:00 2001 From: Vassiliy Yegorov Date: Sat, 4 Jul 2026 16:27:16 +0700 Subject: [PATCH] build: docker compose (app + postgres) with healthchecks and .env Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01BwxdSt4reTm7Dj1oxRvpP3 --- .env.example | 11 ++++++ Makefile | 13 +++++++ README.md | 92 ++++++++++++++++++++++++++++++++++++++++++++++ docker-compose.yml | 37 +++++++++++++++++++ 4 files changed, 153 insertions(+) create mode 100644 .env.example create mode 100644 README.md create mode 100644 docker-compose.yml diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..9412a05 --- /dev/null +++ b/.env.example @@ -0,0 +1,11 @@ +# PostgreSQL +POSTGRES_USER=dnsar +POSTGRES_PASSWORD=change-me-strong-password +POSTGRES_DB=dnsar + +# Порт публикации приложения на хосте +APP_PORT=8080 + +# Ключ шифрования секретов провайдеров/каналов — РОВНО 32 байта в base64. +# Сгенерировать: openssl rand -base64 32 +DNS_AR_ENC_KEY= diff --git a/Makefile b/Makefile index 2bf9af6..3031625 100644 --- a/Makefile +++ b/Makefile @@ -14,3 +14,16 @@ web: .PHONY: build-all build-all: web build + +.PHONY: docker-build docker-up docker-down docker-logs +docker-build: + docker build -t dns-autoresolver:local . + +docker-up: + docker compose up -d --build + +docker-down: + docker compose down + +docker-logs: + docker compose logs -f app diff --git a/README.md b/README.md new file mode 100644 index 0000000..dcb5cf7 --- /dev/null +++ b/README.md @@ -0,0 +1,92 @@ +# DNS Autoresolver + +Утилита автонастройки и проверки DNS-зон: multi-tenant сервис, который сверяет +фактическое состояние зоны у провайдера (Selectel DNS API v2) с шаблоном +записей, показывает диф и применяет изменения только вручную — никакого +автоматического apply без подтверждения оператора. + +## Возможности + +- **Multi-tenant**: проекты, аккаунты провайдера, домены — с авторизацией + (регистрация/логин, сессии). +- **Провайдер Selectel**: чтение зон/RRSet, диф против шаблона, ручной apply. +- **Шаблоны записей**: неймспейс-независимая модель `Record`, движок диффа + шаблон ↔ зона. +- **Диф + ручной apply**: изменения показываются перед применением, apply — + явное действие оператора. +- **Расписание проверок**: планировщик периодически гоняет read-only + check+notify (без Apply), пишет историю проверок и статус drift. +- **Уведомления**: каналы Telegram и Webhook, per-channel статус доставки. +- **Метрики**: Prometheus `/metrics` (публичный, без auth, только агрегаты). +- **Health-check**: `/healthz` — liveness-проба, используется как + Docker `HEALTHCHECK` через встроенный CLI-режим `app -healthcheck`. + +## Стек + +Go 1.26 (statically-linked бинарь, SPA встроена через `embed`), React + +Vite (SPA), PostgreSQL 17, Prometheus client, distroless/static-debian12 +рантайм-образ. + +## Запуск в Docker + +Требуется Docker Engine + Docker Compose v2. + +1. Скопировать пример конфигурации: + + ```bash + cp .env.example .env + ``` + +2. Сгенерировать ключ шифрования секретов (провайдеров/каналов) — ровно + 32 байта в base64 — и вписать его в `.env` как `DNS_AR_ENC_KEY`: + + ```bash + openssl rand -base64 32 + ``` + + Также задать `POSTGRES_PASSWORD` (без дефолта — сервис не поднимется без + явного пароля). + +3. Поднять стек (postgres + app), сборка образа приложения — на лету: + + ```bash + docker compose up -d --build + # или: make docker-up + ``` + + `app` стартует только после того, как `postgres` станет healthy; + миграции схемы БД приложение накатывает само при старте. + +4. Открыть UI: http://localhost:8080 + + - Метрики (Prometheus): http://localhost:8080/metrics + - Health-check: http://localhost:8080/healthz + +Остановить стек: `docker compose down` (или `make docker-down`). +Логи приложения: `docker compose logs -f app` (или `make docker-logs`). + +### Переменные окружения (`.env`) + +| Переменная | Назначение | По умолчанию | +|---------------------|----------------------------------------------------------|--------------| +| `POSTGRES_USER` | пользователь PostgreSQL | `dnsar` | +| `POSTGRES_PASSWORD` | пароль PostgreSQL — **обязателен**, без дефолта | — | +| `POSTGRES_DB` | имя БД | `dnsar` | +| `APP_PORT` | порт публикации приложения на хосте | `8080` | +| `DNS_AR_ENC_KEY` | ключ шифрования секретов, base64 → ровно 32 байта — **обязателен** | — | + +Секреты передаются только через переменные окружения, никогда — в образ, +логи или git. + +## Локальная разработка (без Docker) + +```bash +make build # go build ./... +make test # go test ./... +make web # сборка SPA (npm ci && npm run build) в internal/web/dist +make build-all # web + build +``` + +Для запуска бинаря напрямую нужны те же переменные окружения: +`DNS_AR_DB_DSN`, `DNS_AR_ENC_KEY` (обязательные), `DNS_AR_LISTEN` +(по умолчанию `:8080`). diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..d575c9f --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,37 @@ +services: + postgres: + image: postgres:17-alpine + environment: + POSTGRES_USER: ${POSTGRES_USER:-dnsar} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set in .env} + POSTGRES_DB: ${POSTGRES_DB:-dnsar} + volumes: + - pgdata:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-dnsar} -d ${POSTGRES_DB:-dnsar}"] + interval: 5s + timeout: 3s + retries: 10 + restart: unless-stopped + + app: + build: . + depends_on: + postgres: + condition: service_healthy + environment: + DNS_AR_DB_DSN: postgres://${POSTGRES_USER:-dnsar}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-dnsar}?sslmode=disable + DNS_AR_ENC_KEY: ${DNS_AR_ENC_KEY:?base64 32 bytes, see .env.example} + DNS_AR_LISTEN: ":8080" + ports: + - "${APP_PORT:-8080}:8080" + healthcheck: + test: ["CMD", "/app", "-healthcheck"] + interval: 10s + timeout: 4s + retries: 5 + start_period: 15s + restart: unless-stopped + +volumes: + pgdata: