ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Superset 4.1.1 中文版 Docker 离线部署实战:内网环境安装与避坑指南

Superset 4.1.1 中文版 Docker 离线部署实战:内网环境安装与避坑指南

简介:这份资源面向需要在无外网环境下搭建数据可视化平台的企业运维与开发者,提供 Superset 4.1.1 中文版的 Docker 离线部署方案,解决内网环境无法拉取镜像、部署流程繁琐的问题。压缩包共 6 个文件,约 524.2MB,包含 3 个 tar 镜像文件(Superset 中文版、PostgreSQL 14、Redis 7)、1 个 docker-compose.yml 服务编排文件、1 个 superset_config.py 配置文件和 1 个 .env 环境变量文件,覆盖镜像、编排与配置三类核心内容。目前已有 368 人学习。通过该资源,读者可一次性获得离线镜像与配套编排配置,直接导入本地后即可启动多容器服务,省去逐一下载依赖的步骤;同时可参考配置文件中的数据库连接、端口映射与安全认证等参数,快速完成中文界面的初始化与调优,适合具备基础 Docker 使用经验、希望在内网快速落地数据探索与可视化平台的读者。

1. 从一台没外网的机器说起:Superset 4.1.1 中文版离线部署到底难在哪

上周帮一个朋友处理他实验室内网的一台数据可视化服务器,机器是 CentOS 7.9,网卡能通内网但出不了公网,连 yum 源都是内网镜像。他之前照着网上教程docker pull apache/superset:4.1.1,结果卡在拉取镜像那一步整整一下午,终端里全是dial tcp: i/o timeout。这不是个例,Superset 4.1.1 中文版 Docker 离线部署这件事,坑基本都集中在「镜像怎么进去」「中文怎么生效」「元数据库怎么初始化」这三段。它适合两类人:一类是内网、专网、隔离环境里必须把 BI 平台跑起来的运维;另一类是本地想复现一套干净环境、不想被网络波动干扰的开发者。装不好会怎样?最典型的就是容器起来了但登录页 500,或者界面全是英文、中文包根本没加载。这篇就按我实际装的那一遍,把版本、镜像、配置、验证和翻车点全列清楚。

2. 环境先列清:Superset 4.1.1 的版本组合与离线物料准备

2.1 为什么版本组合比单个版本号更重要

Superset 4.1.1 不是一个能单独拎出来装的二进制,它是一套 Python 应用加前端静态资源,跑在容器里时还依赖 PostgreSQL 或 MySQL 做元数据库、Redis 做缓存。离线部署最怕的就是「Superset 版本对了,但 Python 基础镜像或数据库镜像版本不对」。我一般会先把组合固定死,再去找对应的离线包,而不是装到哪算哪。

下面这套是我这次实际用到的组合,Superset 4.1.1 官方镜像基于 Python 3.10,元数据库用 PostgreSQL 14,缓存用 Redis 7。这三个版本在离线环境里互相兼容,没有出现驱动编译问题。

组件版本作用离线物料形式
Superset4.1.1BI 主应用docker save 导出的 tar
PostgreSQL14.x元数据库docker save 导出的 tar
Redis7.x缓存与 Celery brokerdocker save 导出的 tar
Docker Engine20.10+容器运行时内网 yum/apt 源或离线 rpm
Docker Composev2.x编排单二进制文件

提示:Superset 4.x 已经不再推荐 SQLite 做生产元数据库,离线环境里如果只用 SQLite,Celery 和并发查询会出各种玄学问题,我建议直接上 PostgreSQL。

2.2 离线物料的获取与打包

离线部署的核心动作是「在有网的机器上把镜像拉下来,导出成 tar,再拷进内网」。这一步必须在能出公网的机器上做,而且要注意架构一致:内网机器是 x86_64,导出镜像的机器也必须是 x86_64,ARM 和 x86 的镜像不通用。

# 在有外网的机器上执行,拉取三个镜像 docker pull apache/superset:4.1.1 docker pull postgres:14 docker pull redis:7 # 分别导出为 tar 文件,方便拷贝 docker save -o superset-4.1.1.tar apache/superset:4.1.1 docker save -o postgres-14.tar postgres:14 docker save -o redis-7.tar redis:7 # 打包成一个压缩包,减少拷贝体积 tar -czvf superset-offline-bundle.tar.gz \ superset-4.1.1.tar postgres-14.tar redis-7.tar

docker save会把镜像的所有层打成一个 tar,-o指定输出文件名。这里没有用docker export,因为export导的是容器文件系统,会丢镜像元数据,再import回来跑 compose 会缺 entrypoint。tar -czvf只是把三个 tar 再压一层,方便一次性拷进内网。拷贝方式按内网实际情况走,U 盘、内网文件服务器、scp 都行,这一步不涉及任何外网通道。

2.3 内网机器的 Docker 运行时检查

镜像拷进去之前,先确认内网机器的 Docker 能正常工作。很多内网机器装的是老版本 Docker,docker compose子命令还不存在,只有docker-compose。

# 检查 Docker 版本,要求 20.10 以上 docker version --format '{{.Server.Version}}' # 检查 compose 是 v2 插件还是 v1 独立命令 docker compose version 2>/dev/null || docker-compose version

如果输出的是Docker version 19.03这种,Superset 4.1.1 的 compose 文件里有些字段会不认,常见做法是先升级 Docker。内网升级 Docker 就用离线 rpm 包,rpm -Uvh依次装 containerd、docker-ce、docker-ce-cli、docker-compose-plugin。装完systemctl enable --now docker,再docker info看一遍存储驱动,Overlay2 是正常状态。

3. 镜像导入与目录规划:把离线包变成能跑的容器

3.1 导入镜像并核对标签

离线包拷到内网机器后,先解压再逐个导入。导入完必须核对镜像标签,因为docker load有时候会因为 tar 里的 repo tag 丢失导致镜像变成<none>。

# 解压离线包 tar -xzvf superset-offline-bundle.tar.gz # 依次导入三个镜像 docker load -i superset-4.1.1.tar docker load -i postgres-14.tar docker load -i redis-7.tar # 核对镜像列表,确认标签完整 docker images | grep -E 'superset|postgres|redis'

正常输出里应该能看到apache/superset 4.1.1、postgres 14、redis 7三行。如果 Superset 那行显示的是<none>,说明 tar 里的标签丢了,常见做法是重新docker tag一下:docker tag <IMAGE_ID> apache/superset:4.1.1。这一步不做,后面 compose 里写image: apache/superset:4.1.1会直接报找不到镜像。

3.2 目录结构规划

Superset 容器里需要持久化的东西有三块:元数据库数据、Redis 数据、Superset 的superset_config.py。我一般会在宿主机上建一个统一目录,挂载进去,这样容器删了数据还在。

# 创建部署目录 mkdir -p /opt/superset/{postgres-data,redis-data,config} # 目录说明: # postgres-data 挂给 PostgreSQL 的 /var/lib/postgresql/data # redis-data 挂给 Redis 的 /data # config 放 superset_config.py,挂到容器 /app/pythonpath

/opt/superset这个路径按自己习惯改,但三个子目录的用途要分清。postgres-data权限要注意,PostgreSQL 容器里跑的是 uid 999,宿主机目录如果权限不对,容器启动会报initdb: could not change permissions。常见做法是chown -R 999:999 /opt/superset/postgres-data。

3.3 编写 docker-compose.yml

离线环境里 compose 文件不能写build,只能写image,因为构建需要联网拉基础镜像。下面这份是我改过的版本,去掉了官方 compose 里一些离线用不到的服务。

version: "3.8" services: postgres: image: postgres:14 container_name: superset-db environment: POSTGRES_USER: superset POSTGRES_PASSWORD: superset123 POSTGRES_DB: superset volumes: - /opt/superset/postgres-data:/var/lib/postgresql/data restart: unless-stopped redis: image: redis:7 container_name: superset-redis volumes: - /opt/superset/redis-data:/data restart: unless-stopped superset: image: apache/superset:4.1.1 container_name: superset-app depends_on: - postgres - redis environment: SUPERSET_SECRET_KEY: "change_this_to_a_random_string" DATABASE_HOST: postgres DATABASE_PASSWORD: superset123 REDIS_HOST: redis volumes: - /opt/superset/config:/app/pythonpath ports: - "8088:8088" restart: unless-stopped

SUPERSET_SECRET_KEY必须改,官方镜像默认值不安全,而且多个容器共用同一个 key 会出 session 串号。DATABASE_HOST和REDIS_HOST写的是 compose 服务名,Docker 内部 DNS 会解析,不用写 IP。/app/pythonpath是 Superset 读取superset_config.py的默认路径,挂载进去后容器启动会自动加载。

4. 中文配置与元数据库初始化:让界面和登录都正常

4.1 superset_config.py 的关键参数

Superset 4.1.1 的中文生效分两层:一层是前端语言包,一层是后端配置里的默认语言和时区。前端语言包官方镜像里已经带了zh,不需要额外装,但要在配置里把默认语言指过去。

# /opt/superset/config/superset_config.py import os # 元数据库连接,指向 compose 里的 postgres 服务 SQLALCHEMY_DATABASE_URI = ( "postgresql+psycopg2://superset:superset123@postgres:5432/superset" ) # Redis 缓存配置 CACHE_CONFIG = { "CACHE_TYPE": "RedisCache", "CACHE_DEFAULT_TIMEOUT": 300, "CACHE_KEY_PREFIX": "superset_", "CACHE_REDIS_HOST": "redis", "CACHE_REDIS_PORT": 6379, "CACHE_REDIS_DB": 1, } # 默认语言设为简体中文 BABEL_DEFAULT_LOCALE = "zh" LANGUAGES = { "en": {"flag": "us", "name": "English"}, "zh": {"flag": "cn", "name": "简体中文"}, } # 时区,避免图表时间偏移 DEFAULT_TIMEZONE = "Asia/Shanghai" # 关闭示例数据加载,离线环境没必要 SUPERSET_LOAD_EXAMPLES = False

BABEL_DEFAULT_LOCALE设成zh后,新登录用户默认就是中文界面。LANGUAGES里保留 en 和 zh 两个选项,用户还能自己切。DEFAULT_TIMEZONE不设的话,图表时间会比北京时间少 8 小时,这个坑我踩过,排查了半天以为是数据库时区问题。SUPERSET_LOAD_EXAMPLES关掉能省掉初始化时的一堆示例数据集,离线环境里那些数据也用不上。

4.2 初始化元数据库

配置挂好之后,不要急着docker compose up,Superset 第一次启动需要先初始化元数据库,否则登录页会报relation "ab_user" does not exist。

# 先只启动 postgres 和 redis docker compose up -d postgres redis # 等 postgres 健康后,执行元数据库初始化 docker compose run --rm superset superset db upgrade # 创建管理员账号 docker compose run --rm superset superset fab create-admin \ --username admin \ --firstname Admin \ --lastname User \ --email admin@example.com \ --password admin123 # 初始化角色和权限 docker compose run --rm superset superset init

superset db upgrade会按 SQLAlchemy 迁移脚本建表,这一步必须在 Superset 主服务启动前做。fab create-admin是 Flask-AppBuilder 的命令,创建的是 Superset 登录账号。superset init会同步权限和角色,不做这一步管理员登录后看不到菜单。三条命令都用run --rm,跑完容器自动删,不占资源。

4.3 启动主服务并验证中文

初始化完成后,再启动 superset 服务。

# 启动全部服务 docker compose up -d # 查看 superset 日志,确认没有报错 docker compose logs -f superset

日志里看到Running on http://0.0.0.0:8088就说明起来了。浏览器访问http://<内网IP>:8088,用刚才创建的 admin 账号登录。登录后右上角头像菜单里能看到语言切换,默认已经是简体中文。如果界面还是英文,先检查superset_config.py是否真的挂载进去了:docker exec -it superset-app cat /app/pythonpath/superset_config.py,能看到内容说明挂载正常,看不到就是路径写错了。

5. 避坑与排查:离线部署 Superset 4.1.1 最常见的五个翻车点

5.1 现象:容器启动后立即退出,日志显示数据库连接拒绝

原因:depends_on只保证容器启动顺序,不保证 PostgreSQL 已经准备好接受连接。Superset 启动时如果连不上数据库,会直接退出。

解决:在 compose 里给 postgres 加 healthcheck,superset 的depends_on改成带条件的形式。

postgres: # ... 其他配置 healthcheck: test: ["CMD-SHELL", "pg_isready -U superset"] interval: 5s timeout: 5s retries: 10 superset: depends_on: postgres: condition: service_healthy redis: condition: service_started

5.2 现象:登录页能打开,但输入账号密码后报 500

原因:SUPERSET_SECRET_KEY没设或者设成了默认值,Flask session 加密失败。

解决:在 compose 的 superset 环境变量里设一个足够长的随机字符串,然后重启容器。已经产生的 session 会失效,重新登录即可。

5.3 现象:中文界面部分菜单还是英文

原因:Superset 4.1.1 的前端语言包对某些插件菜单的翻译不完整,这是版本本身的问题,不是配置错误。

解决:核心菜单已经是中文,个别插件名保留英文不影响使用。如果一定要全中文,可以在superset_config.py里加BABEL_DEFAULT_LOCALE = "zh"后重新superset init,但不要期待 100% 覆盖。

5.4 现象:docker load 后镜像标签是 none

原因:导出镜像的机器和导入镜像的机器 Docker 版本差异过大,tar 里的 manifest 解析不一致。

解决:重新docker tag打上正确标签,或者在有网机器上用相同大版本 Docker 重新docker save。

5.5 现象:Celery 相关功能报错,异步查询不执行

原因:离线 compose 里只起了 superset 主服务,没有起 celery worker 和 beat。

解决:如果用到异步查询或定时报表,需要在 compose 里补上 worker 和 beat 服务,镜像还是apache/superset:4.1.1,启动命令分别是celery --app=superset.tasks.celery_app:app worker和celery --app=superset.tasks.celery_app:app beat。离线环境里这两个服务不占额外镜像,直接复用主镜像即可。

6. 装完怎么验证:从登录到跑通第一张图表的检查清单

验证一套离线 Superset 是不是真的可用,不能只看登录页打不打得开。我一般会按下面这个顺序走一遍,每一步都过了才算交付。

检查项操作预期结果
容器状态docker compose ps三个服务都是 Up
元数据库表docker exec superset-db psql -U superset -c "\dt"能看到 ab_user 等表
中文界面登录后看右上角语言显示简体中文
数据源连接新建 SQLite 数据源测试连接成功
图表渲染建一张简单表格图正常出图
时区图表时间轴与北京时间一致

数据源连接这一步,离线环境里可以先用 Superset 自带的 SQLite 测试库,路径填sqlite:////app/superset_home/test.db,不用额外装驱动。图表渲染选一个最简单的Table类型,维度拖一列、指标拖一个 count,保存后能出数就说明前后端链路通了。时区检查容易被忽略,建图时把时间列拖到维度里,看显示的小时数是不是和数据库里存的一致,差 8 小时就是DEFAULT_TIMEZONE没生效。

还有一个我每次都会做的动作:把superset_config.py里的SUPERSET_SECRET_KEY和数据库密码单独记到密码管理里,然后docker compose down再up -d一次,确认重启后数据还在、登录还能进。离线环境最怕的就是重启后元数据库挂载丢了,所有仪表盘配置归零。从那以后我每次交付前都强制走一遍「down 再 up」的验证,确认持久化目录真的生效,希望帮到你。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进