From fef0a64b21d7cbcac0eff2fa0be326b82f064d3a Mon Sep 17 00:00:00 2001 From: Mike Bridge Date: Thu, 7 May 2026 11:53:57 -0600 Subject: [PATCH] fix(docker): MySQL examples DB + EXAMPLES_PORT override (sc-105349) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix two follow-on issues reported when starting the dev stack with docker-compose-mysql.yml: 1. ``superset-init`` step 4 (load-examples) fails with ``MySQLdb.OperationalError: (2002, "Can't connect to server on 'db'")`` because the analytics-examples DB connection inherits ``EXAMPLES_PORT=5432`` (Postgres port) from ``docker/.env``. The override flipped ``DATABASE_DIALECT`` to ``mysql+mysqldb`` but left the EXAMPLES_* group on Postgres defaults, so the URI became ``mysql+mysqldb://examples:examples@db:5432/examples`` — MySQL container has no listener on 5432. Fix: add ``EXAMPLES_HOST/PORT/DB/USER/PASSWORD`` and a complete ``SUPERSET__SQLALCHEMY_EXAMPLES_URI`` to the ``mysql-env`` anchor. 2. The Postgres init scripts under ``docker/docker-entrypoint-initdb.d/`` (``cypress-init.sh``, ``examples-init.sh``) get mounted on the MySQL container too — compose merges volume lists. They invoke ``psql`` which doesn't exist in the MySQL image, abort with ``psql: command not found``, and prevent the ``examples`` DB from being created. Fix: add a MySQL-specific init script ``docker/mysql-init/examples-init.sql`` that creates the ``examples`` database and user, and mount it at ``/docker-entrypoint-initdb.d`` in the override. Compose's later-takes-precedence rule on duplicate volume targets displaces the Postgres init dir, so the MySQL container only sees the MySQL-compatible script. (Used a plain duplicate-target mount rather than the ``!override`` tag because pre-commit's ``check-yaml`` doesn't recognize Compose's custom YAML tags.) Recovery for an existing failed MySQL stack: ``docker compose -f docker-compose.yml -f docker-compose-mysql.yml down``, then ``docker volume rm superset_db_home_mysql`` (so the new init script runs on the next fresh boot), then ``up`` again. Co-Authored-By: Claude Opus 4.7 (1M context) --- docker-compose-mysql.yml | 24 ++++++++++++++++++++++ docker/mysql-init/examples-init.sql | 32 +++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 docker/mysql-init/examples-init.sql diff --git a/docker-compose-mysql.yml b/docker-compose-mysql.yml index 4617eaaf0e2..13f4c99236c 100644 --- a/docker-compose-mysql.yml +++ b/docker-compose-mysql.yml @@ -48,6 +48,17 @@ x-mysql-env: &mysql-env DATABASE_USER: superset DATABASE_PASSWORD: superset SQLALCHEMY_DATABASE_URI: "mysql+mysqldb://superset:superset@db:3306/superset?charset=utf8mb4&binary_prefix=true" + # Override the analytics-examples DB connection too. ``EXAMPLES_PORT`` + # in docker/.env is hardcoded to 5432 (the Postgres port); without + # this override the examples connection would try MySQL on 5432 and + # fail. The examples user/DB are created by docker/mysql-init/ + # examples-init.sql on first MySQL boot. + EXAMPLES_HOST: db + EXAMPLES_PORT: "3306" + EXAMPLES_DB: examples + EXAMPLES_USER: examples + EXAMPLES_PASSWORD: examples + SUPERSET__SQLALCHEMY_EXAMPLES_URI: "mysql+mysqldb://examples:examples@db:3306/examples?charset=utf8mb4&binary_prefix=true" services: db: @@ -57,10 +68,23 @@ services: MYSQL_USER: superset MYSQL_PASSWORD: superset MYSQL_ROOT_PASSWORD: root + # The original 5432 port mapping is harmless on a MySQL container + # (nothing listens on 5432 inside it) but we add 13306->3306 so the + # MySQL port is reachable from the host without colliding with a + # native MySQL on 3306. Compose merges port lists. ports: - "127.0.0.1:${DATABASE_PORT_MYSQL:-13306}:3306" + # Override the init-scripts mount by re-binding the same target path + # to a MySQL-compatible directory. Compose merges volume lists by + # target path; later definitions win on conflict, so this displaces + # the Postgres-specific ``./docker/docker-entrypoint-initdb.d`` mount + # from docker-compose.yml. Without this, MySQL would try to run + # ``cypress-init.sh`` (which invokes ``psql``, not in the MySQL + # image), abort the init phase, and never create the ``examples`` + # database. Add the MySQL data volume separately. volumes: - db_home_mysql:/var/lib/mysql + - ./docker/mysql-init:/docker-entrypoint-initdb.d command: - --default-authentication-plugin=caching_sha2_password - --character-set-server=utf8mb4 diff --git a/docker/mysql-init/examples-init.sql b/docker/mysql-init/examples-init.sql new file mode 100644 index 00000000000..68dabe38671 --- /dev/null +++ b/docker/mysql-init/examples-init.sql @@ -0,0 +1,32 @@ +-- 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. + +-- MySQL counterpart to docker/docker-entrypoint-initdb.d/examples-init.sh. +-- Creates the analytics-examples database and user that Superset's +-- ``load-examples`` command writes to. Mounted by docker-compose-mysql.yml +-- at /docker-entrypoint-initdb.d/ so the MySQL image's first-boot +-- entrypoint runs it automatically. (The Postgres init scripts under +-- docker/docker-entrypoint-initdb.d/ are NOT mounted on the MySQL +-- service — they invoke psql, which doesn't exist in the MySQL image.) + +CREATE DATABASE IF NOT EXISTS examples + CHARACTER SET utf8mb4 + COLLATE utf8mb4_0900_ai_ci; + +CREATE USER IF NOT EXISTS 'examples'@'%' IDENTIFIED BY 'examples'; +GRANT ALL PRIVILEGES ON examples.* TO 'examples'@'%'; +FLUSH PRIVILEGES;