162 lines
4.5 KiB
YAML
162 lines
4.5 KiB
YAML
name: vps-control
|
|
|
|
services:
|
|
postgres:
|
|
image: postgres:16-alpine
|
|
restart: unless-stopped
|
|
environment:
|
|
POSTGRES_DB: ${POSTGRES_DB:-vps_control}
|
|
POSTGRES_USER: ${POSTGRES_USER:-vps_control}
|
|
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
|
|
secrets:
|
|
- db_password
|
|
volumes:
|
|
- postgres-data:/var/lib/postgresql/data
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 8
|
|
networks: [internal]
|
|
mem_limit: 512m
|
|
cpus: 1.0
|
|
pids_limit: 200
|
|
security_opt: ["no-new-privileges:true"]
|
|
|
|
backend:
|
|
build:
|
|
context: ./backend
|
|
restart: unless-stopped
|
|
environment:
|
|
LISTEN_ADDRESS: :8080
|
|
DB_HOST: postgres
|
|
DB_PORT: "5432"
|
|
DB_NAME: ${POSTGRES_DB:-vps_control}
|
|
DB_USER: ${POSTGRES_USER:-vps_control}
|
|
DB_PASSWORD_FILE: /run/secrets/db_password
|
|
DB_SSLMODE: disable
|
|
COOKIE_SECURE: ${COOKIE_SECURE:-true}
|
|
TRUST_PROXY: "true"
|
|
SESSION_TTL: ${SESSION_TTL:-12h}
|
|
METRICS_RETENTION: ${METRICS_RETENTION:-720h}
|
|
LOGS_RETENTION: ${LOGS_RETENTION:-168h}
|
|
AGENT_CREDENTIALS_DIR: /run/secrets
|
|
INTEGRATION_TOKEN_FILE: /run/secrets/integration_token
|
|
INITIAL_ADMIN_USERNAME: ${INITIAL_ADMIN_USERNAME:-admin}
|
|
INITIAL_ADMIN_PASSWORD_FILE: /run/secrets/admin_password
|
|
BOOTSTRAP_SERVER_NAME: ${BOOTSTRAP_SERVER_NAME:-}
|
|
BOOTSTRAP_SERVER_ENDPOINT: ${BOOTSTRAP_SERVER_ENDPOINT:-}
|
|
BOOTSTRAP_AGENT_CREDENTIAL_REF: ${BOOTSTRAP_AGENT_CREDENTIAL_REF:-agent_token}
|
|
secrets:
|
|
- db_password
|
|
- admin_password
|
|
- agent_token
|
|
- integration_token
|
|
depends_on:
|
|
postgres:
|
|
condition: service_healthy
|
|
healthcheck:
|
|
test: ["CMD", "wget", "-q", "-O", "/dev/null", "http://127.0.0.1:8080/healthz"]
|
|
interval: 10s
|
|
timeout: 3s
|
|
retries: 5
|
|
start_period: 10s
|
|
networks: [internal, agent]
|
|
read_only: true
|
|
tmpfs: [/tmp]
|
|
mem_limit: 128m
|
|
cpus: 0.5
|
|
pids_limit: 100
|
|
security_opt: ["no-new-privileges:true"]
|
|
|
|
frontend:
|
|
build:
|
|
context: ./frontend
|
|
restart: unless-stopped
|
|
ports:
|
|
- "${HTTP_BIND_ADDRESS:-127.0.0.1}:${HTTP_PORT:-8080}:8080"
|
|
depends_on:
|
|
backend:
|
|
condition: service_healthy
|
|
healthcheck:
|
|
test: ["CMD", "wget", "-q", "-O", "/dev/null", "http://127.0.0.1:8080/"]
|
|
interval: 10s
|
|
timeout: 3s
|
|
retries: 5
|
|
networks: [edge, internal]
|
|
read_only: true
|
|
tmpfs:
|
|
- /tmp
|
|
- /var/cache/nginx
|
|
- /var/run
|
|
mem_limit: 64m
|
|
cpus: 0.25
|
|
pids_limit: 50
|
|
security_opt: ["no-new-privileges:true"]
|
|
|
|
grafana:
|
|
profiles: ["observability"]
|
|
build:
|
|
context: ./grafana
|
|
restart: unless-stopped
|
|
ports:
|
|
- "${GRAFANA_BIND_ADDRESS:-127.0.0.1}:${GRAFANA_PORT:-3000}:3000"
|
|
environment:
|
|
GF_SERVER_ROOT_URL: ${GRAFANA_ROOT_URL:-http://127.0.0.1:3000}
|
|
GF_USERS_ALLOW_SIGN_UP: "false"
|
|
GF_AUTH_ANONYMOUS_ENABLED: "false"
|
|
GF_SECURITY_COOKIE_SECURE: ${GRAFANA_COOKIE_SECURE:-false}
|
|
GF_ANALYTICS_REPORTING_ENABLED: "false"
|
|
GF_ANALYTICS_CHECK_FOR_UPDATES: "false"
|
|
GF_LOG_LEVEL: warn
|
|
secrets:
|
|
- integration_token
|
|
- grafana_admin_password
|
|
- grafana_secret_key
|
|
depends_on:
|
|
backend:
|
|
condition: service_healthy
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "wget -q -O /dev/null http://127.0.0.1:3000/api/health"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 12
|
|
start_period: 20s
|
|
networks: [edge, internal]
|
|
read_only: true
|
|
tmpfs:
|
|
- /tmp
|
|
- /var/log/grafana
|
|
volumes:
|
|
- grafana-data:/var/lib/grafana
|
|
- grafana-plugins:/usr/share/grafana/data/plugins-bundled
|
|
mem_limit: 384m
|
|
cpus: 0.75
|
|
pids_limit: 150
|
|
security_opt: ["no-new-privileges:true"]
|
|
|
|
volumes:
|
|
postgres-data:
|
|
grafana-data:
|
|
grafana-plugins:
|
|
|
|
networks:
|
|
edge:
|
|
internal:
|
|
internal: true
|
|
agent:
|
|
|
|
secrets:
|
|
db_password:
|
|
file: ${DB_PASSWORD_SECRET_FILE:-./secrets/db_password}
|
|
admin_password:
|
|
file: ${ADMIN_PASSWORD_SECRET_FILE:-./secrets/admin_password}
|
|
agent_token:
|
|
file: ${AGENT_TOKEN_SECRET_FILE:-./secrets/agent_token}
|
|
integration_token:
|
|
file: ${INTEGRATION_TOKEN_SECRET_FILE:-./secrets/integration_token}
|
|
grafana_admin_password:
|
|
file: ${GRAFANA_ADMIN_PASSWORD_SECRET_FILE:-./secrets/grafana_admin_password}
|
|
grafana_secret_key:
|
|
file: ${GRAFANA_SECRET_KEY_SECRET_FILE:-./secrets/grafana_secret_key}
|