Traefik as the server-wide edge (TLS via Let's Encrypt, dashboard on traefik.petrolyst.com behind oauth2-proxy and Keycloak). The fuel-monitoring stack: Superset on atoma.petrolyst.com with Keycloak login and Petrolyst branding, Trino reading the TimescaleDB fuel-db as catalog "fuel". Customization lives in petrolyst-insights/, deployment in the other folders. Deploys run server-side (deploy/deploy.sh) from a Gitea workflow or manually; releases are immutable, Superset metadata is backed up before migrations, and deploy/rollback.sh restores it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
118 lines
4.3 KiB
YAML
118 lines
4.3 KiB
YAML
# Edge proxy for the whole server. Deployed first by deploy/deploy.sh, which
|
|
# exports TRAEFIK_CONFIG_HASH from the release's ARTIFACTS file.
|
|
#
|
|
# Any stack joins by attaching a service to the external network "proxy" and
|
|
# setting traefik.* labels; apps without their own login can add the "sso"
|
|
# middleware (Keycloak client petrolyst, role checked by oauth2-proxy).
|
|
name: traefik
|
|
|
|
services:
|
|
socket-proxy:
|
|
image: tecnativa/docker-socket-proxy:v0.5.0
|
|
environment:
|
|
CONTAINERS: "1"
|
|
EVENTS: "1"
|
|
PING: "1"
|
|
VERSION: "1"
|
|
POST: "0"
|
|
LOG_LEVEL: warning
|
|
volumes:
|
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
|
networks:
|
|
- socket
|
|
restart: unless-stopped
|
|
mem_limit: 64m
|
|
|
|
traefik:
|
|
image: traefik:v3.7.16
|
|
command: ["--configFile=/etc/traefik/static/traefik.yml"]
|
|
ports:
|
|
- "80:80"
|
|
- "443:443"
|
|
# Folders, not single files: promotion replaces files by renaming, which a
|
|
# single-file bind mount would not follow.
|
|
volumes:
|
|
- ./static:/etc/traefik/static:ro
|
|
- ./dynamic:/etc/traefik/dynamic:ro
|
|
- letsencrypt:/letsencrypt
|
|
depends_on:
|
|
- socket-proxy
|
|
networks:
|
|
- proxy
|
|
- socket
|
|
restart: unless-stopped
|
|
mem_limit: 256m
|
|
healthcheck:
|
|
test: ["CMD", "traefik", "healthcheck", "--configFile=/etc/traefik/static/traefik.yml"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 6
|
|
labels:
|
|
petrolyst.config-hash: ${TRAEFIK_CONFIG_HASH:?TRAEFIK_CONFIG_HASH unset - run through deploy/deploy.sh}
|
|
traefik.enable: "true"
|
|
traefik.http.routers.dashboard.rule: Host(`${TRAEFIK_HOST:-traefik.petrolyst.com}`)
|
|
traefik.http.routers.dashboard.entrypoints: websecure
|
|
traefik.http.routers.dashboard.tls.certresolver: le
|
|
traefik.http.routers.dashboard.service: api@internal
|
|
traefik.http.routers.dashboard.middlewares: sso,secure-headers@file
|
|
# Keycloak gate for the dashboard host only (cookie, return hosts and
|
|
# role are tied to it; README "Adding a project"): unauthenticated
|
|
# requests are sent to Keycloak, users without petrolyst:traefik-admin
|
|
# get 403.
|
|
traefik.http.middlewares.sso.forwardauth.address: http://oauth2-proxy:4180/
|
|
traefik.http.middlewares.sso.forwardauth.trustForwardHeader: "true"
|
|
traefik.http.middlewares.sso.forwardauth.authResponseHeaders: X-Auth-Request-User,X-Auth-Request-Email
|
|
|
|
oauth2-proxy:
|
|
image: quay.io/oauth2-proxy/oauth2-proxy:v7.15.5
|
|
command:
|
|
- --provider=keycloak-oidc
|
|
- --oidc-issuer-url=${KEYCLOAK_REALM_URL:-https://iam.thedigitalbridge.io/realms/thedigitalbridge}
|
|
- --client-id=petrolyst
|
|
- --client-secret-file=/run/secrets/keycloak_petrolyst_client_secret
|
|
- --cookie-secret-file=/run/secrets/oauth2_proxy_cookie_secret
|
|
- --code-challenge-method=S256
|
|
- --allowed-role=petrolyst:traefik-admin
|
|
# Required by oauth2-proxy at startup; access is decided by the role above.
|
|
- --email-domain=*
|
|
- --redirect-url=https://${TRAEFIK_HOST:-traefik.petrolyst.com}/oauth2/callback
|
|
- --whitelist-domain=${TRAEFIK_HOST:-traefik.petrolyst.com}
|
|
- --cookie-domain=${TRAEFIK_HOST:-traefik.petrolyst.com}
|
|
- --cookie-secure=true
|
|
- --cookie-samesite=lax
|
|
- --reverse-proxy=true
|
|
- --upstream=static://202
|
|
- --skip-provider-button=true
|
|
- --set-xauthrequest=true
|
|
- --http-address=0.0.0.0:4180
|
|
secrets:
|
|
- keycloak_petrolyst_client_secret
|
|
- oauth2_proxy_cookie_secret
|
|
networks:
|
|
- proxy
|
|
restart: unless-stopped
|
|
mem_limit: 128m
|
|
labels:
|
|
traefik.enable: "true"
|
|
traefik.docker.network: proxy
|
|
traefik.http.routers.oauth2.rule: Host(`${TRAEFIK_HOST:-traefik.petrolyst.com}`) && PathPrefix(`/oauth2/`)
|
|
traefik.http.routers.oauth2.entrypoints: websecure
|
|
traefik.http.routers.oauth2.tls.certresolver: le
|
|
traefik.http.routers.oauth2.middlewares: secure-headers@file
|
|
traefik.http.services.oauth2.loadbalancer.server.port: "4180"
|
|
|
|
networks:
|
|
proxy:
|
|
external: true
|
|
socket:
|
|
internal: true
|
|
|
|
volumes:
|
|
letsencrypt:
|
|
|
|
secrets:
|
|
keycloak_petrolyst_client_secret:
|
|
file: ${PETROLYST_ROOT:-/opt/petrolyst}/secrets/shared/keycloak_petrolyst_client_secret
|
|
oauth2_proxy_cookie_secret:
|
|
file: ${PETROLYST_ROOT:-/opt/petrolyst}/secrets/traefik/oauth2_proxy_cookie_secret
|