From 23ccc9aacc3e221e171805b6b4d30a232c780965 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B5=D0=B9=20=D0=A1=D0=B0?= =?UTF-8?q?=D0=B1=D0=B8=D0=BB=D0=B8=D0=BD?= Date: Sat, 25 Apr 2026 12:22:20 +0300 Subject: [PATCH] Failover Service --- docker/docker-compose.yml | 111 +++----------------------------- docker/fallback/503.html | 17 +++++ docker/fallback/Dockerfile | 3 + docker/fallback/default.conf | 13 ++++ docker/traefik/dynamic_conf.yml | 108 ++++++++++++++++++++++++++++++- 5 files changed, 150 insertions(+), 102 deletions(-) create mode 100644 docker/fallback/503.html create mode 100644 docker/fallback/Dockerfile create mode 100644 docker/fallback/default.conf diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index bc88008..38cffbc 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -8,7 +8,7 @@ services: - "--api.insecure=true" # дашборд (можно удалить в production) - "--providers.docker=true" - "--providers.docker.exposedbydefault=false" - - "--providers.file.filename=/etc/traefik/dynamic_conf.yml" # самоподписанный сертификат и редирект + - "--providers.file.filename=/etc/traefik/dynamic_conf.yml" # самоподписанный сертификат, редирект и failover - "--entrypoints.web.address=:80" # HTTP (для редиректа) - "--entrypoints.websecure.address=:443" # HTTPS/WSS # Метрики Prometheus @@ -29,6 +29,15 @@ services: - eventhub-net restart: unless-stopped + # ================== Сервис-заглушка для Failover ================== + fallback: + build: + context: ./fallback + dockerfile: Dockerfile + networks: + - eventhub-net + restart: unless-stopped + # ================== Кластер EventHub (3 ноды) ================== eventhub-node1: build: @@ -46,42 +55,6 @@ services: - eventhub-node1-data:/app/data labels: - "traefik.enable=true" - # --- REST API пользователей --- - - "traefik.http.routers.api.rule=Host(`api.eventhub.local`)" - - "traefik.http.routers.api.entrypoints=web" - - "traefik.http.routers.api.middlewares=redirect-to-https@file" - - "traefik.http.routers.api-secure.rule=Host(`api.eventhub.local`)" - - "traefik.http.routers.api-secure.entrypoints=websecure" - - "traefik.http.routers.api-secure.tls=true" - - "traefik.http.routers.api-secure.service=api" - - "traefik.http.services.api.loadbalancer.server.port=8080" - # --- WebSocket пользователей (WSS через websecure) --- - - "traefik.http.routers.ws.rule=Host(`ws.eventhub.local`)" - - "traefik.http.routers.ws.entrypoints=web" - - "traefik.http.routers.ws.middlewares=redirect-to-https@file" - - "traefik.http.routers.ws-secure.rule=Host(`ws.eventhub.local`)" - - "traefik.http.routers.ws-secure.entrypoints=websecure" - - "traefik.http.routers.ws-secure.tls=true" - - "traefik.http.routers.ws-secure.service=ws" - - "traefik.http.services.ws.loadbalancer.server.port=8081" - # --- Админский REST --- - - "traefik.http.routers.admin-api.rule=Host(`admin.eventhub.local`)" - - "traefik.http.routers.admin-api.entrypoints=web" - - "traefik.http.routers.admin-api.middlewares=redirect-to-https@file" - - "traefik.http.routers.admin-api-secure.rule=Host(`admin.eventhub.local`)" - - "traefik.http.routers.admin-api-secure.entrypoints=websecure" - - "traefik.http.routers.admin-api-secure.tls=true" - - "traefik.http.routers.admin-api-secure.service=admin-api" - - "traefik.http.services.admin-api.loadbalancer.server.port=8445" - # --- Админский WebSocket (WSS) --- - - "traefik.http.routers.admin-ws.rule=Host(`admin-ws.eventhub.local`)" - - "traefik.http.routers.admin-ws.entrypoints=web" - - "traefik.http.routers.admin-ws.middlewares=redirect-to-https@file" - - "traefik.http.routers.admin-ws-secure.rule=Host(`admin-ws.eventhub.local`)" - - "traefik.http.routers.admin-ws-secure.entrypoints=websecure" - - "traefik.http.routers.admin-ws-secure.tls=true" - - "traefik.http.routers.admin-ws-secure.service=admin-ws" - - "traefik.http.services.admin-ws.loadbalancer.server.port=8446" restart: unless-stopped eventhub-node2: @@ -100,38 +73,6 @@ services: - eventhub-node2-data:/app/data labels: - "traefik.enable=true" - - "traefik.http.routers.api.rule=Host(`api.eventhub.local`)" - - "traefik.http.routers.api.entrypoints=web" - - "traefik.http.routers.api.middlewares=redirect-to-https@file" - - "traefik.http.routers.api-secure.rule=Host(`api.eventhub.local`)" - - "traefik.http.routers.api-secure.entrypoints=websecure" - - "traefik.http.routers.api-secure.tls=true" - - "traefik.http.routers.api-secure.service=api" - - "traefik.http.services.api.loadbalancer.server.port=8080" - - "traefik.http.routers.ws.rule=Host(`ws.eventhub.local`)" - - "traefik.http.routers.ws.entrypoints=web" - - "traefik.http.routers.ws.middlewares=redirect-to-https@file" - - "traefik.http.routers.ws-secure.rule=Host(`ws.eventhub.local`)" - - "traefik.http.routers.ws-secure.entrypoints=websecure" - - "traefik.http.routers.ws-secure.tls=true" - - "traefik.http.routers.ws-secure.service=ws" - - "traefik.http.services.ws.loadbalancer.server.port=8081" - - "traefik.http.routers.admin-api.rule=Host(`admin.eventhub.local`)" - - "traefik.http.routers.admin-api.entrypoints=web" - - "traefik.http.routers.admin-api.middlewares=redirect-to-https@file" - - "traefik.http.routers.admin-api-secure.rule=Host(`admin.eventhub.local`)" - - "traefik.http.routers.admin-api-secure.entrypoints=websecure" - - "traefik.http.routers.admin-api-secure.tls=true" - - "traefik.http.routers.admin-api-secure.service=admin-api" - - "traefik.http.services.admin-api.loadbalancer.server.port=8445" - - "traefik.http.routers.admin-ws.rule=Host(`admin-ws.eventhub.local`)" - - "traefik.http.routers.admin-ws.entrypoints=web" - - "traefik.http.routers.admin-ws.middlewares=redirect-to-https@file" - - "traefik.http.routers.admin-ws-secure.rule=Host(`admin-ws.eventhub.local`)" - - "traefik.http.routers.admin-ws-secure.entrypoints=websecure" - - "traefik.http.routers.admin-ws-secure.tls=true" - - "traefik.http.routers.admin-ws-secure.service=admin-ws" - - "traefik.http.services.admin-ws.loadbalancer.server.port=8446" restart: unless-stopped eventhub-node3: @@ -150,38 +91,6 @@ services: - eventhub-node3-data:/app/data labels: - "traefik.enable=true" - - "traefik.http.routers.api.rule=Host(`api.eventhub.local`)" - - "traefik.http.routers.api.entrypoints=web" - - "traefik.http.routers.api.middlewares=redirect-to-https@file" - - "traefik.http.routers.api-secure.rule=Host(`api.eventhub.local`)" - - "traefik.http.routers.api-secure.entrypoints=websecure" - - "traefik.http.routers.api-secure.tls=true" - - "traefik.http.routers.api-secure.service=api" - - "traefik.http.services.api.loadbalancer.server.port=8080" - - "traefik.http.routers.ws.rule=Host(`ws.eventhub.local`)" - - "traefik.http.routers.ws.entrypoints=web" - - "traefik.http.routers.ws.middlewares=redirect-to-https@file" - - "traefik.http.routers.ws-secure.rule=Host(`ws.eventhub.local`)" - - "traefik.http.routers.ws-secure.entrypoints=websecure" - - "traefik.http.routers.ws-secure.tls=true" - - "traefik.http.routers.ws-secure.service=ws" - - "traefik.http.services.ws.loadbalancer.server.port=8081" - - "traefik.http.routers.admin-api.rule=Host(`admin.eventhub.local`)" - - "traefik.http.routers.admin-api.entrypoints=web" - - "traefik.http.routers.admin-api.middlewares=redirect-to-https@file" - - "traefik.http.routers.admin-api-secure.rule=Host(`admin.eventhub.local`)" - - "traefik.http.routers.admin-api-secure.entrypoints=websecure" - - "traefik.http.routers.admin-api-secure.tls=true" - - "traefik.http.routers.admin-api-secure.service=admin-api" - - "traefik.http.services.admin-api.loadbalancer.server.port=8445" - - "traefik.http.routers.admin-ws.rule=Host(`admin-ws.eventhub.local`)" - - "traefik.http.routers.admin-ws.entrypoints=web" - - "traefik.http.routers.admin-ws.middlewares=redirect-to-https@file" - - "traefik.http.routers.admin-ws-secure.rule=Host(`admin-ws.eventhub.local`)" - - "traefik.http.routers.admin-ws-secure.entrypoints=websecure" - - "traefik.http.routers.admin-ws-secure.tls=true" - - "traefik.http.routers.admin-ws-secure.service=admin-ws" - - "traefik.http.services.admin-ws.loadbalancer.server.port=8446" restart: unless-stopped # ================== Мониторинг ================== diff --git a/docker/fallback/503.html b/docker/fallback/503.html new file mode 100644 index 0000000..7828ea9 --- /dev/null +++ b/docker/fallback/503.html @@ -0,0 +1,17 @@ + + + + + EventHub - Maintenance + + + +

503

+

EventHub временно недоступен. Мы уже чиним.

+

Попробуйте обновить страницу через минуту.

+ + \ No newline at end of file diff --git a/docker/fallback/Dockerfile b/docker/fallback/Dockerfile new file mode 100644 index 0000000..dea2bf5 --- /dev/null +++ b/docker/fallback/Dockerfile @@ -0,0 +1,3 @@ +FROM nginx:alpine +COPY default.conf /etc/nginx/conf.d/default.conf +COPY 503.html /usr/share/nginx/html/503.html \ No newline at end of file diff --git a/docker/fallback/default.conf b/docker/fallback/default.conf new file mode 100644 index 0000000..a46c971 --- /dev/null +++ b/docker/fallback/default.conf @@ -0,0 +1,13 @@ +server { + listen 80 default_server; + root /usr/share/nginx/html; + + location / { + return 503; + } + + error_page 503 /503.html; + location = /503.html { + internal; + } +} \ No newline at end of file diff --git a/docker/traefik/dynamic_conf.yml b/docker/traefik/dynamic_conf.yml index a329ac8..eac73b6 100644 --- a/docker/traefik/dynamic_conf.yml +++ b/docker/traefik/dynamic_conf.yml @@ -13,4 +13,110 @@ http: redirect-to-https: redirectScheme: scheme: https - permanent: true \ No newline at end of file + permanent: true + + routers: + # === REST API пользователей === + api: + rule: "Host(`api.eventhub.local`)" + entryPoints: ["web"] + middlewares: ["redirect-to-https"] + service: "api" + api-secure: + rule: "Host(`api.eventhub.local`)" + entryPoints: ["websecure"] + tls: true + service: "api" + + # === WebSocket пользователей === + ws: + rule: "Host(`ws.eventhub.local`)" + entryPoints: ["web"] + middlewares: ["redirect-to-https"] + service: "ws" + ws-secure: + rule: "Host(`ws.eventhub.local`)" + entryPoints: ["websecure"] + tls: true + service: "ws" + + # === Админский REST === + admin-api: + rule: "Host(`admin.eventhub.local`)" + entryPoints: ["web"] + middlewares: ["redirect-to-https"] + service: "admin-api" + admin-api-secure: + rule: "Host(`admin.eventhub.local`)" + entryPoints: ["websecure"] + tls: true + 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" + + services: + # === Пользовательский REST API (failover) === + api: + failover: + service: api-live + fallback: api-fallback + api-live: + loadbalancer: + servers: + - url: "http://eventhub-node1:8080" + - url: "http://eventhub-node2:8080" + - url: "http://eventhub-node3:8080" + healthCheck: + path: "/health" + interval: "10s" + timeout: "3s" + api-fallback: + loadbalancer: + servers: + - url: "http://fallback:80" + + # === WebSocket пользователей (простой балансировщик) === + ws: + loadbalancer: + servers: + - url: "http://eventhub-node1:8081" + - url: "http://eventhub-node2:8081" + - url: "http://eventhub-node3:8081" + + # === Админский REST (failover) === + admin-api: + failover: + service: admin-api-live + fallback: admin-api-fallback + admin-api-live: + loadbalancer: + servers: + - url: "http://eventhub-node1:8445" + - url: "http://eventhub-node2:8445" + - url: "http://eventhub-node3:8445" + healthCheck: + path: "/health" + interval: "10s" + timeout: "3s" + admin-api-fallback: + loadbalancer: + 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" \ No newline at end of file