目录
前言 :为什么要写这篇文章?
一、superset是什么?
二、建议软件
三、安装步骤
1.安装docker
2.拉取源码
3.修改源码的dockerfile
4.创建superset容器
5.修改容器内的账号密码
6.修改Superset仪表盘(Dashboard)可以匿名访问(免登录)
7.发布dashboard并自定义url
四、二次开发(自定义图表)
1.创建一个简单的 Hello World viz 插件
2.运行
3.创建一个其他的图表(集成echarts)
4.创建一个百度地图插件(使用echarts+echarts for react)
√ 我希望通过 Docker 在服务器上安装 Superset,以便于独立构建 Superset 环境。
× 我不想使用 Docker Compose,因为是多容器部署,且服务器环境不便于进行二次开发。
× 我不想使用 Pip 安装,因为这会导致缺失 superset-frontend 目录,无法修改前端代码和自定义 Superset 的图表等内容。
× 我不想使用 Dockerhub 上的镜像,因为官方 apache/superset镜像 缺失 superset-frontend 目录下内容,而 amancevice/superset镜像则是使用 pip 安装 Superset,都无法修改前端代码和自定义 Superset 的图表等内容。
× Superset 的版本更新比较频繁,因此版本信息比较混乱。目前官方文档比较落后且存在错误,也没有针对特定版本进行说明和指导。
Superset 是一个基于 Python Flask 和 Apache Superset 的数据可视化和探索平台。它是由 Airbnb 在 2015 年发布的,并于 2017 年开源,现已成为 Apache 基金会孵化项目之一。
Superset 提供了一个交互式的数据可视化界面,支持从多种数据源中获取和探索数据,如 SQL 数据库、NoSQL 数据库、搜索引擎等。用户可以通过 Superset 快速创建和共享数据分析和可视化应用,支持多种图表类型和样式,包括折线图、柱状图、散点图、地图等。
我建议您使用 VScode 软件,并安装 Remote-SSH 插件来远程连接您的服务器。此外,您可以安装 Docker 插件来方便地管理 Docker 容器和镜像。
请参考安装Docker详细步骤总结,这里就不重复了。
创建并进入superset文件夹
mkdir superset && cd superset
初始化空的 Git 版本库
git init
从github上拉取源码
git clone https://github.com/apache/superset.git
或 国内可以通过gitee镜像拉取源码,并与远程仓库建立连接
git clone https://gitee.com/mirrors/Superset.git
进入Superset文件夹内
cd Superset
切换到2.1.0版本
git checkout 2.1.0
该 Dockerfile 有三个部分,分别对应三个阶段:
第一部分是 Node 阶段,用于构建静态资源。
第二部分是 Lean 阶段,用于实际运行程序,并生成可发布的 Docker 镜像。
第三部分是 Dev 阶段,用于开发环境。
我们需要对dockerfile做出以下修改:(修改好的dockerfile在后面)
修改依赖为python3.8.16版本和node16版本
在Lean阶段修改apt源,将它改为阿里源
在Lean阶段,在运行环境中通过apt安装sudo
在Lean阶段,在运行环境中安装node16(二次开发需要node16和npm7或8版本)
在Lean阶段将只复制superset-frontend/package.json文件改成从node阶段复制整个superset-frontend文件夹到运行环境
在Lean阶段修改pip源,将它改为阿里源
在Lean阶段复制superset文件夹后,superset汉化,修改config.py(我直接在构建镜像阶段修改了,也可以在启动镜像后手动修改),手动修改如下:
手动修改config.py中BABEL_DEFAULT_LOCALE = "en" 将en改成zh(或通过命令行修改如下)
sed -i 's/BABEL_DEFAULT_LOCALE = "en"/BABEL_DEFAULT_LOCALE = "zh"/g' /app/superset/config.py
在 superset根目录\superset\translations 目录下执行命令:若手动修改时Pybabel命令存在问题,先卸载再安装后执行
pybabel compile -d . #注意最后的 .
pip uninstall --yes babel && /usr/local/bin/python -m pip install babel
以下是我修改后的dockerfile
#
# 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.
#
######################################################################
# Node stage to deal with static asset construction
######################################################################
ARG PY_VER=3.8.16
FROM node:16 AS superset-node
ARG NPM_BUILD_CMD="build"
ENV BUILD_CMD=${NPM_BUILD_CMD}
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
# NPM ci first, as to NOT invalidate previous steps except for when package.json changes
RUN mkdir -p /app/superset-frontend
COPY ./docker/frontend-mem-nag.sh /
RUN /frontend-mem-nag.sh
WORKDIR /app/superset-frontend/
COPY superset-frontend/package*.json ./
# 若此npm源不好用,删除npm config set registry https://registry.npmmirror.com && \
RUN npm config set registry https://registry.npmmirror.com && \
npm ci
COPY ./superset-frontend .
# This seems to be the most expensive step
RUN npm run ${BUILD_CMD}
######################################################################
# Final lean image...
######################################################################
FROM python:${PY_VER} AS lean
ENV LANG=C.UTF-8 \
LC_ALL=C.UTF-8 \
FLASK_ENV=production \
FLASK_APP="superset.app:create_app()" \
PYTHONPATH="/app/pythonpath" \
SUPERSET_HOME="/app/superset_home" \
SUPERSET_PORT=8088
RUN sed -i 's/http:\/\/deb.debian.org\/debian/http:\/\/mirrors.aliyun.com\/debian/g' /etc/apt/sources.list \
&& sed -i 's/http:\/\/security.debian.org\/debian-security/http:\/\/mirrors.aliyun.com\/debian-security/g' /etc/apt/sources.list \
&& mkdir -p ${PYTHONPATH} \
&& useradd --user-group -d ${SUPERSET_HOME} -m --no-log-init --shell /bin/bash superset \
&& apt-get update -y \
&& apt-get upgrade -y \
&& apt-get install -y --no-install-recommends \
build-essential \
curl \
default-libmysqlclient-dev \
libsasl2-dev \
libsasl2-modules-gssapi-mit \
libpq-dev \
libecpg-dev \
sudo \
&& apt-get install -y curl dirmngr apt-transport-https lsb-release ca-certificates \
&& curl -sL https://deb.nodesource.com/setup_16.x | sudo -E bash - \
&& apt-get install -y nodejs \
&& rm -rf /var/lib/apt/lists/* \
&& npm config set registry https://registry.npmmirror.com
# 若此npm源不好用,删除行&& npm config set registry https://registry.npmmirror.com
COPY ./requirements/*.txt /app/requirements/
COPY setup.py MANIFEST.in README.md /app/
# setup.py uses the version information in package.json
COPY ./superset-frontend /app/superset-frontend
RUN mkdir ~/.pip/ \
&& echo '[global]' > ~/.pip/pip.conf \
&& echo 'index-url = https://mirrors.aliyun.com/pypi/simple/' >> ~/.pip/pip.conf \
&& echo 'trusted-host = mirrors.aliyun.com' >> ~/.pip/pip.conf \
&& cd /app \
&& mkdir -p superset/static \
&& touch superset/static/version_info.json \
&& pip install --no-cache -r requirements/local.txt
COPY --from=superset-node /app/superset/static/assets /app/superset/static/assets
## Lastly, let's install superset itself
COPY superset /app/superset
RUN sed -i 's/BABEL_DEFAULT_LOCALE = "en"/BABEL_DEFAULT_LOCALE = "zh"/g' /app/superset/config.py
COPY setup.py MANIFEST.in README.md /app/
RUN cd /app \
&& chown -R superset:superset * \
&& pip install -e . \
&& flask fab babel-compile --target superset/translations
COPY ./docker/run-server.sh /usr/bin/
RUN chmod a+x /usr/bin/run-server.sh
WORKDIR /app
USER superset
HEALTHCHECK CMD curl -f "http://localhost:$SUPERSET_PORT/health"
EXPOSE ${SUPERSET_PORT}
CMD /usr/bin/run-server.sh
######################################################################
# Dev image...
######################################################################
FROM lean AS dev
ARG GECKODRIVER_VERSION=v0.32.0
ARG FIREFOX_VERSION=106.0.3
COPY ./requirements/*.txt ./docker/requirements-*.txt/ /app/requirements/
USER root
RUN apt-get update -y \
&& apt-get install -y --no-install-recommends \
libnss3 \
libdbus-glib-1-2 \
libgtk-3-0 \
libx11-xcb1 \
libasound2 \
libxtst6 \
wget
# Install GeckoDriver WebDriver
RUN wget https://github.com/mozilla/geckodriver/releases/download/${GECKODRIVER_VERSION}/geckodriver-${GECKODRIVER_VERSION}-linux64.tar.gz -O /tmp/geckodriver.tar.gz && \
tar xvfz /tmp/geckodriver.tar.gz -C /tmp && \
mv /tmp/geckodriver /usr/local/bin/geckodriver && \
rm /tmp/geckodriver.tar.gz
# Install Firefox
RUN wget https://download-installer.cdn.mozilla.net/pub/firefox/releases/${FIREFOX_VERSION}/linux-x86_64/en-US/firefox-${FIREFOX_VERSION}.tar.bz2 -O /opt/firefox.tar.bz2 && \
tar xvf /opt/firefox.tar.bz2 -C /opt && \
ln -s /opt/firefox/firefox /usr/local/bin/firefox
# Cache everything for dev purposes...
RUN cd /app \
&& pip install --no-cache -r requirements/docker.txt \
&& pip install --no-cache -r requirements/requirements-local.txt || true
RUN pip uninstall --yes babel && pip install babel
USER superset
######################################################################
# CI image...
######################################################################
FROM lean AS ci
COPY --chown=superset ./docker/docker-bootstrap.sh /app/docker/
COPY --chown=superset ./docker/docker-init.sh /app/docker/
COPY --chown=superset ./docker/docker-ci.sh /app/docker/
RUN chmod a+x /app/docker/*.sh
CMD /app/docker/docker-ci.sh
RUN pybabel compile -d /app/superset/translations || true
保存Dockerfile,并在Dockerfile所在的目录下执行(时间较长)
docker build -t mysuperset:2.1.0 .
docker build这一步占用内存较高,请保证有16G可用内存。
执行成功后,我创建了名为mysuperset版本号为2.1.0的image。
通过刚刚创建的mysuperset:2.1.0镜像创建容器,并将其8088端口(此端口号可在dockerfile中修改)映射到主机的8090端口(选一个未被占用的主机端口),设置参数SUPERSET_SECRET_KEY=123456,将其命名为superset
docker run -d -p 8090:8088 -p 9000:9000 -e "SUPERSET_SECRET_KEY=123456" --name superset mysuperset:2.1.0
初始化用户,用户名admin,密码admin。
docker exec -it superset superset fab create-admin \
--username admin \
--firstname Superset \
--lastname Admin \
--email [email protected] \
--password admin
将本地数据库迁移到最新版本。
docker exec -it superset superset db upgrade
执行汉化
docker exec -it superset pybabel compile -d /app/superset/translations
初始化
docker exec -it superset superset init
正在运行的superset容器中,以 root 用户身份启动一个新的交互式 Bash 会话
docker exec -u root -it superset /bin/bash
修改密码
passwd
输入并确认你想改成的密码,为了方便记忆可修改为root
修改superset用户密码
passwd superset
输入并确认你想改成的密码,为了方便记忆可修改为superset
退出会话
exit
这个方法与百度搜到的其他方法不同,百度搜索结果中的方法是“修改public权限等同gamma”
主机ip:8090为你刚才启动的superset链接(localhost:8090,请修改localhost为你的主机ip)
登录Superset,账号密码均为刚才设置的:admin
点击右上角的 设置>角色列表
选中Admin,点击操作,复制角色
编辑刚刚复制的角色
修改名称为copyToPublic(名字随意)
在权限中删除所有带有write的权限。在网页中使用ctrl+F搜索write,点x删除。
删除menu access on List Users权限
删除menu access on List Roles权限
点击保存,这里一定要点击保存。
手动修改容器中/app/superset/config.py文件,将PUBLIC_ROLE_LIKE: Optional[str] = None的None改成"copyToPublic",此处copyToPublic带有引号,请注意使用英文引号。(或可通过如下命令修改)
docker exec -it superset sed -i 's/PUBLIC_ROLE_LIKE: Optional\[str\] = None/PUBLIC_ROLE_LIKE: Optional\[str\] = "copyToPublic"/g' /app/superset/config.py
初始化supserset
docker exec -it superset superset init
此时可以不登录访问已创建的仪表盘(dashboard)、图表等了。
在发布仪表盘(dashboard)后,可以通过修改看板属性中的SLUG等,生成url
以下 URL 参数可用于修改仪表板的呈现方式:此处参考了官方文档
standalone:
show_filters:
expand_filters:
例如,在运行本地开发构建时,以下内容将禁用顶部导航栏并删除过滤器条:
http://localhost:8090/superset/dashboard/my-dashboard/?standalone=1&show_filters=0
superset已经有的图表无法满足我的需要,我想要在superset中集成更多的自定义的图表。
官方文献:Creating Visualization Plugins | Superset
参考文献1:https://www.youtube.com/watch?v=LDHFY9xTzls&ab_channel=Preset
参考文献2:Building Custom Viz Plugins in Superset v2 (Updated for Monorepo) | Preset
正在运行的 superset
容器中,以 root 用户身份启动一个新的交互式 Bash 会话
docker exec -u root -it superset /bin/bash
修改npm源为淘宝源
npm config set registry https://registry.npmmirror.com
在全局范围内安装 Yo
命令行工具
npm i -g yo
进入/app/superset-frontend/packages/generator-superset目录
cd /app/superset-frontend/packages/generator-superset
执行
npm i && npm link
切换到用户superset
su superset
此时你的用户是 superset
为您的可视化插件创建一个新目录,目录名的前缀应该是 superset-plugin-chart,然后运行 Yeoman 生成器。
mkdir /tmp/superset-plugin-chart-hello-world
cd /tmp/superset-plugin-chart-hello-world
yo @superset-ui/superset
开始build,执行
npm i --force
npm run build
进入/app/superset-frontend
cd /app/superset-frontend
向superset添加图表,执行(链接到已创建的图表)
npm i -S /tmp/superset-plugin-chart-hello-world
我们可以看到在/app/superset-frontend/package.json文件中,已经添加了我自定义的图表。
修改/app/superset-frontend/src/visualizations/presets/MainPreset.js文件,修改两处,一处引用,一处配置
引用:在此处加入行
import { SupersetPluginChartHelloWorld } from 'superset-plugin-chart-hello-world';
配置:在此处插入行
new SupersetPluginChartHelloWorld().configure({
key: 'ext-hello-world',
}),
请注意,在修改MainPreset.js文件时,不要添加无意义的回车和空格,会导致报错。
在/app/superset-frontend目录下
执行分为两种方式:
临时的页面在9000端口(React在保存时热重载和重新编译文件)
npm run dev-server
http://localhost:9000
由于React在保存时热重载和重新编译文件,因此需要跟踪所有项目文件。
若出现了文件观察器达到限制的问题如下所示:可以重启superset容器。或修改docker的配置。
[webpack-dev-server] Project is running at:
[webpack-dev-server] Loopback: http://localhost:9000/
[webpack-dev-server] Content not from webpack is served from '/app/static/assets' directory
[webpack-dev-server] 404s will fallback to '/index.html'
10% building 0/1 entries 0/0 dependencies 0/0 modulesnode:internal/errors:478
ErrorCaptureStackTrace(err);
^
Error: ENOSPC: System limit for number of file watchers reached, watch '/app'
at FSWatcher. (node:internal/fs/watchers:244:19)
at Object.watch (node:fs:2296:34)
at createFsWatchInstance (/app/superset-frontend/node_modules/chokidar/lib/nodefs-handler.js:119:15)
at setFsWatchListener (/app/superset-frontend/node_modules/chokidar/lib/nodefs-handler.js:166:15)
at NodeFsHandler._watchWithNodeFs (/app/superset-frontend/node_modules/chokidar/lib/nodefs-handler.js:331:14)
at NodeFsHandler._handleDir (/app/superset-frontend/node_modules/chokidar/lib/nodefs-handler.js:567:19)
at NodeFsHandler._addToNodeFs (/app/superset-frontend/node_modules/chokidar/lib/nodefs-handler.js:617:27)
at async /app/superset-frontend/node_modules/chokidar/index.js:451:21
at async Promise.all (index 0)
Emitted 'error' event on FSWatcher instance at:
at FSWatcher._handleError (/app/superset-frontend/node_modules/chokidar/index.js:647:10)
at NodeFsHandler._addToNodeFs (/app/superset-frontend/node_modules/chokidar/lib/nodefs-handler.js:645:18)
at async /app/superset-frontend/node_modules/chokidar/index.js:451:21
at async Promise.all (index 0) {
errno: -28,
syscall: 'watch',
code: 'ENOSPC',
path: '/app',
filename: '/app'
}
若运行正式版本,则执行
npm run build
执行正式页面需重启容器
e.g. 打开页面实在是太卡了,我把整个docker容器都重启了。
systemctl restart docker
然后重启需要打开的容器。
http://localhost:8090
在创建图表时搜索:hello,即可找到刚刚创建的图表
如果想要修改图标,可以替换/app/superset-frontend/node_modules/superset-plugin-chart-hello-world/src/images目录下的thumbnail.png文件。
同上述方法,通过yo,创建/tmp/superset-plugin-chart-test,创建一个名为superset-plugin-chart-test的插件。并在/app/superset-frontend目录下执行npm i -S /tmp/superset-plugin-chart-test,并修改/app/superset-frontend/src/visualizations/presets/MainPreset.js文件。(和1.2.中的方法相同)
在/tmp/superset-plugin-chart-test目录下安装echarts-for-react
npm i echarts-for-react --save
修改/tmp/superset-plugin-chart-test/src/SupersetPluginChartTest.tsx文件,改成
import ReactEcharts from "echarts-for-react"
import React from "react"
const SupersetPluginChartTest = () => {
const getOption = () => {
return {
title: {
text: "ECharts 入门示例",
},
tooltip: {},
legend: {
data: ["销量"],
},
xAxis: {
data: ["衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"],
},
yAxis: {},
series: [
{
name: "销量",
type: "bar",
data: [5, 20, 36, 10, 10, 20],
},
],
}
}
return
}
export default SupersetPluginChartTest;
在/tmp/superset-plugin-chart-test 目录下执行
npm run build
在/app/superset-frontend目录下
npm run dev-server
或
npm run build
在已经通过npm i --save .......安装好echarts和echarts for react后。
同上述方法,通过yo,创建/tmp/superset-plugin-baidu-map,创建一个名为superset-plugin-baidu-map的插件。并在/app/superset-frontend目录下执行npm i -S /tmp/superset-plugin-baidu-map,并修改/app/superset-frontend/src/visualizations/presets/MainPreset.js文件。(和1.2.中的方法相同)
修改/tmp/superset-plugin-chart-test/src/SupersetPluginChartTest.tsx文件,改成
import React from "react"
import ReactEcharts from "echarts-for-react"
import echarts from "echarts";
import 'echarts/extension/bmap/bmap';
const SupersetPluginChartBaiduMap = () => {
const getOption = () => {
return {
bmap: {
center: [104.114129, 37.550339],
zoom: 5,
roam: true
},
series: [
{
type: 'scatter',
coordinateSystem: 'bmap',
symbolSize: 20,
data: [[104.114129, 37.550339]]
}
]
}
}
return (
)
}
export default SupersetPluginChartBaiduMap;
再修改/app/superset/templates/tail_js_custom_extra.html文件
在末尾加入
ak为你申请的百度地图api,请选择应用类型为浏览器端。
在dashboard中,若想要删除百度地图左下角的图表,可以修改dashboard的css ,增加
/* 隐藏地图bmap左下角logo */
.anchorBL{
display:none;
}
如果想像其他图表一样,添加控件,可以参考我自己创建的Superset百度地图插件。
经度、纬度、机构名称、地址、指标、默认图标颜色为必填项。
地图页面(主页面):superset-plugin-chart-baidu-map/src/SupersetPluginChartBaiduMap.tsx
要修改的文件
1. 用于传输配置数据的文件
2. 用于传输query数据的文件
控件类别:
AnnotationLayerControl: 注释图层控件
BoundsControl: 边界控件
CheckboxControl: 复选框控件
CollectionControl: 集合控件
ColorPickerControl: 颜色选择器控件
ColorSchemeControl: 颜色方案控件
DatasourceControl: 数据源控件
DateFilterControl: 日期过滤器控件
FixedOrMetricControl: 固定值或指标控件
HiddenControl: 隐藏控件
SelectAsyncControl: 异步选择控件
SelectControl: 选择控件
SliderControl: 滑块控件
SpatialControl: 空间控件
TextAreaControl: 多行文本控件
TextControl: 单行文本控件
TimeSeriesColumnControl: 时间序列列控件
ViewportControl: 视口控件
VizTypeControl: 可视化类型控件
MetricsControl: 指标控件
AdhocFilterControl: 自定义过滤器控件
FilterBoxItemControl: 过滤器框控件
DndColumnSelect: 数据列拖放选择控件
DndFilterSelect: 过滤器拖放选择控件
DndMetricSelect: 指标拖放选择控件
控件设置control panel :
superset-plugin-chart-baidu-map/src/plugin/controlPanel.ts
命名及使用规则:
1. 规则1
superset-plugin-chart-baidu-map/src/plugin/controlPanel.ts中的“name”项、
superset-plugin-chart-baidu-map/src/plugin/buildQuery.ts
下划线分隔的小写字符串命名法,如:abcd_efgh
2. 规则2
superset-plugin-chart-baidu-map/src/plugin/transformProps.ts、
superset-plugin-chart-baidu-map/src/types.ts、
superset-plugin-chart-baidu-map/src/SupersetPluginChartBaiduMap.tsx、
superset-plugin-chart-baidu-map/test/plugin/transformProps.test.ts
此变量名需沿用1中的name并改成驼峰式,如:abcdEfgh。
翻译:
此处以汉化为例:
在ts、js、tsx、jsx等文件生成的界面上,如果需要在页面上汉化
import { t } from '@superset-ui/core';
在需要汉化文本的地方使用
t('text need to translate')
需要修改文件,自定义添加原文和对应汉语翻译。
/app/superset/translations/zh/LC_MESSAGES/messages.po
重新执行编译
pybabel compile -d /app/superset/translations
echarts symbol图标用法
原文链接。
例如:在图表中修改该symbol
symbol: 'image://data:image/gif;base64,xxxxxxxx'
xxxxxxxx处为图片的base64编码,可使用在线转换。
此处建议转成gif图片后再转成base64编码,svg图片的base64编码会导致图标不显示。