services: portainer: image: portainer/portainer-ce:latest container_name: portainer restart: unless-stopped networks: - traefik-public volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - portainer-data:/data labels: - "traefik.enable=true" - "traefik.http.routers.portainer.rule=Host(`portainer.${DOMAIN}`)" - "traefik.http.routers.portainer.entrypoints=websecure" - "traefik.http.routers.portainer.tls=true" - "traefik.http.routers.portainer.tls.certresolver=letsencrypt" - "traefik.http.services.portainer.loadbalancer.server.port=9000" prometheus: image: prom/prometheus:latest container_name: prometheus restart: unless-stopped user: "65534:65534" networks: - traefik-public - app-internal volumes: - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro - ./prometheus/alerts.yml:/etc/prometheus/alerts.yml:ro - prometheus-data:/prometheus command: - '--config.file=/etc/prometheus/prometheus.yml' - '--storage.tsdb.path=/prometheus' - '--storage.tsdb.retention.time=30d' - '--web.console.libraries=/usr/share/prometheus/console_libraries' - '--web.console.templates=/usr/share/prometheus/consoles' - '--web.enable-lifecycle' labels: - "traefik.enable=true" - "traefik.http.routers.prometheus.rule=Host(`prometheus.${DOMAIN}`)" - "traefik.http.routers.prometheus.entrypoints=websecure" - "traefik.http.routers.prometheus.tls=true" - "traefik.http.routers.prometheus.tls.certresolver=letsencrypt" - "traefik.http.routers.prometheus.middlewares=prometheus-auth" - "traefik.http.middlewares.prometheus-auth.basicauth.users=${PROMETHEUS_AUTH}" - "traefik.http.services.prometheus.loadbalancer.server.port=9090" healthcheck: test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:9090/-/healthy"] interval: 30s timeout: 10s retries: 3 grafana: image: grafana/grafana:latest container_name: grafana restart: unless-stopped networks: - traefik-public - app-internal environment: - GF_SERVER_ROOT_URL=https://grafana.${DOMAIN} - GF_SECURITY_ADMIN_USER=${GRAFANA_ADMIN_USER} - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_ADMIN_PASSWORD} - GF_USERS_ALLOW_SIGN_UP=false - GF_INSTALL_PLUGINS=${GRAFANA_PLUGINS} - GF_LOG_LEVEL=info - GF_ANALYTICS_REPORTING_ENABLED=false volumes: - grafana-data:/var/lib/grafana - ./grafana/provisioning:/etc/grafana/provisioning:ro - ./grafana/dashboards:/var/lib/grafana/dashboards:ro labels: - "traefik.enable=true" - "traefik.http.routers.grafana.rule=Host(`grafana.${DOMAIN}`)" - "traefik.http.routers.grafana.entrypoints=websecure" - "traefik.http.routers.grafana.tls=true" - "traefik.http.routers.grafana.tls.certresolver=letsencrypt" - "traefik.http.middlewares.grafana-vpn-only.ipwhitelist.sourcerange=${MONITORING_VPN_IP_WHITELIST:-10.8.0.0/24}" - "traefik.http.routers.grafana.middlewares=grafana-vpn-only" - "traefik.http.services.grafana.loadbalancer.server.port=3000" depends_on: prometheus: condition: service_healthy healthcheck: test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000/api/health"] interval: 30s timeout: 10s retries: 3 node-exporter: image: prom/node-exporter:latest container_name: node-exporter restart: unless-stopped networks: - app-internal volumes: - /proc:/host/proc:ro - /sys:/host/sys:ro - /:/rootfs:ro command: - '--path.procfs=/host/proc' - '--path.sysfs=/host/sys' - '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)' healthcheck: test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:9100/metrics"] interval: 30s timeout: 10s retries: 3 cadvisor: image: gcr.io/cadvisor/cadvisor:latest container_name: cadvisor restart: unless-stopped privileged: true networks: - app-internal volumes: - /:/rootfs:ro - /var/run:/var/run:ro - /sys:/sys:ro - /var/lib/docker/:/var/lib/docker:ro - /dev/disk/:/dev/disk:ro devices: - /dev/kmsg healthcheck: test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/healthz"] interval: 30s timeout: 10s retries: 3 volumes: portainer-data: name: portainer-data prometheus-data: name: prometheus-data grafana-data: name: grafana-data networks: traefik-public: external: true app-internal: external: true