CI / changes (push) Successful in 15s
CI / commitlint (push) Has been skipped
CI / openapi (push) Has been skipped
CI / web (push) Successful in 1m0s
CI / go (push) Successful in 1m0s
CI / bird2 (push) Successful in 16s
CI / release (push) Successful in 3m39s
Added public HTTPS endpoints for firewall installation and enrollment scripts, allowing access without API keys. Updated the URL handling in the firewall code to ensure all suggested control plane URLs are served over HTTPS. Enhanced documentation to reflect the new public endpoints and their usage. Updated tests to verify the correct behavior of the new URL handling logic.
287 lines
9.2 KiB
YAML
287 lines
9.2 KiB
YAML
# Production stack для /opt/evobgp/docker-compose.yaml
|
||
# Скопируйте на сервер:
|
||
# scp deploy/compose/docker-compose.production.example.yaml root@host:/opt/evobgp/docker-compose.yaml
|
||
# scp deploy/compose/.env.production.example root@host:/opt/evobgp/.env
|
||
#
|
||
# Запуск:
|
||
# cd /opt/evobgp
|
||
# mkdir -p runtime-logs
|
||
# docker login git.shts.su
|
||
# docker compose pull
|
||
# docker compose up -d
|
||
#
|
||
# Runtime logs API (/v1/runtime-logs/*): evobgp-all + stack-runtime-logs делят каталог
|
||
# EVOBGP_RUNTIME_LOGS_HOST_DIR на хосте (default /opt/evobgp/runtime-logs).
|
||
#
|
||
# Postgres: shm_size + start_period — иначе часто «dependency postgres failed» на слабом хосте.
|
||
# Web UI: WEBUI_DOMAIN, WEBUI_IP_WHITELIST, LETSENCRYPT_EMAIL, CF_DNS_API_TOKEN в .env
|
||
# Cloudflare: DNS only (серый облачок) для WEBUI_DOMAIN.
|
||
#
|
||
# ACME: том traefik_letsencrypt.name зафиксирован — не `docker compose down -v` без бэкапа.
|
||
# COMPOSE_PROJECT_NAME должен совпадать с label com.docker.compose.project стека.
|
||
name: evobgp-microvps-full
|
||
|
||
configs:
|
||
prometheus_yml:
|
||
content: |
|
||
global:
|
||
scrape_interval: 15s
|
||
evaluation_interval: 15s
|
||
rule_files:
|
||
- /etc/prometheus/alerts.yml
|
||
scrape_configs:
|
||
- job_name: evobgp-all
|
||
metrics_path: /metrics
|
||
static_configs:
|
||
- targets: ["evobgp-all:8080"]
|
||
prometheus_alerts_yml:
|
||
content: |
|
||
groups: []
|
||
|
||
services:
|
||
postgres:
|
||
image: postgres:16-alpine
|
||
restart: unless-stopped
|
||
shm_size: "256mb"
|
||
environment:
|
||
POSTGRES_USER: evobgp
|
||
POSTGRES_PASSWORD: evobgp
|
||
POSTGRES_DB: evobgp
|
||
volumes:
|
||
- pgdata:/var/lib/postgresql/data
|
||
healthcheck:
|
||
test: ["CMD-SHELL", "pg_isready -U evobgp -d evobgp"]
|
||
interval: 10s
|
||
timeout: 5s
|
||
retries: 12
|
||
start_period: 45s
|
||
logging:
|
||
driver: json-file
|
||
options:
|
||
max-size: "10m"
|
||
max-file: "3"
|
||
|
||
nats:
|
||
image: nats:2.10-alpine
|
||
restart: unless-stopped
|
||
command: ["-js", "-m", "8222"]
|
||
ports:
|
||
- "4222:4222"
|
||
logging:
|
||
driver: json-file
|
||
options:
|
||
max-size: "10m"
|
||
max-file: "3"
|
||
|
||
bird2:
|
||
image: ${EVOBGP_REGISTRY:-git.shts.su/denozord}/evobgp-bird2:${EVOBGP_IMAGE_TAG:-latest}
|
||
restart: unless-stopped
|
||
cap_add:
|
||
- NET_ADMIN
|
||
sysctls:
|
||
net.ipv4.ip_forward: "1"
|
||
net.ipv6.conf.all.forwarding: "1"
|
||
volumes:
|
||
- bird_etc:/etc/bird
|
||
- bird_run:/run/bird
|
||
ports:
|
||
- "179:179/tcp"
|
||
logging:
|
||
driver: json-file
|
||
options:
|
||
max-size: "10m"
|
||
max-file: "3"
|
||
|
||
evobgp-agent:
|
||
image: ${EVOBGP_REGISTRY:-git.shts.su/denozord}/evobgp-agent:${EVOBGP_IMAGE_TAG:-latest}
|
||
restart: unless-stopped
|
||
depends_on:
|
||
bird2:
|
||
condition: service_started
|
||
cap_add:
|
||
- NET_ADMIN
|
||
volumes:
|
||
- bird_etc:/etc/bird
|
||
- bird_run:/run/bird
|
||
entrypoint: ["/usr/local/bin/evobgp-agent"]
|
||
command: ["watch", "-socket=/run/bird/bird.ctl", "-watch-interval=30s"]
|
||
logging:
|
||
driver: json-file
|
||
options:
|
||
max-size: "10m"
|
||
max-file: "3"
|
||
|
||
evobgp-all:
|
||
image: ${EVOBGP_REGISTRY:-git.shts.su/denozord}/evobgp-all:${EVOBGP_IMAGE_TAG:-latest}
|
||
restart: unless-stopped
|
||
depends_on:
|
||
postgres:
|
||
condition: service_healthy
|
||
nats:
|
||
condition: service_started
|
||
bird2:
|
||
condition: service_started
|
||
ports:
|
||
- "8080:8080"
|
||
environment:
|
||
EVOBGP_DATABASE_URL: postgres://evobgp:evobgp@postgres:5432/evobgp?sslmode=disable
|
||
# EVOBGP_BROKER_URL: nats://nats:4222
|
||
EVOBGP_NODE_DISPATCH_ENABLED: "1"
|
||
EVOBGP_BUNDLE_SEED_HEX: "bd8fbcd31545aacfdd228203beca8e945ab9a752f2ce5624cf42d9f316389a9d"
|
||
EVOBGP_HTTP_ADDR: ":8080"
|
||
EVOBGP_SEED_DEMO: "1"
|
||
EVOBGP_BIRDC_SOCKET: /run/bird/bird.ctl
|
||
EVOBGP_BIRDC_INTERVAL: 30s
|
||
EVOBGP_BIRD_ACTIVE_DIR: /etc/bird
|
||
EVOBGP_BIRD_STAGING_DIR: /tmp/evobgp-bird-staging
|
||
EVOBGP_SERVICE: evobgp-all
|
||
EVOBGP_RUNTIME_LOGS_DIR: /opt/evobgp/runtime-logs
|
||
EVOBGP_DEV_INSECURE: "1"
|
||
volumes:
|
||
- bird_etc:/etc/bird
|
||
- bird_run:/run/bird:ro
|
||
- type: bind
|
||
source: ${EVOBGP_RUNTIME_LOGS_HOST_DIR:-/opt/evobgp/runtime-logs}
|
||
target: /opt/evobgp/runtime-logs
|
||
bind:
|
||
create_host_path: true
|
||
logging:
|
||
driver: json-file
|
||
options:
|
||
max-size: "10m"
|
||
max-file: "3"
|
||
|
||
evobgp-web:
|
||
image: ${EVOBGP_REGISTRY:-git.shts.su/denozord}/evobgp-web-all:${EVOBGP_IMAGE_TAG:-latest}
|
||
restart: unless-stopped
|
||
depends_on:
|
||
evobgp-all:
|
||
condition: service_started
|
||
labels:
|
||
- traefik.enable=true
|
||
# Публичные firewall-эндпоинты — без WEBUI_IP_WHITELIST (установка с произвольных серверов).
|
||
- traefik.http.routers.evobgp-firewall-public.rule=Host(`${WEBUI_DOMAIN}`) && (Path(`/v1/firewall/install.sh`) || Path(`/v1/firewall/sync-script`) || PathPrefix(`/v1/firewall/enroll`))
|
||
- traefik.http.routers.evobgp-firewall-public.entrypoints=websecure
|
||
- traefik.http.routers.evobgp-firewall-public.tls=true
|
||
- traefik.http.routers.evobgp-firewall-public.tls.certresolver=letsencrypt
|
||
- traefik.http.routers.evobgp-firewall-public.priority=100
|
||
- traefik.http.routers.evobgp-firewall-public.service=evobgp-web
|
||
- traefik.http.routers.evobgp-web.rule=Host(`${WEBUI_DOMAIN}`)
|
||
- traefik.http.routers.evobgp-web.entrypoints=websecure
|
||
- traefik.http.routers.evobgp-web.tls=true
|
||
- traefik.http.routers.evobgp-web.tls.certresolver=letsencrypt
|
||
- traefik.http.routers.evobgp-web.priority=10
|
||
- traefik.http.routers.evobgp-web.middlewares=webui-ipwhitelist@docker
|
||
- traefik.http.middlewares.webui-ipwhitelist.ipallowlist.sourcerange=${WEBUI_IP_WHITELIST}
|
||
- traefik.http.services.evobgp-web.loadbalancer.server.port=80
|
||
logging:
|
||
driver: json-file
|
||
options:
|
||
max-size: "10m"
|
||
max-file: "3"
|
||
|
||
evobgp-edge:
|
||
image: traefik:latest
|
||
restart: unless-stopped
|
||
depends_on:
|
||
evobgp-web:
|
||
condition: service_started
|
||
ports:
|
||
- "80:80"
|
||
- "443:443"
|
||
environment:
|
||
DOCKER_API_VERSION: "1.44"
|
||
CF_DNS_API_TOKEN: ${CF_DNS_API_TOKEN}
|
||
command:
|
||
- --log.level=INFO
|
||
- --api.dashboard=false
|
||
- --providers.docker=true
|
||
- --providers.docker.exposedbydefault=false
|
||
- --entrypoints.web.address=:80
|
||
- --entrypoints.websecure.address=:443
|
||
- --entrypoints.web.http.redirections.entrypoint.to=websecure
|
||
- --entrypoints.web.http.redirections.entrypoint.scheme=https
|
||
- --certificatesresolvers.letsencrypt.acme.email=${LETSENCRYPT_EMAIL}
|
||
- --certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json
|
||
- --certificatesresolvers.letsencrypt.acme.dnschallenge=true
|
||
- --certificatesresolvers.letsencrypt.acme.dnschallenge.provider=cloudflare
|
||
- --certificatesresolvers.letsencrypt.acme.dnschallenge.delaybeforecheck=15
|
||
volumes:
|
||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||
- traefik_letsencrypt:/letsencrypt
|
||
logging:
|
||
driver: json-file
|
||
options:
|
||
max-size: "10m"
|
||
max-file: "3"
|
||
|
||
prometheus:
|
||
image: prom/prometheus:v2.54.1
|
||
restart: unless-stopped
|
||
depends_on:
|
||
evobgp-all:
|
||
condition: service_started
|
||
ports:
|
||
- "9090:9090"
|
||
configs:
|
||
- source: prometheus_yml
|
||
target: /etc/prometheus/prometheus.yml
|
||
- source: prometheus_alerts_yml
|
||
target: /etc/prometheus/alerts.yml
|
||
command:
|
||
- --config.file=/etc/prometheus/prometheus.yml
|
||
- --storage.tsdb.path=/prometheus
|
||
- --storage.tsdb.retention.time=7d
|
||
- --web.enable-lifecycle
|
||
logging:
|
||
driver: json-file
|
||
options:
|
||
max-size: "10m"
|
||
max-file: "3"
|
||
|
||
stack-runtime-logs:
|
||
image: docker:27-cli
|
||
restart: unless-stopped
|
||
depends_on:
|
||
evobgp-all:
|
||
condition: service_started
|
||
environment:
|
||
COMPOSE_PROJECT_NAME: ${COMPOSE_PROJECT_NAME:-evobgp-microvps-full}
|
||
volumes:
|
||
- /var/run/docker.sock:/var/run/docker.sock
|
||
- type: bind
|
||
source: ${EVOBGP_RUNTIME_LOGS_HOST_DIR:-/opt/evobgp/runtime-logs}
|
||
target: /logs
|
||
bind:
|
||
create_host_path: true
|
||
entrypoint: ["/bin/sh", "-c"]
|
||
command:
|
||
- |
|
||
set -eu
|
||
mkdir -p /logs
|
||
PROJECT=$$COMPOSE_PROJECT_NAME
|
||
SERVICES="postgres nats bird2 evobgp-agent evobgp-all evobgp-web evobgp-edge prometheus"
|
||
log_one() {
|
||
svc=$$1
|
||
f="/logs/$$svc.log"
|
||
while true; do
|
||
cid=$$(docker ps -q \
|
||
-f "label=com.docker.compose.service=$$svc" \
|
||
-f "label=com.docker.compose.project=$$PROJECT" | head -n1)
|
||
if [ -n "$$cid" ]; then
|
||
echo "---- $$(date -u +"%Y-%m-%dT%H:%M:%SZ") attach $$svc $$cid ----" >> "$$f"
|
||
docker logs -f --timestamps "$$cid" >> "$$f" 2>&1 || true
|
||
fi
|
||
sleep 3
|
||
done
|
||
}
|
||
for s in $$SERVICES; do log_one "$$s" & done
|
||
wait
|
||
|
||
volumes:
|
||
pgdata:
|
||
bird_etc:
|
||
bird_run:
|
||
traefik_letsencrypt:
|
||
name: evobgp_traefik_letsencrypt
|