Docker部署Superset v2.1.0 +修改环境+汉化+匿名访问+创建自定义图表(二次开发)+集成echarts+echarts百度地图

目录

前言 :为什么要写这篇文章?

一、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是什么?

Superset 是一个基于 Python Flask 和 Apache Superset 的数据可视化和探索平台。它是由 Airbnb 在 2015 年发布的,并于 2017 年开源,现已成为 Apache 基金会孵化项目之一。

Superset 提供了一个交互式的数据可视化界面,支持从多种数据源中获取和探索数据,如 SQL 数据库、NoSQL 数据库、搜索引擎等。用户可以通过 Superset 快速创建和共享数据分析和可视化应用,支持多种图表类型和样式,包括折线图、柱状图、散点图、地图等。

二、建议软件

我建议您使用 VScode 软件,并安装 Remote-SSH 插件来远程连接您的服务器。此外,您可以安装 Docker 插件来方便地管理 Docker 容器和镜像。

三、安装步骤

1.安装docker

请参考​​​​​安装Docker详细步骤总结,这里就不重复了。

2.拉取源码

创建并进入superset文件夹

mkdir superset && cd superset

初始化空的 Git 版本库

git init

从github上拉取源码,并与远程仓库建立连接

git pull https://github.com/apache/superset.git
git remote add origin https://github.com/apache/superset.git

国内可以通过gitee镜像拉取源码,并与远程仓库建立连接

git pull https://gitee.com/mirrors/Superset.git
git remote add origin https://gitee.com/mirrors/Superset.git

 确保你已经与远程仓库建立了连接,并且从远程仓库同步了所有分支信息,可以使用以下命令

git fetch origin

切换到2.1.0版本

git checkout 2.1.0

3.修改源码的dockerfile

该 Dockerfile 有三个部分,分别对应三个阶段:

  1. 第一部分是 Node 阶段,用于构建静态资源。

  2. 第二部分是 Lean 阶段,用于实际运行程序,并生成可发布的 Docker 镜像。

  3. 第三部分是 Dev 阶段,用于开发环境。

我们需要对dockerfile做出以下修改:(修改好的dockerfile在后面)

  1. 修改依赖为python3.8版本和node16版本

  2. 在Lean阶段修改apt源,将它改为阿里源

  3. 在Lean阶段,在运行环境中通过apt安装sudo

  4. 在Lean阶段,在运行环境中安装node16(二次开发需要node16和npm7或8版本)

  5. 在Lean阶段将只复制superset-frontend/package.json文件改成从node阶段复制整个superset-frontend文件夹到运行环境

  6. 在Lean阶段修改pip源,将它改为阿里源

  7. 在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
    • 需要执行superset init
    • 需要重启容器
    • 需要清理浏览器缓存(也可以用无痕模式)

以下是我修改后的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
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 .

执行成功后,我创建了名为mysuperset版本号为2.1.0的image。

4.创建superset容器

通过刚刚创建的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

5.修改容器内的账号密码

正在运行的superset容器中,以 root 用户身份启动一个新的交互式 Bash 会话

docker exec -u root -it superset /bin/bash

修改密码

passwd

输入并确认你想改成的密码,为了方便记忆可修改为root

修改superset用户密码

passwd superset

 输入并确认你想改成的密码,为了方便记忆可修改为superset

退出会话

exit

6.修改Superset仪表盘(Dashboard)可以匿名访问(免登录)

这个方法与百度搜到的其他方法不同,百度搜索结果中的方法是“修改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)、图表等了。

7.发布dashboard并自定义url

在发布仪表盘(dashboard)后,可以通过修改看板属性中的SLUG等,生成url

以下 URL 参数可用于修改仪表板的呈现方式:此处参考了官方文档

standalone:

  •         0(默认):以正常方式显示仪表板
  •         1:隐藏顶部导航栏
  •         2:同时隐藏顶部导航栏和标题
  •         3:隐藏顶部导航栏、标题和顶级选项卡

show_filters:

  •         0:不显示过滤器条
  •         1(默认):如果启用了本机过滤器,则显示带有过滤器条的仪表板

expand_filters:

  •         (默认):如果存在本机过滤器,则以展开的形式显示过滤器条
  •         0:以折叠的形式显示过滤器条
  •         1:以展开的形式显示过滤器条

例如,在运行本地开发构建时,以下内容将禁用顶部导航栏并删除过滤器条:

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

1.创建一个简单的 Hello World viz 插件

正在运行的 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

根据引导创建,运行结果如下所示:

superset@85f42e98d870:/tmp/superset-plugin-chart-hello-world$ yo @superset-ui/superset

     _-----_     ╭──────────────────────────╮
    |       |    │      Welcome to the      │
    |--(o)--|    │    generator-superset    │
   `---------´   │        generator!        │
    ( _´U`_ )    ╰──────────────────────────╯
    /___A___\   /
     |  ~  |     
   __'.___.'__   
 ´   `  |° ´ Y ` 

? Package name: superset-plugin-chart-hello-world
? Plugin name: Hello World
? Description: Superset Plugin Chart Hello World
? What type of chart would you like? Time-series chart
   create package.json
   create .gitignore
   create babel.config.js
   create jest.config.js
   create package-lock.json
   create README.md
   create tsconfig.json
   create src/index.ts
   create src/plugin/buildQuery.ts
   create src/plugin/controlPanel.ts
   create src/plugin/index.ts
   create src/plugin/transformProps.ts
   create src/types.ts
   create src/SupersetPluginChartHelloWorld.tsx
   create test/index.test.ts
   create test/__mocks__/mockExportString.js
   create test/plugin/buildQuery.test.ts
   create test/plugin/transformProps.test.ts
   create types/external.d.ts
   create src/images/thumbnail.png

开始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文件时,不要添加无意义的回车和空格,会导致报错。

2.运行

在/app/superset-frontend目录下

执行分为两种方式:

  1. dev临时的页面(可实时修改),此处建议使用dev,完成全部修改后再执行build
  2. 正式的页面

临时的页面在9000端口(React在保存时热重载和重新编译文件)

npm run dev-server

http://localhost:9000

 由于React在保存时热重载和重新编译文件,因此需要跟踪所有项目文件。

若出现了文件观察器达到限制的问题如下所示:可以重启superset容器。或修改docker的配置。

<i> [webpack-dev-server] Project is running at:
<i> [webpack-dev-server] Loopback: http://localhost:9000/
<i> [webpack-dev-server] Content not from webpack is served from '/app/static/assets' directory
<i> [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.<computed> (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文件。

3.创建一个其他的图表(集成echarts)

同上述方法,通过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 <ReactEcharts option={getOption()} />
}

export default SupersetPluginChartTest;

在/tmp/superset-plugin-chart-test 目录下执行

npm run build

在/app/superset-frontend目录下

npm run dev-server

npm run build

如此,即可在superset中创建此chart,如图所示

4.创建一个百度地图插件(使用echarts+echarts for react)

在已经通过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 (
      <ReactEcharts option={getOption()} echarts={echarts} />
  )
}

export default SupersetPluginChartBaiduMap;

再修改/app/superset/templates/tail_js_custom_extra.html文件

在末尾加入

<script type="text/javascript" src="https://api.map.baidu.com/api?v=3.0&ak=YOUR_API_KEY"></script>

 ak为你申请的百度地图api,请选择应用类型为浏览器端。

在dashboard中,若想要删除百度地图左下角的图表,可以修改dashboard的css ,增加

/* 隐藏地图bmap左下角logo */
.anchorBL{
display:none;
}

猜你喜欢

转载自blog.csdn.net/weixin_43219396/article/details/130271278