简介:面向需要在内网或离线环境搭建数据可视化平台的企业与开发者,这份资源将Superset 4.1.1中文版与Docker容器化部署打包在一起,免去手动配置依赖的繁琐,尤其适合对英文命令行不熟悉的中文用户。压缩包共6个文件,总体积约524.2MB,其中包含3个Docker镜像tar包(如Redis、PostgreSQL、Superset本体)、docker-compose.yml编排文件、superset_config.py配置文件和.env环境变量文件,结构清晰,可快速完成整套环境启动。已有368人学习下载。通过该资源,使用者能够获得一套可移植、可复用的离线部署方案,只需调整少量环境变量与配置即可上线使用,同时镜像已预先下载,确保无互联网时也能顺利安装。对于需要快速开展数据探索与可视化工作的团队,是一份省时省力的实用工具包。
1. 一个离线场景讲清 Superset 部署的本质:镜像、依赖与配置的三明治
拿到 Superset 4.1.1 的中文离线包时,部门群里已经因为"谁能把可视化平台跑起来"争论了两天。内网环境要求所有服务不出网,Docker Hub 连不上,pip 源不通——这不是不会写 docker run 的问题,而是你根本拿不到一份能在这台机器上直接跑起来的镜像、依赖和配置组合。Superset 本身就是个"三明治":底层是 Python 和一堆编译期依赖,中间是 React 前端构建产物,上层是你自己的数据库连接和本地化配置。任何一层没对齐,服务就是起不来。这篇文章把 4.1.1 离线部署从镜像传输、容器初始化、中文化配置到外接数据库拆开讲一遍,适合正在折腾内网数据平台的新手,也适合被各种玄学问题反复折磨的老手。读完你能明白为什么有的包在演示机上秒开,到了生产机就翻车。
2. 先过镜像这一关:save/load 还是内网 registry,两个选型理由
2.1 为什么离线方案必须绕过裸进程部署
Superset 4.1.1 的前端是编译后的静态资源,后端是大量 Python 包和部分 C 扩展的集合。裸机部署意味着你要在一台没有外网的机器上,解决 pip 依赖、系统库版本、Node 构建产物三件事的交叉兼容。我在模拟项目X里试过一次离线裸部署:Python 版本差一个小版本,某个 C 扩展编译失败;换 Python 版本之后,另一个依赖的 glibc 版本又不对了。折腾两天,最后停在某个基础库上。这不是操作问题,是依赖树本身在离线环境里根本无法收敛。
Docker 镜像把这些全部锁进容器层。只要你拿到的 tar 包是在干净的联网环境里构建的,镜像内部自带的 Python 版本、系统库、前端资源就是一致的。离线部署要操心的只剩两件事:镜像怎么传到目标机,以及容器启动后怎么写配置。前者是传输问题,后者是配置问题,都不再涉及编译和依赖解析。
2.2 镜像传输的两条路线与选择标准
离线环境里传镜像,常规做法是 docker save 配合 docker load,或者自建内网 registry。两条路线各有适用场景,我在下表里把取舍逻辑列清楚。
| 对比项 | docker save / load | 内网 registry |
|---|---|---|
| 适用规模 | 1~2 台目标机,一次性交付 | 3 台以上机器,或后续要持续发版 |
| 磁盘开销 | tar 包多大就占多大,目标机还要额外展开一份 | 只有仓库机器占存储,各节点按需拉取 |
| 增量更新 | 不支持,每次要重新导出完整镜像 | 支持,按新 tag 推送即可 |
| 前置条件 | 一台能访问目标机的临时机器(U盘/内网共享目录) | 一台能长期开机的机器跑 registry:2 |
| 维护成本 | 低,拷过去 load 完就结束 | 中等,要管仓库存储和 HTTPS 或 insecure 配置 |
如果只有一两台机器,我会直接用 save/load,省去维护仓库的精力。但如果你隐约觉得"后面还会加节点",现在就花半小时把 registry 立起来。血泪经验是:等机器从 1 台变 3 台再迁移镜像,中间要处理的 tag 混乱和磁盘问题比现在搭仓库还麻烦。
镜像层面也没什么玄学,save 和 load 走的是同一套 registry 协议,只是把镜像层压缩打包成 tar。真正容易翻车的反而是 save 时候的 tag 写法,这一点后面避坑章节会专门讲。
2.3 目标机离线安装 Docker 的 rpm 路径
目标机连 Docker 都没有的话,得先把 docker-ce、containerd.io、docker-ce-cli、runc 这组 rpm 包准备好。常见做法是在一台同发行版的联网机器上用 yumdownloader 拉一个本地源目录,再整体拷贝到离线机。
# 在联网的某台机器上 mkdir -p docker-rpm cd docker-rpm yumdownloader --resolve docker-ce docker-ce-cli containerd.io tar czf docker-rpm.tar.gz docker-rpm# 在离线目标机上 tar xzf docker-rpm.tar.gz cd docker-rpm sudo yum install -y ./*.rpm sudo systemctl enable --now docker docker versionyumdownloader 的 --resolve 参数会把依赖一并拉下来,放在当前目录。拷贝到目标机后,用yum install -y ./*.rpm让 yum 从本地目录解析,而不是去配置的远程源找。第一个命令里先把 Docker 相关包下载再打包传输,第二个命令里安装并验证 Docker 版本。注意生成 rpm 包的机器和目标机的发行版要一致,最好是同大版本,跨版本很容易出现把 glibc 版本打得过高的情况。enable 和 now 参数组合,是让 Docker 开机自启并立即启动,离线服务器不会有人手动去开服务,这一步必须做。
3. 从 tar 包到能跑的容器:端口、挂载与初始化四件套
3.1 导入并验证本地镜像
拿到离线 tar 包之后,第一步在目标机上执行 docker load。这里看起来简单,但导入之后的验证动作不能省。
sha256sum superset-4.1.1.tar sudo docker load -i superset-4.1.1.tar sudo docker images | grep -i supersetsha256sum 先校验 tar 包完整性,避免 U 盘拷贝中途损坏导致镜像层文件缺损。load 完成后务必用 docker images 确认镜像的 repo 和 tag。如果输出里只有一堆<none>,说明打包时 tag 没写对,后面运行容器会很痛苦。这里有个容易忽略的点:load 输出的日志会显示Loaded image: superset:4.1.1-chinese,这个节点信息就是后面 docker run 要使用的全名,记下来。
3.2 启动参数里的四个关键开关
4.1.1 官方镜像默认暴露 8088 端口,数据目录在 /app/superset_home,这两个路径是启动参数的主线。
mkdir -p /data/superset/data sudo docker run -d \ --name superset \ --restart unless-stopped \ -p 80:8088 \ -v /data/superset/data:/app/superset_home \ -e SUPERSET_SECRET_KEY="change-it-to-32-char-random-string" \ -e SUPERSET_LOAD_EXAMPLES=No \ -e TZ=Asia/Shanghai \ superset:4.1.1-chinese端口映射把容器内的 8088 绑定到宿主机 80,这样内网通过 http://宿主机IP 直接访问。数据卷挂载到 /app/superset_home,SQLite 元数据库文件和配置会落在这个目录。SUPERSET_SECRET_KEY 是 Flask 的签名密钥,至少要 32 个字符的随机串,否则会话会出现间歇性失效。SUPERSET_LOAD_EXAMPLES=No 是为了避免首次启动时后台任务疯狂加载示例仪表盘,离线环境下加载失败还会拖慢启动速度。TZ=Asia/Shanghai 让容器日志时间戳对齐本地时间,排查问题的时候不用再做时区换算。
如果之前做过其他容器平台,会觉得这不就是个 docker run 吗。但 Superset 的特殊点在于:容器起来只代表进程在跑,不代表平台可用,初始化四件套才是真正把空壳容器变成可用系统的步骤。
3.3 初始化四件套:顺序不能乱
Superset 的初始化分为四个独立命令,顺序错了会直接报错或者账号无法登录。
docker exec -it superset superset db upgrade docker exec -it superset superset fab create-admin \ --username admin --firstname admin --lastname admin \ --email admin@local.local --password 'Admin@123456' docker exec -it superset superset initdb upgrade 负责把元数据库表结构同步到当前版本,必须在建账号之前执行。Fab create-admin 创建后台管理员账号,这一步依赖表结构完整。init 命令加载角色和权限,包括默认的 Admin、Gamma、Alpha 这几个固定角色。如果跳过 init,登录时会发现很多菜单消失,或者数据集权限页面直接异常。这三个命令执行完,4.1.1 基本就处于可登录状态。
另外注意 create-admin 的参数在不同小版本上略有变化。如果提示某个参数无法识别,直接执行docker exec -it superset superset fab create-admin走交互式输入,按提示填用户名、密码、邮箱即可。初始化完成后,浏览器打开内网地址应该能看到登录页,默认语言是英文,中文切换的细节在下一章。
4. 中文化与外接数据库:把默认镜像改成业务平台的三个落点
4.1 中文本地化从翻译文件到浏览器显示
Superset 4.1.1 的中文支持分两层:一层是框架本身的翻译文件,另一层是每个用户的偏好设置。很多部署完发现界面还是英文,是因为只做了第一层,没做第二层。
首先确认镜像里是否已经有中文翻译文件。Superset 的翻译机制是基于 Flask-Babel,语言文件放在源码目录的 translations/zh/LC_MESSAGES 下。离线包如果写了"中文版",通常已经把 messages.mo 编译进去。但验证方式很简单:登录后点右上角用户菜单,切到设置页面,看语言下拉框里有没有中文选项。没有的话,修改容器里的 Superset 配置,把中文加入可用语言列表。
docker exec -it superset bash cd /app/superset/assets # 在 config.py 里确认或者添加 LANGUAGES 配置 python - <<'PY' from app.config import LANGUAGES print(LANGUAGES) PY如果没有按预期输出中文,需要编辑配置文件把 LANGUAGES 字典补全,常见写法是LANGUAGES = {'zh': '中文', 'en': 'English'}。修改后重启容器才生效。这里有个小坑:Superset 的前端静态资源已经打包在镜像里,直接改 Python 配置只能影响服务端渲染的部分页面,前端图表编辑器的语言偏好是存在浏览器 localStorage 里的。所以完成配置后,要强制刷新浏览器,甚至清一次缓存。
还有一个更省事的做法:把SUPERSET_LANGUAGES环境变量加进 docker run 参数,部分镜像版本会读取它。但这个方法在不同构建版本里行为不一致,最稳妥的还是直接改 config.py 然后重启。
4.2 摆脱内置 SQLite:接入外部 MySQL 的收尾配置
Superset 默认元数据库是 SQLite,文件躺在 /app/superset_home 里。SQLite 做单机验证没问题,但多人同时编辑仪表盘或数据集时,写锁冲突会很严重。更关键的是备份问题——SQLite 文件在容器的数据卷里,如果数据卷所在磁盘损坏,整个平台配置和所有看板元数据直接归零。我一般接手部署任务的第一件事,就是配置外部数据库。
用 docker-compose 管理时,把 SQLALCHEMY_DATABASE_URI 作为环境变量注入即可:
version: '3' services: superset: image: superset:4.1.1-chinese restart: unless-stopped ports: - "80:8088" volumes: - /data/superset/data:/app/superset_home environment: - SUPERSET_SECRET_KEY=change-it-to-32-char-random-string - SUPERSET_LOAD_EXAMPLES=No - TZ=Asia/Shanghai - SQLALCHEMY_DATABASE_URI=mysql://superset_user:StrongPass@192.168.10.20:3306/superset?charset=utf8mb4URI 里的 charset=utf8mb4 不要丢,否则中文字段在数据库里会变乱码。这个环境变量会被 Superset 的应用配置直接读取,等价于修改 config.py 里的 SQLALCHEMY_DATABASE_URI 常量。换外部库之后,初始化命令要重跑一遍,先确保外部库里建好 superset 数据库和账号,再执行 db upgrade、create-admin、init 三件套。
镜像默认可能没有带 MySQL 驱动。如果容器里没装 mysqlclient 或 PyMySQL,连接时会报找不到模块。一条临时命令docker exec -it superset pip install PyMySQL可以救急,但容器一旦 rm 重建,这个依赖就没了。有长期维护预期的话,用 Dockerfile 重新构建一个新镜像,把驱动依赖写死在镜像里。
FROM superset:4.1.1-chinese RUN pip install --no-cache-dir PyMySQL重新构建的镜像tag要打一个新版本,比如 4.1.1-mysql,后续所有节点统一拉这个版本。
4.3 目录挂载和数据持久化的约定
在投入真实业务之前,必须先搞懂容器内哪些文件值得挂到宿主机。Superset 的 /app/superset_home 里通常有这么几类内容:
| 文件或目录 | 作用 | 是否需要持久化 |
|---|---|---|
| superset.db | SQLite 元数据库(如果没外接数据库) | 必须,外接数据库后可不关心 |
| superset_config.py | 运行时写入的配置文件 | 必须,否则重启后配置丢失 |
| celerybeat-schedule | 定时任务的调度快照 | 建议,否则刷新任务调度会重排 |
| log/ | 应用日志和 worker 日志 | 建议,跨容器生命周期保留排查线索 |
数据卷挂载要覆盖整个 /app/superset_home,而不是单独挂某个文件。单独挂文件容易遇到文件权限和 SELinux 上下文的问题。另外,宿主机目录权限要注意:容器内是以 root 用户跑的,挂载目录如果权限是 0755 且拥有者不是 root,写入时会报 Permission denied。先chown -R 0:0或直接把目录权限放到 0777 再启动容器,能少踩一个坑。
外接数据库之后,SQLite 文件就不再产生,但配置文件和 celery 信息仍在数据卷里,所以挂载动作不能省。
5. 避坑与排查:离线部署最容易翻车的五个位置
5.1 镜像 load 后全是<none>tag
现象:docker load 成功,但 docker images 输出里没有预期的 superset 标签,只看到一堆<none>仓库名。docker run 的时候就不知道用什么名字启动。
原因:打包机器上 save 命令写的 tag 不对。比如执行docker save <image-id> -o superset.tar,保存的是镜像 ID 而不是仓库标签。load 进目标机后,镜像 ID 没变,标签信息丢失,于是显示为<none>。
解决:重新在打包机上先打全 tag 再 save。docker tag superset:4.1.1-chinese superset:4.1.1-chinese听起来是废话,实际操作中 tag 的仓库名部分可能带域名或路径,容易写漏。正确方式是docker save superset:4.1.1-chinese -o superset-4.1.1.tar,保存的镜像名必须是 docker images 列表里完整显示的 REPOSITORY:TAG。如果已经导入到目标机,也可以直接用docker tag <image-id> superset:4.1.1-chinese把那个无标签镜像重新命名,不需要重新拷贝。
5.2 容器状态 UP 但页面打不开
现象:docker ps 显示容器 Restarting 或 Up 几秒后自动退出,浏览器访问宿主机 IP:80 一直连接超时。
原因:两层问题叠加。第一层是端口映射里把宿主机 80 占用了,或者容器内部 8088 没起来;第二层是内网机器上 firewalld 默认拦截了非标准端口,80 端口虽然常见,但防火墙策略没放行时照样超时。
解决:先看日志定位是服务没起来还是端口不通。docker logs superset --tail 200如果有 "Running on http://0.0.0.0:8088" 说明服务已监听,问题在宿主机网络;然后ss -lntp | grep 80确认端口监听状态,再用firewall-cmd --list-all检查放行规则。端口没收进白名单就执行firewall-cmd --permanent --add-port=80/tcp && firewall-cmd --reload。如果日志显示启动到一半就退,多半是上一步初始化没做全,回到 db upgrade 和 init 两件套重跑。
5.3 中文部分生效、部分还是英文
现象:登录界面和导航栏已经是中文,但图表的右键菜单、数据集配置页面仍显示英文,有些按钮还混着中文和英文。
原因:Superset 的前端翻译和后端翻译是两套体系。后端页面的模板翻译由 Flask-Babel 读取 Python 配置,前端组件的翻译资源是打包在 JavaScript 里的,由浏览器语言偏好决定。离线包做中文化时如果只替换了后端翻译文件,前端翻译资源缺失,表现就是部分生效。
解决:确认容器内翻译文件是否完整:docker exec -it superset ls /app/superset/translations/zh/LC_MESSAGES/,应该有两个文件 messages.mo 和 messages.po。如果只有 .po 没有 .mo,需要编译:docker exec -it superset pybabel compile -d translations -l zh。前端缺失的部分很难在离线环境补全,因为要重构建静态资源,工程量大。实际处理中,我把这个归类为"可接受的不完整",先把管理员语言和浏览器语言都切成中文,大部分中文内容都会正常显示,个别按钮英文不影响看板和数据集功能。
5.4 外接 MySQL 报表库连不上
现象:在 Superset 里配置 MySQL 数据源,点测试连接时提示Can't connect to MySQL server on '192.168.x.x' (2003)或者Authentication plugin 'caching_sha2_password' cannot be loaded。
原因:2003 是网络或端口问题,常见原因是目标机器上没有安装对应的 MySQL 驱动,或者数据库账号的 host 限制不允许从 Superset 容器所在网段访问。认证插件报错是 MySQL 8 默认的认证插件是 caching_sha2_password,PyMySQL 对它的支持依赖 cryptography 库,镜像里没装就会失败。
解决:先确认网络:docker exec -it superset bash -c "mysql -h 192.168.x.x -u superset_user -p",能连上说明网络没问题。连不上检查目标库的 bind-address 和账号 host 配置。认证插件问题,登录目标库执行ALTER USER 'superset_user'@'%' IDENTIFIED WITH mysql_native_password BY 'password';,改成传统认证方式,兼容性最好。但一些云数据库默认不允许改认证插件,那就在原数据库里装上 cryptography 依赖再重新连接。这里要强调:别在生产库上直接改认证插件而不通知 DBA,先评估影响范围。
5.5 重启容器之后仪表盘全没了
现象:docker rm 容器再跑一个新的,登录账号还在,数据库连接还在,但之前建的仪表盘和图表全部消失,像是回到了初始化状态。
原因:SQLite 文件写在容器可写层。宿主机数据卷挂载只覆盖了 /app/superset_home 里的部分文件,但某些版本会把元数据库写到 /var/lib/superset 或者镜像内其他路径,数据卷没覆盖到。容器删除后可写层一起销毁,数据没了,连后悔药都没得吃。
解决:先确认元数据库实际路径:docker exec -it superset find / -name "superset.db" 2>/dev/null。如果不在挂载目录,改启动参数把对应目录也挂出来。更彻底的方案是回到上一章,把元数据库直接外接到 MySQL,让容器变成纯无状态服务。从那以后我做任何 Superset 交付,第一件事就是把元数据库外连,绝不把生产数据放在容器可写层里。
6. 进阶:把离线交付做成可持续维护的内网闭环
离线部署稳定运行一个月之后,真正的需求往往是"要加一台节点"或者"要同时给业务方开一个测试环境"。此时再从头走一遍 save/load 的成本就高了。可维护性更强的做法是把内网 registry 用起来。
在离线仓库机器上启动一个最小 registry 容器:
sudo docker run -d \ --name registry \ --restart unless-stopped \ -p 5000:5000 \ -v /data/registry:/var/lib/registry \ registry:2然后把刚才的本地镜像打上仓库地址前缀再推送:
sudo docker tag superset:4.1.1-chinese 192.168.10.5:5000/superset:4.1.1-chinese sudo docker push 192.168.10.5:5000/superset:4.1.1-chinese注意仓库地址用了内网 IP 加端口,目标机拉取时需要把所有节点的 Docker daemon 配置加上"insecure-registries": ["192.168.10.5:5000"],否则 Docker 默认按 HTTPS 去连,会报证书错误。这一点最容易漏,改完配置文件要重启 Docker 服务。
多台节点拉取镜像的命令就变成:
sudo docker pull 192.168.10.5:5000/superset:4.1.1-chinese sudo docker run -d \ --name superset \ -p 80:8088 \ -v /data/superset/data:/app/superset_home \ -e SUPERSET_SECRET_KEY="same-key-across-nodes" \ -e TZ=Asia/Shanghai \ 192.168.10.5:5000/superset:4.1.1-chineseSECRET_KEY 在多节点共用时保持一致,否则负载均衡下会话会频繁失效,这是容易被忽略的细节。
备份恢复方面,外接 MySQL 之后备份链路要清晰一些。元数据库用 mysqldump 做逻辑备份,配置和调度文件用 tar 打总。定时备份脚本我放在 /etc/cron.d/superset-backup:
30 2 * * 0 root mysqldump -h 192.168.10.20 -u superset_user -p'StrongPass' superset | gzip > /data/backup/superset-db-$(date +\%F).sql.gz 31 2 * * 0 root tar czf /data/backup/superset-conf-$(date +\%F).tar.gz /data/superset/data备份时间选在周日凌晨,避开业务高峰。mysqldump 是物理读,会把所有表结构和数据写出来,压缩后体积能降很多。注意带日期变量时 cron 里的百分号要转义成 %F,否则 cron 会直接报错。
线上环境如果允许短暂停写,备份前可以临时停掉 superset 容器里的 worker 进程防止数据写入半截。命令是docker exec -it superset bash -c "pkill -f celery",备份完成后重启容器即可。这套流程执行过一次之后,整个平台对镜像传输、初始化顺序、中文化配置的基本逻辑就都串起来了,后续换版本、加节点都是同一套动作。
每次我到一个新环境,都会强制自己先走一遍"导入镜像 → 初始化 → 做一张测试看板 → 重启容器 → 验证看板还在"的验证环。这个环走通了,离线交付这件事就算真正落地了。希望帮到你。
本文还有配套的精品资源,点击获取