Apache Storm 2.8.9 Docker Compose 部署指南

使用 Docker Compose 一键编排 Apache Storm 2.8.9 伪集群(ZooKeeper 3.9.3 + nimbus/supervisor/ui/logviewer),自建 storm:2.8.9 镜像、挂载 storm.yaml、JVM 堆 256-512MB、端口映射与数据卷持久化,含等价 docker run 与常见故障,命令与回显均实测

Apache StormApache Storm2026/10/12

Apache Storm 2.8.9 Docker Compose 部署指南

目标:使用 Docker Compose 编排一套 Apache Storm 2.8.9 伪集群——ZooKeeper 3.9.3 与 Nimbus、Supervisor、UI、Logviewer 四守护进程各占一个服务,通过自建 storm:2.8.9 镜像与挂载 storm.yaml 完成部署,JVM 堆限定 256-512MB,UI 映射到宿主机端口。命令与回显均为实际执行结果。

一、环境信息

  • Docker:24+ / Docker Compose v2(docker compose 子命令)
  • 宿主机:Ubuntu 22.04(x86_64)
  • Storm 镜像:自建 storm:2.8.9(基于 eclipse-temurin:17-jre-jammy,内含 Storm 2.8.9 + python3)
  • ZooKeeper 镜像:zookeeper:3.9.3(官方镜像)
  • 服务:zookeeper、nimbus、supervisor、ui、logviewer
  • 映射端口:6627(nimbus)、6700/6701(worker slots)、18080→8080(ui)、8081(logviewer)、2181(zookeeper)
  • 配置挂载:./conf/storm.yaml → /opt/storm/conf/storm.yaml
  • 数据卷:nimbus-data、supervisor-data、worker-logs

二、镜像选型说明

镜像说明
storm:2.8.9(自建)本指南采用。Docker Hub 无 Apache 官方 Storm 镜像,基于 eclipse-temurin:17-jre-jammy + 发行版 tar.gz 构建,各守护进程共用一个镜像、以 command 切换角色
zookeeper:3.9.3官方 ZooKeeper 镜像,开箱即用;Storm 2.8.9 兼容 ZooKeeper 3.8/3.9

💡 Storm 2.8.9 运行必须 Java 17+,基础镜像选 eclipse-temurin:17-jre-jammy(JRE 即可,运行无需 JDK);镜像内需补装 python3,否则 /opt/storm/bin/storm 命令行与守护进程包装脚本无法执行。

三、前置条件

  • 已安装 Docker 与 Docker Compose v2 的宿主机,root 权限。
  • 准备好 Storm 2.8.9 发行包 apache-storm-2.8.9.tar.gz(372,775,041 字节,sha512:f545c00e84136fd929b84673e15999bf9c31993d78dc6d06aa49f9cf41dfe45786d5564fb5dc2e70b8098b190dcf53092cd53503963d75b3b6384ba8a431a165,来源 https://archive.apache.org/dist/storm/apache-storm-2.8.9/apache-storm-2.8.9.tar.gz 或华为云镜像同名路径)。
  • 宿主机端口未被占用:6627、6700、6701、8081、2181、18080(UI 映射端口,宿主机 8080 常被其他服务占用,故映射到 18080,实测见 FAQ)。

四、部署步骤

4.1 创建目录结构并准备发行包

mkdir -p storm-compose/conf
cd storm-compose
cp /path/to/apache-storm-2.8.9.tar.gz .

4.2 编写 Dockerfile(自建 storm:2.8.9)

cat > Dockerfile <<'EOF'
FROM eclipse-temurin:17-jre-jammy
RUN apt-get update && apt-get install -y --no-install-recommends python3 && rm -rf /var/lib/apt/lists/*
COPY apache-storm-2.8.9.tar.gz /tmp/
RUN cd /tmp && tar -xzf apache-storm-2.8.9.tar.gz \
    && mv apache-storm-2.8.9 /opt/storm \
    && rm -f /tmp/apache-storm-2.8.9.tar.gz \
    && mkdir -p /data/storm
WORKDIR /opt/storm
EOF
关键点说明
python3Storm 命令行/守护进程包装脚本必需
COPY + tar先拷包再解压,比构建时外网下载快且可离线复现
/data/storm预建 storm.local.dir,供挂卷持久化

4.3 编写 storm.yaml(容器间用服务名互访)

cat > conf/storm.yaml <<'EOF'
storm.zookeeper.servers:
    - "zookeeper"
nimbus.seeds: ["nimbus"]
storm.local.dir: "/data/storm"
supervisor.slots.ports:
    - 6700
    - 6701
    - 6702
    - 6703
ui.port: 8080
logviewer.port: 8081
nimbus.childopts: "-Xms256m -Xmx512m"
supervisor.childopts: "-Xms256m -Xmx512m"
ui.childopts: "-Xms256m -Xmx512m"
logviewer.childopts: "-Xms256m -Xmx512m"
EOF

💡 Compose 内置 DNS 按服务名解析:ZooKeeper 地址写服务名 zookeeper,Nimbus 种子写 nimbus。四个守护进程的 JVM 堆统一限制为 256-512MB。

4.4 编写 docker-compose.yml

cat > docker-compose.yml <<'EOF'
services:
  zookeeper:
    image: zookeeper:3.9.3
    container_name: storm-zk
    restart: unless-stopped
    environment:
      ZOO_4LW_COMMANDS_WHITELIST: "srvr,ruok,mntr"
    ports:
      - "2181:2181"

  nimbus:
    image: storm:2.8.9
    container_name: storm-nimbus
    restart: unless-stopped
    command: ["/opt/storm/bin/storm", "nimbus"]
    depends_on:
      - zookeeper
    volumes:
      - ./conf:/opt/storm/conf
      - nimbus-data:/data/storm
    ports:
      - "6627:6627"

  supervisor:
    image: storm:2.8.9
    container_name: storm-supervisor
    restart: unless-stopped
    command: ["/opt/storm/bin/storm", "supervisor"]
    depends_on:
      - nimbus
    volumes:
      - ./conf:/opt/storm/conf
      - supervisor-data:/data/storm
      - worker-logs:/opt/storm/logs
    ports:
      - "6700:6700"
      - "6701:6701"

  ui:
    image: storm:2.8.9
    container_name: storm-ui
    restart: unless-stopped
    command: ["/opt/storm/bin/storm", "ui"]
    depends_on:
      - nimbus
    volumes:
      - ./conf:/opt/storm/conf
    ports:
      - "18080:8080"

  logviewer:
    image: storm:2.8.9
    container_name: storm-logviewer
    restart: unless-stopped
    command: ["/opt/storm/bin/storm", "logviewer"]
    depends_on:
      - supervisor
    volumes:
      - ./conf:/opt/storm/conf
      - worker-logs:/opt/storm/logs
    ports:
      - "8081:8081"

volumes:
  nimbus-data:
  supervisor-data:
  worker-logs:
EOF
配置项说明
image: storm:2.8.9自建镜像,五个服务共用,command 决定各自角色
command: ["/opt/storm/bin/storm", "nimbus"]前台运行对应守护进程,PID 1 可被 compose 跟踪,崩溃自动重启
ports: 18080:8080UI 映射到宿主机 18080(宿主机 8080 被 haproxy 占用时的高位端口规避,实测踩坑见 11.1)
volumes: ./conf:/opt/storm/conf挂载自定义 storm.yaml,改配置后 docker compose restart 即生效
volumes: nimbus-data / supervisor-dataNimbus 与 Supervisor 各自独立的 storm.local.dir(二者本就不应共享本地状态目录)
volumes: worker-logsSupervisor 与 Logviewer 共享 /opt/storm/logs,Logviewer 才能看到 Worker 日志

4.5 构建镜像并启动

docker build -t storm:2.8.9 .
docker compose up -d

实测回显(节选):

 Container storm-logviewer Creating
 Container storm-logviewer Created
 Container storm-zk Starting
 Container storm-zk Started
 Container storm-nimbus Starting
 Container storm-nimbus Started
 Container storm-ui Starting
 Container storm-supervisor Starting
 Container storm-supervisor Started
 Container storm-ui Started
 Container storm-logviewer Started

4.6 验证服务

docker compose ps --format '{{.Name}} {{.Status}}'

实测回显:

storm-logviewer Up 30 seconds
storm-nimbus Up About a minute
storm-supervisor Up About a minute
storm-ui Up 30 seconds
storm-zk Up About a minute

Storm UI 接口验证(ui 服务内):

docker exec storm-ui curl -s http://127.0.0.1:8080/api/v1/cluster/summary

实测回显(节选):

{"stormVersion":"2.8.9","fragmentedCpu":0.0,"executorsTotal":0,"totalMem":4096.0,"availCpu":400.0,"slotsTotal":4,"stormVersionInfo":{"date":"2026-07-18T15:27Z","srcChecksum":"dd8ab586a06db2ced58135f6be47980",...

宿主机侧验证映射端口与 CLI:

curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:18080/
docker exec storm-nimbus /opt/storm/bin/storm list

实测回显:

200
Running: java -client -Ddaemon.name= ... org.apache.storm.command.ListTopologies
13:27:34.919 [main] INFO  o.a.s.u.NimbusClient - Found leader nimbus : 02503e8a5ea5:6627:0
No topologies running.

💡 Found leader nimbus 说明 Nimbus/ZooKeeper/Supervisor 协调链路全部打通。浏览器访问 http://<宿主机IP>:18080 即 Storm UI。

五、数据持久化说明

  • nimbus-data 卷持久化 Nimbus 的 storm.local.dir(拓扑 jar 暂存 inbox、分配状态),删除服务不丢上传记录。
  • supervisor-data 卷持久化 Supervisor 本地状态(worker 心跳等),独立于 nimbus 卷,符合真实集群「各节点本地目录不共享」原则。
  • worker-logs 卷被 supervisor 与 logviewer 共享挂载到 /opt/storm/logs:Worker 日志落此卷,Logviewer 网页(8081)据此展示拓扑各组件日志。
  • ./conf 宿主机目录挂载:修改 storm.yaml 后执行 docker compose restart nimbus 逐服务重启生效,配置随目录持久化。
  • docker compose down 保留三个命名卷;docker compose down -v 才会清空数据。

六、常用环境变量表

Storm 自身主要靠 storm.yaml 配置,Compose 层常用的环境变量如下:

环境变量适用服务说明本指南值
ZOO_4LW_COMMANDS_WHITELISTzookeeper放行四字命令(srvr/ruok/mntr)供健康检查srvr,ruok,mntr
STORM_JAVA_HOME全部 Storm 服务指定 java 路径(基础镜像默认已在 PATH,一般无需设置)不设置
ZOO_MY_ID / ZOO_SERVERSzookeeper组建多节点 ZK 集群时使用(单节点无需)不设置

💡 JVM 堆由 storm.yaml 的 *.childopts 控制而非环境变量,这也是自建镜像 + 挂载 conf 的好处:四守护进程堆 256-512MB 集中一处管理。

七、常用配置参数说明(command)

command 字段覆盖镜像默认进程,对应 /opt/storm/bin/storm <daemon> 前台运行:

command 值说明
["/opt/storm/bin/storm", "nimbus"]主控守护进程,拓扑分发与调度(本指南 nimbus 服务)
["/opt/storm/bin/storm", "supervisor"]工作节点守护进程,拉起 Worker(本指南 supervisor 服务)
["/opt/storm/bin/storm", "ui"]Web UI,默认 8080(本指南 ui 服务)
["/opt/storm/bin/storm", "logviewer"]日志查看服务,默认 8081(本指南 logviewer 服务)

八、配置文件持久化(conf 挂载)

挂载 ./conf 后所有配置变更只改宿主文件,按服务逐个重启生效:

vim conf/storm.yaml
docker compose restart nimbus
docker compose restart supervisor
docker compose restart ui
docker compose restart logviewer

⚠️ storm.zookeeper.servers 与 nimbus.seeds 必须写 compose 服务名(zookeeper/nimbus);改成容器内 IP 会在重启后因 IP 变化失联。改 JVM 堆时直接调 *.childopts(当前 -Xms256m -Xmx512m),无需动镜像。

九、等价 docker run 运行方式

不使用 compose 文件时,可等价地逐条 docker run(先自建网络供服务名解析):

docker network create storm-net

docker run -d --name storm-zk --network storm-net \
  -p 2181:2181 zookeeper:3.9.3

docker run -d --name storm-nimbus --network storm-net \
  -v "$PWD/conf:/opt/storm/conf" -v storm-nimbus-data:/data/storm \
  -p 6627:6627 storm:2.8.9 /opt/storm/bin/storm nimbus

docker run -d --name storm-supervisor --network storm-net \
  -v "$PWD/conf:/opt/storm/conf" -v storm-supervisor-data:/data/storm \
  -v storm-worker-logs:/opt/storm/logs \
  -p 6700:6700 -p 6701:6701 storm:2.8.9 /opt/storm/bin/storm supervisor

docker run -d --name storm-ui --network storm-net \
  -v "$PWD/conf:/opt/storm/conf" \
  -p 18080:8080 storm:2.8.9 /opt/storm/bin/storm ui

docker run -d --name storm-logviewer --network storm-net \
  -v "$PWD/conf:/opt/storm/conf" -v storm-worker-logs:/opt/storm/logs \
  -p 8081:8081 storm:2.8.9 /opt/storm/bin/storm logviewer

与 compose 版等价的关键:同一自定义网络(服务名互访)、相同 conf 挂载、supervisor 与 logviewer 共享 worker-logs 卷。

十、常用运维命令

docker compose up -d              # 启动全栈
docker compose ps                 # 查看各服务状态
docker compose logs -f nimbus     # 跟踪 nimbus 日志
docker compose logs -f supervisor # 跟踪 supervisor 日志
docker compose restart ui         # 重启单个服务
docker exec storm-nimbus /opt/storm/bin/storm list   # 容器内查看拓扑
docker compose down               # 停止并删除服务(保留数据卷)
docker compose down -v            # 停止并删除服务与数据卷

十一、常见问题(FAQ)

11.1:UI 服务启动失败,failed to bind host port 0.0.0.0:8080/tcp: address already in use

实测回显:

Error response from daemon: failed to set up container networking: driver failed programming external connectivity on endpoint storm-ui (...): failed to bind host port 0.0.0.0:8080/tcp: address already in use

定位:宿主机 8080 已被其他进程占用(实测环境为 haproxy,ss -tlnp | grep 8080 可见)。 解决:改用高位端口映射 18080:8080(本指南做法),或释放宿主机 8080 后再启动。

11.2:容器反复重启,日志报 /usr/bin/env: 'python3': No such file or directory

定位:基础镜像无 python3,storm 包装脚本无法执行。 解决:确认使用本指南 Dockerfile(apt-get install -y python3),重新 docker build。

11.3:storm list 卡住或报连接拒绝

定位:服务启动顺序问题,depends_on 只保证启动顺序不保证 ZooKeeper 就绪。 解决:ZooKeeper 起来后约 10-30 秒再执行;docker compose logs zookeeper 看到 binding to port 0.0.0.0/0.0.0.0:2181 后再试 CLI。

11.4:宿主机执行 docker compose up -d --build 尝试从远端拉取 storm:2.8.9 失败

定位:本地不存在该镜像时 compose 会先尝试 registry 拉取(Docker Hub 无官方 storm 镜像,必然失败)。 解决:先执行 docker build -t storm:2.8.9 . 构建本地镜像,再 docker compose up -d。

11.5:Logviewer 打不开拓扑日志

定位:logviewer 与 supervisor 不共享 /opt/storm/logs 卷,worker 日志不可见。 解决:按 4.4 节为两个服务挂载同一个 worker-logs 卷。

十二、参考链接