Apache Samza 1.8.0 Docker Compose 部署指南

Apache Samza 1.8.0 Docker Compose 部署指南:ZooKeeper 3.9、Kafka 4.3.1 与 Samza 作业编排 hello-samza,含 topic 预建与排障,JVM 堆 256-512MB

Apache SamzaApache Samza2026/10/13

Apache Samza 1.8.0 Docker Compose 部署指南

目标:使用 Docker Compose 在单机一键编排 Apache Samza 1.8.0 流处理环境——ZooKeeper 3.9 协调、Kafka 4.3.1 消息总线、Samza 作业镜像常驻消费并产出统计流。以下编排文件与回显均在真实环境逐步实测(wikipedia-stats 偏移量持续增长验证全链路)。

一、环境信息

项目值
Docker24+(含 Compose v2)
ZooKeeper 镜像zookeeper:3.9(端口 2181)
Kafka 镜像apache/kafka:4.3.1(端口 9092,KRaft 模式,无需外部 ZK 协调集群)
Samza 作业镜像基于 ubuntu:22.04 + OpenJDK 11 构建(含 hello-samza dist)
样例应用hello-samza(Samza 1.8.0 依赖,Wikipedia 流处理)
编排目录/opt/samza-compose
JVM 堆各组件统一 -Xms256m -Xmx512m

二、镜像选型说明

服务镜像说明
zookeeperzookeeper:3.9官方镜像,SERVER_JVMFLAGS 控制 JVM 堆
kafkaapache/kafka:4.3.1官方镜像,KRaft(KAFKA_PROCESS_ROLES=broker,controller)自协调,KAFKA_HEAP_OPTS 控制 JVM 堆
samza-job自构建(build: .)ubuntu:22.04 + openjdk-11-jdk-headless + hello-samza dist tar,入口 run-class.sh 启动 WikipediaZkLocalApplication

💡 Kafka 4.x 已移除对 ZooKeeper 的协调依赖(KRaft),但 Samza 作业的协调器与消费者位移仍使用 ZooKeeper,因此两个服务并存。

三、前置条件

  • 一台装有 Docker(24+)与 Docker Compose v2 的 Linux 服务器,root 权限。
  • 准备 Samza 作业镜像构建素材:
    • hello-samza-1.6.0-dist.tar.gz(142,047,404 字节,内含 Samza 1.8.0 构件)——由「Apache Samza 1.8.0 安装指南」4.4 节构建产物拷贝而来;
    • 作业配置文件 wikipedia-application-local-runner-compose.properties(见 4.3)。
  • 网络可访问 Docker Hub(拉取 zookeeper:3.9 与 apache/kafka:4.3.1)。

四、部署步骤

4.1 创建编排目录与文件

mkdir -p /opt/samza-compose
cd /opt/samza-compose
cp /path/to/hello-samza-1.6.0-dist.tar.gz .   # 安装指南 4.4 构建产物

4.2 编写 compose.yml

services:
  zookeeper:
    image: zookeeper:3.9
    container_name: samza-zookeeper
    restart: unless-stopped
    environment:
      SERVER_JVMFLAGS: "-Xms256m -Xmx512m"
    ports:
      - "2181:2181"
    volumes:
      - zk-data:/data
      - zk-datalog:/datalog

  kafka:
    image: apache/kafka:4.3.1
    container_name: samza-kafka
    restart: unless-stopped
    depends_on:
      - zookeeper
    environment:
      KAFKA_NODE_ID: 1
      KAFKA_PROCESS_ROLES: broker,controller
      KAFKA_CONTROLLER_QUORUM_VOTERS: "1@kafka:9093"
      KAFKA_LISTENERS: "PLAINTEXT://:9092,CONTROLLER://:9093"
      KAFKA_ADVERTISED_LISTENERS: "PLAINTEXT://kafka:9092"
      KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: "PLAINTEXT:PLAINTEXT,CONTROLLER:PLAINTEXT"
      KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
      KAFKA_HEAP_OPTS: "-Xms256m -Xmx512m"
    ports:
      - "9092:9092"
    volumes:
      - kafka-data:/var/lib/kafka/data

  samza-job:
    build: .
    container_name: samza-job
    restart: unless-stopped
    depends_on:
      - zookeeper
      - kafka

volumes:
  zk-data:
  zk-datalog:
  kafka-data:

4.3 编写作业配置与 Dockerfile

wikipedia-application-local-runner-compose.properties(关键点:ZooKeeper/Kafka 用 Compose 服务名解析,properties 覆盖应用描述符中硬编码的 localhost 地址——实测生效):

job.name=wikipedia-application-compose
job.coordinator.factory=org.apache.samza.zk.ZkJobCoordinatorFactory
job.coordinator.zk.connect=zookeeper:2181
job.coordinator.system=kafka
job.default.system=kafka
task.name.grouper.factory=org.apache.samza.container.grouper.task.GroupByContainerIdsFactory
serializers.registry.string.class=org.apache.samza.serializers.StringSerdeFactory
serializers.registry.integer.class=org.apache.samza.serializers.IntegerSerdeFactory
stores.wikipedia-stats.factory=org.apache.samza.storage.kv.RocksDbKeyValueStorageEngineFactory
stores.wikipedia-stats.changelog=kafka.wikipedia-stats-changelog
stores.wikipedia-stats.key.serde=string
stores.wikipedia-stats.msg.serde=integer
systems.kafka.samza.factory=org.apache.samza.system.kafka.KafkaSystemFactory
systems.kafka.consumer.zookeeper.connect=zookeeper:2181/
systems.kafka.producer.bootstrap.servers=kafka:9092

Dockerfile:

# Apache Samza 1.8.0 作业镜像(ZK 协调器本地运行模式,单 JVM 进程)
FROM ubuntu:22.04

RUN apt-get update -qq \
    && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
       openjdk-11-jdk-headless wget net-tools procps \
    && rm -rf /var/lib/apt/lists/*

WORKDIR /opt/hello-samza
COPY hello-samza-1.6.0-dist.tar.gz /opt/hello-samza/
RUN tar -xzf hello-samza-1.6.0-dist.tar.gz \
    && rm -f hello-samza-1.6.0-dist.tar.gz

COPY wikipedia-application-local-runner-compose.properties /opt/hello-samza/config/

# JVM 堆限制 256-512MB(run-class.sh 检测到 -Xmx 后不再叠加默认 768M)
ENV JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64
ENV PATH=${JAVA_HOME}/bin:/opt/hello-samza/bin:${PATH}
ENV JAVA_OPTS="-Xms256m -Xmx512m"

WORKDIR /opt/hello-samza
CMD ["bin/run-class.sh", "samza.examples.wikipedia.application.WikipediaZkLocalApplication", \
     "--config", "job.config.loader.factory=org.apache.samza.config.loaders.PropertiesConfigLoaderFactory", \
     "--config", "job.config.loader.properties.path=/opt/hello-samza/config/wikipedia-application-local-runner-compose.properties"]

4.4 启动编排

cd /opt/samza-compose
docker compose up -d
docker compose ps

真实回显(三服务均 Up):

NAME              IMAGE                     COMMAND                   SERVICE      STATUS
samza-job         samza-compose-samza-job   "bin/run-class.sh sa…"    samza-job    Up 2 minutes
samza-kafka       apache/kafka:4.3.1        "/__cacert_entrypoin…"    kafka        Up 2 minutes
samza-zookeeper   zookeeper:3.9             "/docker-entrypoint.…"    zookeeper    Up 2 minutes

4.5 预建 Kafka topic

# 进入 Kafka 容器执行(或宿主机装有 kafka 客户端时直连 localhost:9092)
docker exec -it samza-kafka /opt/kafka/bin/kafka-topics.sh \
  --bootstrap-server localhost:9092 \
  --create --topic wikipedia-raw --partitions 1 --replication-factor 1
docker exec -it samza-kafka /opt/kafka/bin/kafka-topics.sh \
  --bootstrap-server localhost:9092 \
  --create --topic wikipedia-edits --partitions 1 --replication-factor 1

⚠️ wikipedia-raw(输入)与 wikipedia-edits 必须预建,否则作业启动时报 SamzaException: Partition info not(yet?) available for system kafka topic wikipedia-raw 并反复重启。

4.6 验证作业运行与数据链路

作业日志应出现协调器成为 leader、进入 run loop:

docker logs samza-job 2>&1 | grep -E 'became the leader|Entering run loop|Container PID'

真实回显(节选):

ZkJobCoordinator [INFO] ZkJobCoordinator::onBecomeLeader - I became the leader
SamzaContainer [INFO] Entering run loop.

数据链路验证(wikipedia-stats 偏移量持续增长):

docker exec samza-kafka /opt/kafka/bin/kafka-get-offsets.sh \
  --bootstrap-server localhost:9092 --topic wikipedia-stats
docker exec samza-kafka /opt/kafka/bin/kafka-get-offsets.sh \
  --bootstrap-server localhost:9092 --topic wikipedia-stats

真实回显(间隔 30 秒,偏移量持续增长):

wikipedia-stats:0:2
wikipedia-stats:0:13

💡 __samza_coordinator_wikipedia-application-compose_1、wikipedia-application-compose-1-window-statsWindow、wikipedia-stats-changelog 由作业自动创建。

五、数据持久化说明

  • zk-data:/data 与 zk-datalog:/datalog:ZooKeeper 数据与事务日志卷,重启不丢;
  • kafka-data:/var/lib/kafka/data:Kafka 消息日志卷,重启不丢;
  • 作业容器为无状态计算节点(任务状态经 Kafka changelog 持久化),无需额外卷。

六、常用环境变量表

服务变量默认值说明
zookeeperSERVER_JVMFLAGS-Xms256m -Xmx512mZK JVM 堆参数
kafkaKAFKA_NODE_ID1KRaft 节点 ID
kafkaKAFKA_PROCESS_ROLESbroker,controllerKRaft 角色(单节点兼任)
kafkaKAFKA_ADVERTISED_LISTENERSPLAINTEXT://kafka:9092客户端可达地址(Compose 网络内服务名)
kafkaKAFKA_HEAP_OPTS-Xms256m -Xmx512mBroker JVM 堆
samza-jobJAVA_OPTS-Xms256m -Xmx512m作业 JVM 堆

七、常用配置参数说明

  • job.coordinator.zk.connect=zookeeper:2181:作业协调器 ZooKeeper 地址(Compose 服务名解析)。
  • systems.kafka.consumer.zookeeper.connect=zookeeper:2181/:消费者位移 ZooKeeper。
  • systems.kafka.producer.bootstrap.servers=kafka:9092:生产端 Kafka 地址。
  • 上述 properties 优先级高于应用描述符中硬编码的 localhost 地址(实测:将 bootstrap.servers 改为错误端口 9999 后作业报连接失败,证明覆盖生效)。

八、配置文件持久化

  • wikipedia-application-local-runner-compose.properties 随镜像构建固化到 /opt/hello-samza/config/;
  • 修改配置后需重建作业镜像:docker compose up -d --build samza-job;
  • 也可以将配置文件挂载卷覆盖镜像内副本,免重建(推荐生产做法):
    volumes:
      - ./wikipedia-application-local-runner-compose.properties:/opt/hello-samza/config/wikipedia-application-local-runner-compose.properties:ro

九、等价 docker run 运行方式

不使用 Compose 时,三个服务等价于以下 docker run(同一自定义网络内):

docker network create samza-net

docker run -d --name samza-zookeeper --network samza-net \
  -e SERVER_JVMFLAGS="-Xms256m -Xmx512m" -p 2181:2181 \
  -v zk-data:/data -v zk-datalog:/datalog \
  zookeeper:3.9

docker run -d --name samza-kafka --network samza-net \
  -e KAFKA_NODE_ID=1 -e KAFKA_PROCESS_ROLES=broker,controller \
  -e KAFKA_CONTROLLER_QUORUM_VOTERS="1@kafka:9093" \
  -e KAFKA_LISTENERS="PLAINTEXT://:9092,CONTROLLER://:9093" \
  -e KAFKA_ADVERTISED_LISTENERS="PLAINTEXT://kafka:9092" \
  -e KAFKA_CONTROLLER_LISTENER_NAMES=CONTROLLER \
  -e KAFKA_LISTENER_SECURITY_PROTOCOL_MAP="PLAINTEXT:PLAINTEXT,CONTROLLER:PLAINTEXT" \
  -e KAFKA_INTER_BROKER_LISTENER_NAME=PLAINTEXT \
  -e KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR=1 \
  -e KAFKA_HEAP_OPTS="-Xms256m -Xmx512m" -p 9092:9092 \
  -v kafka-data:/var/lib/kafka/data \
  apache/kafka:4.3.1

docker build -t samza-job:1.8.0 .
docker run -d --name samza-job --network samza-net samza-job:1.8.0

十、常用运维命令

# 查看状态
docker compose ps

# 查看作业日志(过滤关键行)
docker logs -f samza-job
docker logs samza-job 2>&1 | grep -E 'ERROR|Exception' | tail -20

# 进入 Kafka 容器操作 topic / 偏移量
docker exec -it samza-kafka /opt/kafka/bin/kafka-topics.sh \
  --bootstrap-server localhost:9092 --list
docker exec -it samza-kafka /opt/kafka/bin/kafka-get-offsets.sh \
  --bootstrap-server localhost:9092 --topic wikipedia-stats

# 向输入 topic 灌数据
docker exec -i samza-kafka /opt/kafka/bin/kafka-console-producer.sh \
  --bootstrap-server localhost:9092 --topic wikipedia-raw < wikipedia-raw.json

# 消费验证输出
docker exec -it samza-kafka /opt/kafka/bin/kafka-console-consumer.sh \
  --bootstrap-server localhost:9092 --topic wikipedia-stats --from-beginning --max-messages 2

# 重建作业镜像并滚动生效
docker compose up -d --build samza-job

# 整体停止
docker compose down
# 连数据卷一并清除(谨慎)
docker compose down -v

十一、常见问题

11.1 作业容器反复重启(Exit 0 循环)

现象:docker compose ps 显示 samza-job Up N seconds,RestartCount 持续增长。

定位:两种常见原因——

  1. 输入 topic 未预建:日志报 SamzaException: Partition info not(yet?) available for system kafka topic wikipedia-raw;
  2. 配置含未定义序列化器:日志报 buildSystemSerdeMap: No class defined for serde: json(如配置了 systems.kafka.samza.msg.serde=json 却未定义 serializers.json.class)。

解决:先 docker logs samza-job | tail -30 定位具体报错;按 4.5 预建 topic,或从配置删除未定义的 serde 行,然后 docker compose up -d --build samza-job。

11.2 作业启动日志出现 Unrecognized option: -d64 / Unrecognized VM option 'PrintGCDateStamps'

定位:Samza run-class.sh 对 Java 11 的 JVM 兼容性探测输出(Java 8 支持这些参数,Java 11 不支持即跳过),属正常探测噪音,不影响运行。

解决:无需处理。

11.3 Kafka 4.x 无 --describe 选项

现象:kafka-get-offsets.sh --describe 报错。

解决:Kafka 4.x 的 GetOffsetShell 移除该选项,直接 --topic <名称> 即可。

11.4 作业进程启动后很快退出(Exit 0)

定位:若改用 run-app.sh 提交本地 ZK 模式作业,leader 选举后主线程正常返回退出(exit 0),属预期行为;且上一轮残留的 ZK ephemeral 节点会导致新一轮非 leader 直接退出。

解决:作业镜像应使用含 waitForFinish 的入口类 WikipediaZkLocalApplication;残留节点用 docker exec samza-zookeeper zkCli.sh deleteall /app-wikipedia-application-compose-1 清理后重建。

十二、参考链接