Переделать связь нод в кластере на автоматическое обнаружение #9

This commit is contained in:
2026-05-01 22:30:40 +03:00
parent 1787b0f8a3
commit f36dd3bbc1
25 changed files with 870 additions and 332 deletions

View File

@@ -0,0 +1,29 @@
# ============================================================
# Одноэтапный Dockerfile (сборка и рантайм в одном образе)
# ============================================================
FROM erlang:28-alpine
# Устанавливаем инструменты для сборки и runtime-зависимости
RUN apk add \
# для сборки
#git curl gcc
make musl-dev \
rust cargo openssl-dev libsodium-dev
#\
# для рантайма
#openssl libstdc++ libgcc ncurses-libs
# Рабочая директория
#RUN mkdir -p log/test/ct
# Копируем конфигурацию и исходники
COPY rebar.config ./
COPY include/ include/
COPY src/ src/
COPY test/api_SUITE.erl test/
COPY test/api/ test/api/
# Компилируем и запускаем тесты
RUN rebar3 compile
CMD rebar3 ct --sname ci_api_test -v

14
docker/build-images.sh Normal file
View File

@@ -0,0 +1,14 @@
# Основной образ EventHub (единственный для нод)
docker build -t eventhub:latest -f docker/Dockerfile .
# Сервис заглушка
docker build -t fallback:latest -f docker/fallback/Dockerfile docker/fallback
# Observer Web
docker build -t observer_web:latest -f docker/ObserverWeb.Dockerfile .
# Logrotate
docker build -t logrotate:latest -f docker/logrotate/Dockerfile docker/logrotate
# Admin UI из соседней папки EventHubFrontAdmin
docker build -t admin-ui:latest -f ../EventHubFrontAdmin/Dockerfile ../EventHubFrontAdmin

View File

@@ -0,0 +1,191 @@
# docker/docker-compose.swarm.yml
version: "3.8"
services:
# ================== Балансировщик ==================
traefik:
image: traefik:latest
command:
# - "--log.level=DEBUG"
- "--api.insecure=true"
- "--providers.docker=true"
# - "--providers.swarm.endpoint=unix:///var/run/docker.sock" # провайдер Swarm
- "--providers.docker.exposedbydefault=false"
- "--providers.file.filename=/etc/traefik/dynamic_conf.yml"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--metrics.prometheus=true"
- "--metrics.prometheus.buckets=0.1,0.3,1.2,5.0"
- "--metrics.prometheus.addEntryPointsLabels=true"
- "--metrics.prometheus.addServicesLabels=true"
- "--accesslog=true"
- "--accesslog.filepath=/var/log/traefik/access.log"
- "--accesslog.format=json"
- "--experimental.plugins.coraza.modulename=github.com/jcchavezs/coraza-http-wasm-traefik"
- "--experimental.plugins.coraza.version=v0.3.0"
ports:
- "80:80"
- "443:443"
- "8080:8080"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
- "./traefik/certs:/etc/traefik/certs:ro"
- "./traefik/dynamic_conf.yml:/etc/traefik/dynamic_conf.yml:ro"
- "traefik-logs:/var/log/traefik"
- "traefik-plugins:/plugins-storage"
networks:
- eventhub-net
deploy:
replicas: 1
restart_policy:
condition: any
# ================== Сервис заглушка ==================
fallback:
image: fallback:latest
networks:
- eventhub-net
deploy:
replicas: 0
restart_policy:
condition: any
# ================== Кластер EventHub ==================
eventhub:
image: eventhub:latest
hostname: "eventhub-node{{.Task.Slot}}"
environment:
- NODE_NAME=eventhub-node{{.Task.Slot}}
- RELEASE_COOKIE=${RELEASE_COOKIE:-eventhub_cookie}
- JWT_SECRET=${JWT_SECRET:-eventhub_top_secret}
- ADMIN_SUPER_EMAIL=${ADMIN_SUPER_EMAIL:-superadmin@eventhub.local}
- ADMIN_SUPER_PASSWORD=${ADMIN_SUPER_PASSWORD:-SuperAdmin123!}
- ADMIN_MODER_EMAIL=${ADMIN_MODER_EMAIL:-moderator@eventhub.local}
- ADMIN_MODER_PASSWORD=${ADMIN_MODER_PASSWORD:-Moderator123!}
- ADMIN_SUPPORT_EMAIL=${ADMIN_SUPPORT_EMAIL:-support@eventhub.local}
- ADMIN_SUPPORT_PASSWORD=${ADMIN_SUPPORT_PASSWORD:-Support123!}
networks:
eventhub-net:
aliases:
- eventhub-node
volumes:
- eventhub-data:/app/data
deploy:
replicas: 1
endpoint_mode: dnsrr
restart_policy:
condition: any
labels:
- "traefik.enable=true"
# ================== Admin UI ==================
admin-ui:
image: admin-ui:latest
networks:
- eventhub-net
deploy:
replicas: 0
restart_policy:
condition: any
labels:
- "traefik.enable=true"
# ================== Мониторинг ==================
prometheus:
image: prom/prometheus:latest
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
- '--web.console.libraries=/usr/share/prometheus/console_libraries'
- '--web.console.templates=/usr/share/prometheus/consoles'
- '--storage.tsdb.retention.time=30d'
- '--storage.tsdb.retention.size=15GB'
volumes:
- ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus-data:/prometheus
networks:
- eventhub-net
ports:
- "9090:9090"
deploy:
replicas: 0
restart_policy:
condition: any
grafana:
image: grafana/grafana:latest
environment:
- GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_ADMIN_PASSWORD}
- GF_SECURITY_DISABLE_INITIAL_ADMIN_PASSWORD_CHANGE=false
- GF_USERS_ALLOW_SIGN_UP=false
- GF_AUTH_ANONYMOUS_ENABLED=false
volumes:
- ./grafana/provisioning:/etc/grafana/provisioning
- ./grafana/dashboards:/etc/grafana/dashboards
- grafana-data:/var/lib/grafana
networks:
- eventhub-net
ports:
- "3000:3000"
deploy:
replicas: 0
restart_policy:
condition: any
# ================== Аналитика логов ==================
loglynx:
image: k0lin/loglynx:latest
user: root
ports:
- "6123:6123"
volumes:
- traefik-logs:/app/traefik/logs:ro
- loglynx-data:/app/data
environment:
- TRAEFIK_LOG_PATH=${TRAEFIK_LOG_PATH}
- SERVER_PORT=6123
- DATABASE_PATH=/app/data/loglynx.db
networks:
- eventhub-net
deploy:
replicas: 0
restart_policy:
condition: any
# ================== Инструмент отладки ==================
observer_web:
image: observer_web:latest
environment:
- RELEASE_COOKIE=${RELEASE_COOKIE}
networks:
- eventhub-net
ports:
- "4000:4000"
deploy:
replicas: 0
restart_policy:
condition: any
# ================== Ротация логов ==================
logrotate:
image: logrotate:latest
volumes:
- traefik-logs:/var/log/traefik:rw
networks:
- eventhub-net
deploy:
replicas: 0
restart_policy:
condition: any
networks:
eventhub-net:
driver: overlay
volumes:
eventhub-data:
prometheus-data:
grafana-data:
traefik-logs:
loglynx-data:
traefik-plugins:

View File

@@ -45,6 +45,7 @@ services:
networks:
- eventhub-net
restart: unless-stopped
profiles: ['ci']
# ================== Кластер EventHub (3 ноды) ==================
eventhub-node1:
@@ -56,9 +57,10 @@ services:
- NODE_NAME=eventhub-node1@eventhub-node1.local
- RELEASE_COOKIE=${RELEASE_COOKIE}
- JWT_SECRET=${JWT_SECRET}
- JOIN_NODES=eventhub-node1@eventhub-node1.local,eventhub-node2@eventhub-node2.local,eventhub-node3@eventhub-node3.local
networks:
- eventhub-net
eventhub-net:
aliases:
- eventhub-node # ← общий алиас для DNS-лукапа
volumes:
- eventhub-node1-data:/app/data
labels:
@@ -74,9 +76,10 @@ services:
- NODE_NAME=eventhub-node2@eventhub-node2.local
- RELEASE_COOKIE=${RELEASE_COOKIE}
- JWT_SECRET=${JWT_SECRET}
- JOIN_NODES=eventhub-node1@eventhub-node1.local,eventhub-node2@eventhub-node2.local,eventhub-node3@eventhub-node3.local
networks:
- eventhub-net
eventhub-net:
aliases:
- eventhub-node # ← общий алиас для DNS-лукапа
volumes:
- eventhub-node2-data:/app/data
labels:
@@ -92,9 +95,10 @@ services:
- NODE_NAME=eventhub-node3@eventhub-node3.local
- RELEASE_COOKIE=${RELEASE_COOKIE}
- JWT_SECRET=${JWT_SECRET}
- JOIN_NODES=eventhub-node1@eventhub-node1.local,eventhub-node2@eventhub-node2.local,eventhub-node3@eventhub-node3.local
networks:
- eventhub-net
eventhub-net:
aliases:
- eventhub-node # ← общий алиас для DNS-лукапа
volumes:
- eventhub-node3-data:/app/data
labels:
@@ -108,9 +112,11 @@ services:
dockerfile: Dockerfile
networks:
- eventhub-net
restart: unless-stopped
# restart: unless-stopped
restart: no
labels:
- "traefik.enable=true"
profiles: ['ui']
# ================== Мониторинг ==================
prometheus:
image: prom/prometheus:latest
@@ -129,6 +135,7 @@ services:
ports:
- "9090:9090"
restart: unless-stopped
profiles: ['ci']
grafana:
image: grafana/grafana:latest
@@ -146,6 +153,7 @@ services:
ports:
- "3000:3000"
restart: unless-stopped
profiles: ['ci']
# ================== Аналитика логов ==================
loglynx:
@@ -163,6 +171,7 @@ services:
- DATABASE_PATH=/app/data/loglynx.db
networks:
- eventhub-net
profiles: ['ci']
# ================== Инструмент отладки ==================
observer_web:
@@ -176,6 +185,7 @@ services:
ports:
- "4000:4000"
restart: unless-stopped
profiles: ['ci']
# ================== Ротация логов Traefik ==================
logrotate:
@@ -187,6 +197,7 @@ services:
networks:
- eventhub-net
restart: unless-stopped
profiles: ['ci']
networks:
eventhub-net:

View File

@@ -9,50 +9,58 @@ tls:
keyFile: /etc/traefik/certs/traefik.key
http:
serversTransports:
http1-ws-transport:
disableHTTP2: true
insecureSkipVerify: true
middlewares:
redirect-to-https:
redirectScheme:
scheme: https
permanent: true
strip-api-prefix:
stripPrefix:
prefixes:
- "/api"
waf:
plugin:
coraza:
directives:
# - "SecRuleEngine DetectionOnly" # можно раскомментировать для тестирования
- "SecRuleEngine On"
- "SecDebugLog /dev/stdout"
- "SecDebugLogLevel 2"
# - "SecRule REQUEST_URI \"@rx /admin\" \"id:101,phase:1,log,deny,status:403\""
- "SecRule ARGS \"@rx (union|select|insert|drop|alter)\" \"id:102,phase:2,log,deny,status:403\""
api-ratelimit:
rateLimit:
average: 100
average: 5000
period: 1m
burst: 50
burst: 500
admin-ratelimit:
rateLimit:
average: 20
average: 5000
period: 1m
burst: 5
burst: 500
routers:
# --- REST API пользователей ---
# Пользовательский REST API
api:
rule: "Host(`api.eventhub.local`)"
entryPoints: ["web"]
middlewares: ["redirect-to-https", "api-ratelimit", "waf"]
middlewares: ["redirect-to-https", "strip-api-prefix", "api-ratelimit", "waf"]
service: "api"
api-secure:
rule: "Host(`api.eventhub.local`)"
entryPoints: ["websecure"]
tls: true
middlewares: ["api-ratelimit", "waf"]
middlewares: ["strip-api-prefix", "api-ratelimit", "waf"]
service: "api"
# --- WebSocket пользователей (без WAF) ---
# Пользовательский WebSocket
ws:
rule: "Host(`ws.eventhub.local`)"
entryPoints: ["web"]
@@ -64,45 +72,56 @@ http:
tls: true
service: "ws"
# --- Админ-панель (SPA) ---
# Админский REST API
admin-api:
rule: "Host(`admin-api.eventhub.local`)"
entryPoints: ["web"]
middlewares: ["redirect-to-https", "strip-api-prefix", "admin-ratelimit", "waf"]
service: "admin-api"
admin-api-secure:
rule: "Host(`admin-api.eventhub.local`)"
entryPoints: ["websecure"]
tls: true
middlewares: ["strip-api-prefix", "admin-ratelimit", "waf"]
service: "admin-api"
# Админский WebSocket
admin-ws:
rule: "Host(`admin-ws.eventhub.local`)"
entryPoints: ["web"]
middlewares: ["redirect-to-https"]
service: "admin-ws"
admin-ws-secure:
rule: "Host(`admin-ws.eventhub.local`)"
entryPoints: ["websecure"]
tls: true
service: "admin-ws"
# Админский UI
admin-ui:
rule: "Host(`admin.eventhub.local`) && !PathPrefix(`/api/`) && !PathPrefix(`/ws/`)"
rule: "Host(`admin-ui.eventhub.local`)"
entryPoints: ["web"]
middlewares: ["redirect-to-https"]
service: "admin-ui-service"
admin-ui-secure:
rule: "Host(`admin.eventhub.local`) && !PathPrefix(`/api/`) && !PathPrefix(`/ws/`)"
rule: "Host(`admin-ui.eventhub.local`)"
entryPoints: ["websecure"]
tls: true
service: "admin-ui-service"
# --- Проксирование /api/ на админский REST ---
admin-api-proxy:
rule: "Host(`admin.eventhub.local`) && PathPrefix(`/api/`)"
entryPoints: ["web"]
middlewares: ["redirect-to-https", "admin-ratelimit", "waf"]
service: "admin-api"
admin-api-proxy-secure:
rule: "Host(`admin.eventhub.local`) && PathPrefix(`/api/`)"
entryPoints: ["websecure"]
tls: true
middlewares: ["admin-ratelimit", "waf"]
service: "admin-api"
# --- Проксирование /ws/ на админский WebSocket ---
admin-ws-proxy:
rule: "Host(`admin.eventhub.local`) && PathPrefix(`/ws/`)"
# Клиентский UI
client-ui:
rule: "Host(`ui.eventhub.local`)"
entryPoints: ["web"]
middlewares: ["redirect-to-https"]
service: "admin-ws"
admin-ws-proxy-secure:
rule: "Host(`admin.eventhub.local`) && PathPrefix(`/ws/`)"
service: "client-ui-service"
client-ui-secure:
rule: "Host(`ui.eventhub.local`)"
entryPoints: ["websecure"]
tls: true
service: "admin-ws"
service: "client-ui-service"
services:
# --- Пользовательский REST API (failover) ---
api:
failover:
service: api-live
@@ -110,9 +129,7 @@ http:
api-live:
loadbalancer:
servers:
- url: "http://eventhub-node1:8080"
- url: "http://eventhub-node2:8080"
- url: "http://eventhub-node3:8080"
- url: "http://eventhub:8080"
healthCheck:
path: "/health"
interval: "10s"
@@ -122,15 +139,12 @@ http:
servers:
- url: "http://fallback:80"
# --- Пользовательский WebSocket ---
ws:
loadbalancer:
servers:
- url: "http://eventhub-node1:8081"
- url: "http://eventhub-node2:8081"
- url: "http://eventhub-node3:8081"
- url: "http://eventhub:8081"
serversTransport: http1-ws-transport
# --- Админский REST (failover) ---
admin-api:
failover:
service: admin-api-live
@@ -138,11 +152,9 @@ http:
admin-api-live:
loadbalancer:
servers:
- url: "http://eventhub-node1:8445"
- url: "http://eventhub-node2:8445"
- url: "http://eventhub-node3:8445"
- url: "http://eventhub:8445"
healthCheck:
path: "/health"
path: "/v1/admin/health"
interval: "10s"
timeout: "3s"
admin-api-fallback:
@@ -150,16 +162,18 @@ http:
servers:
- url: "http://fallback:80"
# --- Админский WebSocket ---
admin-ws:
loadbalancer:
servers:
- url: "http://eventhub-node1:8446"
- url: "http://eventhub-node2:8446"
- url: "http://eventhub-node3:8446"
- url: "http://eventhub:8446"
serversTransport: http1-ws-transport
# --- SPA (админ‑панель) ---
admin-ui-service:
loadbalancer:
servers:
- url: "http://admin-ui:80"
- url: "http://admin-ui:80"
client-ui-service:
loadbalancer:
servers:
- url: "http://client-ui:80"