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 Samza 1.8.0 Docker Compose 部署指南
目标:使用 Docker Compose 在单机一键编排 Apache Samza 1.8.0 流处理环境——ZooKeeper 3.9 协调、Kafka 4.3.1 消息总线、Samza 作业镜像常驻消费并产出统计流。以下编排文件与回显均在真实环境逐步实测(
wikipedia-stats偏移量持续增长验证全链路)。
一、环境信息
| 项目 | 值 |
|---|---|
| Docker | 24+(含 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 |
二、镜像选型说明
| 服务 | 镜像 | 说明 |
|---|---|---|
| zookeeper | zookeeper:3.9 | 官方镜像,SERVER_JVMFLAGS 控制 JVM 堆 |
| kafka | apache/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 持久化),无需额外卷。
六、常用环境变量表
| 服务 | 变量 | 默认值 | 说明 |
|---|---|---|---|
| zookeeper | SERVER_JVMFLAGS | -Xms256m -Xmx512m | ZK JVM 堆参数 |
| kafka | KAFKA_NODE_ID | 1 | KRaft 节点 ID |
| kafka | KAFKA_PROCESS_ROLES | broker,controller | KRaft 角色(单节点兼任) |
| kafka | KAFKA_ADVERTISED_LISTENERS | PLAINTEXT://kafka:9092 | 客户端可达地址(Compose 网络内服务名) |
| kafka | KAFKA_HEAP_OPTS | -Xms256m -Xmx512m | Broker JVM 堆 |
| samza-job | JAVA_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 持续增长。
定位:两种常见原因——
- 输入 topic 未预建:日志报
SamzaException: Partition info not(yet?) available for system kafka topic wikipedia-raw; - 配置含未定义序列化器:日志报
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 清理后重建。
十二、参考链接
- ZooKeeper 镜像:https://hub.docker.com/_/zookeeper
- Apache Kafka 镜像:https://hub.docker.com/r/apache/kafka
- Apache Samza:https://samza.apache.org/
- hello-samza:https://github.com/apache/samza-hello-samza