Files
superset2/docker-compose.yml
Evan Rusackas e4f0e0a71b fix(docker): prevent static asset 404s by waiting for webpack dev server
When running `docker compose up`, nginx would start immediately and begin
proxying `/static` requests to port 9000 (webpack dev server) before the
`superset-node` container had finished running `npm install` and starting
the dev server. This resulted in 404 errors for all static assets.

This fix adds:
1. A health check to `superset-node` that verifies the webpack dev server
   is responding on port 9000
2. A `depends_on` condition on `nginx` that waits for `superset-node` to
   be healthy before starting

The health check:
- Uses Node.js (already available in the container) to make HTTP requests
- Has a 60-second start period to allow for `npm install`
- Retries up to 30 times at 10-second intervals (5+ minutes total)
- Prevents nginx from proxying to a non-existent server

Fixes #30183

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-21 21:51:14 -08:00

279 lines
9.1 KiB
YAML

#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# -----------------------------------------------------------------------
# We don't support docker compose for production environments.
# If you choose to use this type of deployment make sure to
# create you own docker environment file (docker/.env) with your own
# unique random secure passwords and SECRET_KEY.
#
# For verbose logging during development:
# - Set SUPERSET_LOG_LEVEL=debug in docker/.env-local for detailed Superset logs
# -----------------------------------------------------------------------
x-superset-user: &superset-user root
x-superset-volumes: &superset-volumes
# /app/pythonpath_docker will be appended to the PYTHONPATH in the final container
- ./docker:/app/docker
- ./superset:/app/superset
- ./superset-core:/app/superset-core
- ./superset-frontend:/app/superset-frontend
- superset_home:/app/superset_home
- ./tests:/app/tests
- superset_data:/app/data
x-common-build: &common-build
context: .
target: ${SUPERSET_BUILD_TARGET:-dev} # can use `dev` (default) or `lean`
cache_from:
- apache/superset-cache:3.10-slim-trixie
args:
DEV_MODE: "true"
INCLUDE_CHROMIUM: ${INCLUDE_CHROMIUM:-false}
INCLUDE_FIREFOX: ${INCLUDE_FIREFOX:-false}
BUILD_TRANSLATIONS: ${BUILD_TRANSLATIONS:-false}
services:
nginx:
env_file:
- path: docker/.env # default
required: true
- path: docker/.env-local # optional override
required: false
image: nginx:latest
restart: unless-stopped
ports:
- "${NGINX_PORT:-80}:80"
extra_hosts:
- "host.docker.internal:host-gateway"
volumes:
- ./docker/nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./docker/nginx/templates:/etc/nginx/templates:ro
depends_on:
superset-node:
condition: service_healthy
redis:
image: redis:7
restart: unless-stopped
ports:
- "127.0.0.1:${REDIS_PORT:-6379}:6379"
volumes:
- redis:/data
db:
env_file:
- path: docker/.env # default
required: true
- path: docker/.env-local # optional override
required: false
image: postgres:17
restart: unless-stopped
ports:
- "127.0.0.1:${DATABASE_PORT:-5432}:5432"
volumes:
- db_home:/var/lib/postgresql/data
- ./docker/docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d
superset:
env_file:
- path: docker/.env # default
required: true
- path: docker/.env-local # optional override
required: false
build:
<<: *common-build
command: ["/app/docker/docker-bootstrap.sh", "app"]
restart: unless-stopped
ports:
- ${SUPERSET_PORT:-8088}:8088
# When in cypress-mode ->
- ${CYPRESS_PORT:-8081}:8081
extra_hosts:
- "host.docker.internal:host-gateway"
user: *superset-user
depends_on:
superset-init:
condition: service_completed_successfully
volumes: *superset-volumes
superset-websocket:
build: ./superset-websocket
ports:
- ${WEBSOCKET_PORT:-8080}:8080
extra_hosts:
- "host.docker.internal:host-gateway"
depends_on:
- redis
# Mount everything in superset-websocket into container and
# then exclude node_modules and dist with bogus volume mount.
# This is necessary because host and container need to have
# their own, separate versions of these files. .dockerignore
# does not seem to work when starting the service through
# docker compose.
#
# For example, node_modules may contain libs with native bindings.
# Those bindings need to be compiled for each OS and the container
# OS is not necessarily the same as host OS.
volumes:
- ./superset-websocket:/home/superset-websocket
- /home/superset-websocket/node_modules
- /home/superset-websocket/dist
# Mount config file. Create your own docker/superset-websocket/config.json
# for custom settings, then point to it here. Do not use this example in production.
- ./docker/superset-websocket/config.example.json:/home/superset-websocket/config.json:ro
environment:
- PORT=8080
- REDIS_HOST=redis
- REDIS_PORT=6379
- REDIS_SSL=false
superset-init:
build:
<<: *common-build
command: ["/app/docker/docker-init.sh"]
env_file:
- path: docker/.env # default
required: true
- path: docker/.env-local # optional override
required: false
depends_on:
db:
condition: service_started
redis:
condition: service_started
user: *superset-user
volumes: *superset-volumes
healthcheck:
disable: true
superset-node:
build:
context: .
target: superset-node
args:
# This prevents building the frontend bundle since we'll mount local folder
# and build it on startup while firing docker-frontend.sh in dev mode, where
# it'll mount and watch local files and rebuild as you update them
DEV_MODE: "true"
BUILD_TRANSLATIONS: ${BUILD_TRANSLATIONS:-false}
environment:
# set this to false if you have perf issues running the npm i; npm run dev in-docker
# if you do so, you have to run this manually on the host, which should perform better!
BUILD_SUPERSET_FRONTEND_IN_DOCKER: true
NPM_RUN_PRUNE: false
SCARF_ANALYTICS: "${SCARF_ANALYTICS:-}"
# configuring the dev-server to use the host.docker.internal to connect to the backend
superset: "http://superset:8088"
# Webpack dev server must bind to 0.0.0.0 to be accessible from outside the container
WEBPACK_DEVSERVER_HOST: "0.0.0.0"
ports:
- "127.0.0.1:${NODE_PORT:-9000}:9000" # exposing the dynamic webpack dev server
command: ["/app/docker/docker-frontend.sh"]
env_file:
- path: docker/.env # default
required: true
- path: docker/.env-local # optional override
required: false
volumes: *superset-volumes
healthcheck:
# Check if webpack dev server is responding on port 9000
# This prevents nginx from proxying before the frontend is ready
test: ["CMD-SHELL", "node -e \"const http = require('http'); http.get('http://localhost:9000', (r) => process.exit(r.statusCode === 200 ? 0 : 1)).on('error', () => process.exit(1))\""]
interval: 10s
timeout: 5s
retries: 30
start_period: 60s
superset-worker:
build:
<<: *common-build
command: ["/app/docker/docker-bootstrap.sh", "worker"]
env_file:
- path: docker/.env # default
required: true
- path: docker/.env-local # optional override
required: false
environment:
CELERYD_CONCURRENCY: 2
restart: unless-stopped
depends_on:
superset-init:
condition: service_completed_successfully
user: *superset-user
volumes: *superset-volumes
extra_hosts:
- "host.docker.internal:host-gateway"
healthcheck:
test: ["CMD-SHELL", "celery -A superset.tasks.celery_app:app inspect ping -d celery@$$HOSTNAME"]
# Bump memory limit if processing selenium / thumbnails on superset-worker
# mem_limit: 2038m
# mem_reservation: 128M
superset-worker-beat:
build:
<<: *common-build
command: ["/app/docker/docker-bootstrap.sh", "beat"]
env_file:
- path: docker/.env # default
required: true
- path: docker/.env-local # optional override
required: false
restart: unless-stopped
depends_on:
- superset-worker
user: *superset-user
volumes: *superset-volumes
healthcheck:
disable: true
superset-tests-worker:
build:
<<: *common-build
command: ["/app/docker/docker-bootstrap.sh", "worker"]
env_file:
- path: docker/.env # default
required: true
- path: docker/.env-local # optional override
required: false
profiles:
- optional
environment:
DATABASE_HOST: localhost
DATABASE_DB: test
REDIS_CELERY_DB: 2
REDIS_RESULTS_DB: 3
REDIS_HOST: localhost
CELERYD_CONCURRENCY: 8
network_mode: host
depends_on:
superset-init:
condition: service_completed_successfully
user: *superset-user
volumes: *superset-volumes
healthcheck:
test: ["CMD-SHELL", "celery inspect ping -A superset.tasks.celery_app:app -d celery@$$HOSTNAME"]
volumes:
superset_home:
external: false
db_home:
external: false
redis:
external: false
superset_data:
external: false