Apache Superset をソースコードから起動してカスタマイズする方法


なぜ Apache Superset?
BI(ビジネスインテリジェンス)ツールを選定する時、いくつかの条件があると思います。
その中では「機能性」が用途に応えられるのかが選定条件の一つになると思います。
数多のBIツールから一つ一つ調査することになります。
最近の流行りだと
・Tableau ← 非常に優秀だが、ライセンス料金がそれなりにかかる
・Looker Studio ← 無料で機能性も充実だが、Google アカウントや Google Cloud との連携を前提とした使い方になることが多いなど。
・Kibana + Elastic Search ← 高速で機能性も充実だが、ドキュメントベースでリレーショナルの DB と違って、 ESQL の勉強などが必要
・その他、色々
幾つかのツールを使ってみて感じたのは、どのツールも必ず一長一短があります。
であれば、足りない機能を自分たちで実装できる BI ツールがいいのでは?
それが Apache Superset です。

superset のコードを改変し、ソースから起動する
Superset の良いところ、気になるところ

superset のコミュニティはかなり大きい
良いところ
・無料
・コミュニティが大きい
・Opensource なのでいくらでも改変できる
・エンジニアなら自由度が高い
気になるところ
・グラフの種類がわりと少ない
・グラフの Layer 機能がない
・改変はできるが Python と React の知識が必要
・Kibana + Elastic Search など高速設計エンジンに比べると遅い
上記の理由から、本記事では Superset をソースコードから起動する手順を整理して紹介します。公式ドキュメントにも開発手順はありますが、設定や構成が複雑だったりして、Docker に不慣れだと動作確認に悩む場面があると思います。そこで、本記事では実際に試した際につまずいたり補足が必要だと感じたポイントも含めて解説します。
Superset をソースコードから起動する
選定条件
インストールするために Git, Python (Backend), Npm (Frontend) とデータベースが必要です。
開発環境汚染を防止するため、docker を使います。
ソースコードを取得する
Superset のソースコードは Github で公開しています。
https://github.com/apache/superset
まずは github から clone してソースコードを取得します。
git clone https://github.com/apache/superset.gitすると、superset のフォルダができますので、下記のコマンドで出来たフォルダに入ります。
cd supersetそのままだと main ブランチの古いコードになるので、新しいバージョンに切り替えます。
今回は 6.0.0rc2 を使用します。テーマや細かい権限管理できるバージョンなのでおすすめです。(あくまでローカル開発・検証環境の構築を対象としています)
git checkout -b 6.0.0rc2 6.0.0rc2
6.0.0rc2 を checkout した結果
カスタム Docker コンテナ作成
git から clone したディレクトリにも docker-compose.yml がありますが、不要な設定も多いため、
今回は使いません。
下記は docker-compose.yml です。
仮の設定が多いため、Production などでは使わないでください。
services:
postgres-db:
image: postgres:17
restart: always
container_name: postgres-db
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: postgres
POSTGRES_HOST: postgres-db
ports:
- 5432:5432
networks:
- superset_network
superset:
build: .
container_name: superset
tty: true
volumes:
- .:/app
ports:
- 8088:8088
- 9000:9000
networks:
- superset_network
environment:
PYTHONUNBUFFERED: 1
ENABLE_PLAYWRIGHT: false
PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: true
BUILD_SUPERSET_FRONTEND_IN_DOCKER: true
SECRET_KEY: 029348uhfdaspf8uya
SUPERSET_SECRET_KEY: 029348uhfdaspf8uya
FLASK_APP: superset
COMPOSE_PROJECT_NAME: superset
DEV_MODE: true
DATABASE_DB: superset
DATABASE_HOST: postgres-db
DATABASE_PASSWORD: postgres
DATABASE_USER: postgres
EXAMPLES_DB: superset
EXAMPLES_HOST: postgres-db
EXAMPLES_USER: postgres
EXAMPLES_PASSWORD: postgres
EXAMPLES_PORT: 5432
DATABASE_PORT: 5432
DATABASE_DIALECT: postgresql
POSTGRES_DB: superset
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
PYTHONPATH: /app/pythonpath:/app/docker/pythonpath_dev
REDIS_HOST: redis
REDIS_PORT: 6379
FLASK_DEBUG: true
SUPERSET_LOG_LEVEL: info
SUPERSET_APP_ROOT: /
SUPERSET_ENV: development
SUPERSET_LOAD_EXAMPLES: no
SUPERSET_PORT: 8088
CYPRESS_CONFIG: false
MAPBOX_API_KEY: ''
networks:
superset_network:
name: "superset_network"
driver: bridgeそして Dockerfile です。
FROM debian:12-slim
RUN apt update
RUN apt upgrade
RUN apt install -y curl build-essential gnupg ca-certificates python3.11 python3.11-dev python3.11-venv libssl-dev libffi-dev libsasl2-dev libldap2-dev default-libmysqlclient-dev
RUN apt install -y zstd
ARG NODE_MAJOR=20
RUN mkdir -p /etc/apt/keyrings && \
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg && \
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list
# Update APT and install Node.js
RUN apt-get update && \
apt-get install -y nodejs && \
rm -rf /var/lib/apt/lists/*
WORKDIR /app上記の docker-compose.yml と Dockerfile を一緒に superset のルートディレクトリにおいてください。
既存の docker-compose.yml と Dockerfile があるので、上書きか、消してください。
次は docker compose でコンテナを作成します。
sudo docker compose up -dこれで下準備のデータベースとソース開発用のコンテナができています。
Superset 用のデータベース作成
下記のコマンドで postgres-db のコンテナ内に入ります。
docker exec -it -u postgres postgres-db /bin/bash
lspsql コマンドで postgresql に接続します。
psqlSuperset 用のデータベースを作成しておきます。
create database superset;その後 exit を 2 回入力して postgresql、コンテナから出ます。

\l コマンドでデータベースが作成されたことを確認できます。
バックエンドサーバのセットアップ
バックエンドサーバ(Python)をセットアップします。
下記のコマンドで python3 を使いますが、システムによっては python だったりします。
まずは Python の Dependencies をインストールしますが、
今回は mysql ではなく、 postgresql を使いますので、
requirements/development.txt をちょっと編集します。
452 行目のところに mysqlclient を消すか、コメントアウトします。
また、authlib==1.6.5 をつけることで各認証機能を有効できます。
authlib==1.6.5# mysqlclient==2.2.6 #コメントアウトすることで、ライブラリをインストールしなくなります。# # via apache-superset次にコンテナ内で操作するため、 docker exec でコンテナ内に入ります。
docker exec -it superset /bin/bash
ls
コンテナ内のファイルがちゃんとマウントされているところの確認
また、python の仮想環境から作ることをおすすめします。下記のコマンドは python 仮想環境から作成します。
python3 -m venv venv
source venv/bin/activatepip で python の必要ライブラリパッケージをインストールします。
pip install -r requirements/development.txt
pip install -e .
pip でライブラリパッケージインストール完了
superset のコマンドが使えるようになるので、superset コマンドで db 作成します。
superset db upgrade
admin ユーザを作成します。
superset fab create-admin
任意ですが、サンプルのデータ入れます。
superset load_examplessuperset を初期化します。
superset init
最後に、superset のバックエンドサーバを起動します。
下記の例はポート 8088 に起動します。
superset run -p 8088 -h 0.0.0.0 --with-threads --reload --debugger --debugこれでバックエンドサーバのセットアップは完了です。
ただ、フロントエンドサーバは今ないので、このまま localhost:8088 に接続すると、
404エラーになります。
フロントエンドサーバのセットアップ
フロントエンドサーバのソースコードは clone したレポジトリーの superset-frontend フォルダにあります。
バックエンドの terminal 起動したままで、別の terminal 開いてまたコンテナに入り直します。
docker exec -it superset /bin/bash
lsフロントエンドサーバのフォルダに入ります。
cd superset-frontendフロントエンドサーバは React で、 node バージョン 20.18.1 以上と npm バージョン 10.8.1 以上が必要です。
node と npm のインストールは Dockerfile で既に行なっているので問題ありません。
初期ライブラリをインストールします。
npm installフロントエンドサーバをビルドします。
初回ビルドなので、時間かかります。
npm run buildこれでフロントエンドも起動できるようになりましたので、下記のコマンドで起動します。
npm run dev
しばらくビルドしたら起動完了します。
コンフィグを編集する
Superset は Redis を通して WebSocket を使っているので、
今回は使わないため、コンフィグを編集して無効にします。
docker/pythonpath_dev/superset_config.py を開いて編集します。
import logging
import os
import sys
from celery.schedules import crontab
from flask_caching.backends.filesystemcache import FileSystemCache
logger = logging.getLogger()
DATABASE_DIALECT = os.getenv("DATABASE_DIALECT")
DATABASE_USER = os.getenv("DATABASE_USER")
DATABASE_PASSWORD = os.getenv("DATABASE_PASSWORD")
DATABASE_HOST = os.getenv("DATABASE_HOST")
DATABASE_PORT = os.getenv("DATABASE_PORT")
DATABASE_DB = os.getenv("DATABASE_DB")
EXAMPLES_USER = os.getenv("EXAMPLES_USER")
EXAMPLES_PASSWORD = os.getenv("EXAMPLES_PASSWORD")
EXAMPLES_HOST = os.getenv("EXAMPLES_HOST")
EXAMPLES_PORT = os.getenv("EXAMPLES_PORT")
EXAMPLES_DB = os.getenv("EXAMPLES_DB")
# The SQLAlchemy connection string.
SQLALCHEMY_DATABASE_URI = (
f"{DATABASE_DIALECT}://"
f"{DATABASE_USER}:{DATABASE_PASSWORD}@"
f"{DATABASE_HOST}:{DATABASE_PORT}/{DATABASE_DB}"
)
SQLALCHEMY_EXAMPLES_URI = (
f"{DATABASE_DIALECT}://"
f"{EXAMPLES_USER}:{EXAMPLES_PASSWORD}@"
f"{EXAMPLES_HOST}:{EXAMPLES_PORT}/{EXAMPLES_DB}"
)
# ---------- WebSocket を無効します ----------
WEBSOCKET_ENABLED = False
# ---------- キャッシュの種類を変更を無効します ----------
CACHE_CONFIG = {
"CACHE_TYPE": "SimpleCache",
"CACHE_DEFAULT_TIMEOUT": 86400,
"CACHE_THRESHOLD": 10000,
}
QUERY_SEARCH_CACHE_CONFIG = {
'CACHE_TYPE': 'SimpleCache',
'CACHE_DEFAULT_TIMEOUT': 86400,
'CACHE_THRESHOLD': 10000,
}
FILTER_STATE_CACHE_CONFIG = {
'CACHE_TYPE': 'SimpleCache',
'CACHE_DEFAULT_TIMEOUT': 86400,
'CACHE_THRESHOLD': 10000,
}
# ---------- Redis 設定をコメントアウトして、無効にします ----------
# REDIS_HOST = os.getenv("REDIS_HOST", "redis")
# REDIS_PORT = os.getenv("REDIS_PORT", "6379")
# REDIS_CELERY_DB = os.getenv("REDIS_CELERY_DB", "0")
# REDIS_RESULTS_DB = os.getenv("REDIS_RESULTS_DB", "1")
#
# RESULTS_BACKEND = FileSystemCache("/app/superset_home/sqllab")
#
# CACHE_CONFIG = {
# "CACHE_TYPE": "RedisCache",
# "CACHE_DEFAULT_TIMEOUT": 300,
# "CACHE_KEY_PREFIX": "superset_",
# "CACHE_REDIS_HOST": REDIS_HOST,
# "CACHE_REDIS_PORT": REDIS_PORT,
# "CACHE_REDIS_DB": REDIS_RESULTS_DB,
# }
# DATA_CACHE_CONFIG = CACHE_CONFIG
# THUMBNAIL_CACHE_CONFIG = CACHE_CONFIG
#
#
# class CeleryConfig:
# broker_url = f"redis://{REDIS_HOST}:{REDIS_PORT}/{REDIS_CELERY_DB}"
# imports = (
# "superset.sql_lab",
# "superset.tasks.scheduler",
# "superset.tasks.thumbnails",
# "superset.tasks.cache",
# )
# result_backend = f"redis://{REDIS_HOST}:{REDIS_PORT}/{REDIS_RESULTS_DB}"
# worker_prefetch_multiplier = 1
# task_acks_late = False
# beat_schedule = {
# "reports.scheduler": {
# "task": "reports.scheduler",
# "schedule": crontab(minute="*", hour="*"),
# },
# "reports.prune_log": {
# "task": "reports.prune_log",
# "schedule": crontab(minute=10, hour=0),
# },
# }
#
#
# CELERY_CONFIG = CeleryConfig
FEATURE_FLAGS = {"ALERT_REPORTS": True}
ALERT_REPORTS_NOTIFICATION_DRY_RUN = True
WEBDRIVER_BASEURL = f"http://superset_app{os.environ.get('SUPERSET_APP_ROOT', '/')}/" # When using docker compose baseurl should be http://superset_nginx{ENV{BASEPATH}}/ # noqa: E501
# The base URL for the email report hyperlinks.
WEBDRIVER_BASEURL_USER_FRIENDLY = (
f"http://localhost:8888/{os.environ.get('SUPERSET_APP_ROOT', '/')}/"
)
SQLLAB_CTAS_NO_LIMIT = True
log_level_text = os.getenv("SUPERSET_LOG_LEVEL", "INFO")
LOG_LEVEL = getattr(logging, log_level_text.upper(), logging.INFO)
if os.getenv("CYPRESS_CONFIG") == "true":
# When running the service as a cypress backend, we need to import the config
# located @ tests/integration_tests/superset_test_config.py
base_dir = os.path.dirname(__file__)
module_folder = os.path.abspath(
os.path.join(base_dir, "../../tests/integration_tests/")
)
sys.path.insert(0, module_folder)
from superset_test_config import * # noqa
sys.path.pop(0)
#
# Optionally import superset_config_docker.py (which will have been included on
# the PYTHONPATH) in order to allow for local settings to be overridden
#
try:
import superset_config_docker
from superset_config_docker import * # noqa: F403
logger.info(
f"Loaded your Docker configuration at [{superset_config_docker.__file__}]"
)
except ImportError:
logger.info("Using default Docker config...")バックエンドサーバを起動したままなので、 Hot Reload 機能でコンフィグが編集された時すぐに変更が反映します。
Superset を試す
Webブラウザを開いて http://localhost:8088/ に入ると下記の画面がでれば設定がうまくいってます。
superset fab create-admin で作った user/pass を入力すれば入ります。

ログイン画面が出ていれば設定に問題なくできました。

ログイン後の画面
Superset をカスタマイズしてみる
やっとソースコードから起動できましたので、利点であるコードの改変に試しましょう。
まずは簡単なものから紹介します。
フロントエンドのコードを変更してみる
Superset のフロントエンドのソースコードは root フォルダから superset-frontend フォルダーにあります。

今回は試しに**「テーマを強制的に Dark Theme にする」**のソース変更をしてみましょう。
superset-frontend/src/theme/ThemeController.ts の 147行あたりに下記のように編集します。
// Initialize theme and mode
this.currentMode = this.determineInitialMode();
const initialTheme =
this.getThemeForMode(ThemeMode.DARK) || this.defaultTheme;
//this.getThemeForMode(this.currentMode) || this.defaultTheme;this.currentMode → ThemeMode.DARK に変更することで、システム設定関係なく強制的に Dark Mode にすることができます。
変更が自動的に反映されます。

コード編集すると自動でコンパイルしてくれます
ブラウザを更新するとテーマが Dark Mode に変更されたことが確認できます。

Dark Mode に変更されました
Superset グラフの種類を増やしてみる
Superset のグラフの種類は他の有名 BI ツールと比べると少なく、
増やしたい気持ちが強いです。
本来は使用目的に伴って色々コード改変、もしくは作成しますが、
今回は単純に増やすことをしてみます。
Superset のグラフのソースコードは superset-frontend/plugins フォルダにあります。

今回は下記の画像の Histogramと同じものを増やしてみます。
上のメニュの Charts → +New Chart でこのメニューをアクセスできます。


Histogram を複製します
superset-frontend/plugins/plugin-chart-echarts/Histogram
のフォルダを同じ階層で複製して、 フォルダ名を Histogram_New にします。

superset-frontend/plugins/plugin-chart-echarts/src/Histogram_New/index.ts
を編集します。
30行目の EchartsHistogramChartPlugin を EchartsHistogramNewChartPlugin にします。
// TODO: Implement cross filtering
// export default class EchartsHistogramChartPlugin extends ChartPlugin<
export default class EchartsHistogramNewChartPlugin extends ChartPlugin<
HistogramFormData,
HistogramChartProps
> {新しいグラフクラスができているので、index に追加します。
superset-frontend/plugins/plugin-chart-echarts/src/index.ts の31行あたりに追加します。
export { default as EchartsGraphChartPlugin } from './Graph';
export { default as EchartsGaugeChartPlugin } from './Gauge';
export { default as EchartsHistogramChartPlugin } from './Histogram';
// HistogramNew を追加
export { default as EchartsHistogramNewChartPlugin } from './Histogram_New';
export { default as EchartsRadarChartPlugin } from './Radar';
export { default as EchartsFunnelChartPlugin } from './Funnel';superset-frontend/packages/superset-ui-core/src/chart/types/VizType.ts の 39行目あたりに新しいタイプを増やす
Handlebars = 'handlebars',
Heatmap = 'heatmap_v2',
Histogram = 'histogram_v2',
HistogramNew = 'histogram_New', // 追加
Horizon = 'horizon',
LegacyBubble = 'bubble',最後に superset-frontend/src/visualizations/presets/MainPreset.js で 169行目あたりに新しいグラフを追加します。
new EchartsHeatmapChartPlugin().configure({ key: VizType.Heatmap }),
new EchartsHistogramChartPlugin().configure({ key: VizType.Histogram }),
//追加
new EchartsHistogramNewChartPlugin().configure({ key: VizType.HistogramNew }),
new SelectFilterPlugin().configure({ key: FilterPlugins.Select }),上記の編集が終わったらもう一度グラフのリスト画面に入ると追加したグラフが増えていることを確認できます。

Histogram New が増えました
最後に
今回は時間の都合でフロントエンドの簡単な改変しか紹介できませんでしたが、
また時間ができたらバックエンドの機能改変方法や、全く新しいグラフ作製方法なども紹介したいと思います。
では、また次回に!
