目录
1. 方案一:整合到一个 docker-compose.yml 文件
2. 方案二:使用单独的 docker-compose.yml
一、Spark 与 Kafka 的 Docker 部署方案
对于已有的 Kafka+Zookeeper Docker 部署,现在想要添加 Spark,有两种主要方案:
1. 方案一:整合到一个 docker-compose.yml 文件
优点: 集中管理所有相关服务; 简化网络配置 ;容易理解整个系统架构
实现方式: 在已有的 docker-compose.yml 中添加 Spark 相关服务,例如:
version: '3'
services:
zookeeper:
# 你已有的 zookeeper 配置...
kafka:
# 你已有的 kafka 配置...
spark-master:
image: bitnami/spark:latest
environment:
- SPARK_MODE=master
ports:
- "8080:8080"
- "7077:7077"
spark-worker:
image: bitnami/spark:latest
environment:
- SPARK_MODE=worker
- SPARK_MASTER_URL=spark://spark-master:7077
depends_on:
- spark-master
2. 方案二:使用单独的 docker-compose.yml
优点:服务职责更加清晰分离;更灵活地独立管理服务;避免单个配置文件过于庞大
实现方式: 创建一个新的 docker-compose.yml 文件,专门用于 Spark:
version: '3'
services:
spark-master:
image: bitnami/spark:latest
environment:
- SPARK_MODE=master
ports:
- "8080:8080"
- "7077:7077"
networks:
- spark-network
- kafka-network # 与 Kafka 网络连接
spark-worker:
image: bitnami/spark:latest
environment:
- SPARK_MODE=worker
- SPARK_MASTER_URL=spark://spark-master:7077
depends_on:
- spark-master
networks:
- spark-network
networks:
spark-network:
driver: bridge
kafka-network:
external: true # 使用 Kafka 的外部网络
3. 关于 Zookeeper
不需要重复安装 Zookeeper。如果选择方案二(分开部署),Spark 可以通过 Docker 网络直接使用已有的 Zookeeper 实例。
只需确保:(1)在 Kafka 的 docker-compose.yml 中为网络命名;(2)在 Spark 的配置中将该网络声明为 external 网络;(3)先启动包含 Zookeeper 和 Kafka 的 docker-compose,然后再启动包含 Spark 的 docker-compose。
4. 建议
如果系统规模不大,建议使用方案一(单一 docker-compose 文件),这样更容易管理和理解整体架构。
如果希望更灵活地管理不同服务,或者已经有一个非常复杂的 Kafka 设置,方案二可能更合适。
无论哪种方案,确保在 Docker 网络配置上做好连接,让 Spark 能够访问 Kafka 和 Zookeeper。
二、分开部署 Spark
1. 创建目录结构
目录结构如下:
# 个人开发环境 目录
~/dev/
└── docker/ # spark-docker-compose.yml 相关配置
# 挂载目录
/data
├── spark/
│ ├── data/ # /opt/bitnami/spark/data 的挂载目录
│ │ ├── master/ # Spark Master节点
│ │ ├── worker1/ # Spark Worker1节点
│ │ └── worker2/ # Spark Worker2节点
│ ├── conf/ # /opt/bitnami/spark/conf 的挂载目录
│ │ ├── master/ # Spark Master节点
│ │ ├── worker1/ # Spark Worker1节点
│ │ └── worker2/ # Spark Worker2节点
│ └── logs/ # /opt/bitnami/spark/logs 的挂载目录
│ ├── master/ # Spark Master节点
│ ├── worker1/ # Spark Worker1节点
│ └── worker2/ # Spark Worker2节点
├── prometheus/
│ └── prometheus.yml # /etc/prometheus/prometheus.yml 的挂载文件
└── grafana/
└── data/ # /var/lib/grafana 的挂载目录
命令如下:
# 以app用户登录执行
mkdir -p ~/dev/docker
# 以root用户登录执行
sudo mkdir -p /data/spark/data/{master,worker1,worker2} /data/spark/conf/{master,worker1,worker2} /data/spark/logs/{master,worker1,worker2} /data/prometheus /data/grafana/data
sudo chown -R 1000:1000 /data/prometheus
# Bitnami 标准: Bitnami 在其容器设计中采用了 1001 作为其非 root 用户的标准 UID
sudo chown -R 1001:1001 /data/spark
# Grafana 通常使用 UID 472
sudo chown -R 472:472 /data/grafana
# 权限 700 表示:所有者(app):可读、可写、可执行;用户组和其他人:无权限
sudo chmod -R 700 /data/spark /data/prometheus /data/grafana
效果图如下:
2. 创建配置文件
2.1. Spark配置文件
在目录 /data/spark/conf/master 下创建文件 spark-defaults.conf,内容如下:
# Spark Master默认配置
spark.master spark://spark-master:7077
spark.executor.memory 2g
spark.driver.memory 1g
spark.executor.cores 2
spark.default.parallelism 8
spark.serializer org.apache.spark.serializer.KryoSerializer
spark.driver.extraJavaOptions -XX:+UseG1GC -XX:+DisableExplicitGC
spark.executor.extraJavaOptions -XX:+UseG1GC -XX:+DisableExplicitGC
spark.ui.port 8080
在目录 /data/spark/conf/worker下创建文件 spark-defaults.conf,内容如下:
# Spark Worker默认配置
spark.executor.memory 2g
spark.driver.memory 1g
spark.executor.cores 2
spark.serializer org.apache.spark.serializer.KryoSerializer
spark.driver.extraJavaOptions -XX:+UseG1GC -XX:+DisableExplicitGC
spark.executor.extraJavaOptions -XX:+UseG1GC -XX:+DisableExplicitGC
2.2. Prometheus配置文件
在目录 /data/prometheus 下创建文件 prometheus.yml,内容如下:
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: 'spark-master'
static_configs:
- targets: ['spark-master:8080']
- job_name: 'spark-worker-1'
static_configs:
- targets: ['spark-worker-1:8081']
- job_name: 'spark-worker-2'
static_configs:
- targets: ['spark-worker-2:8081']
3. 创建 Docker Compose 配置
在目录 /dev/docker 下创建自定义名称文件 spark-docker-compose.yml,内容如下:
version: '3'
networks:
spark_net:
driver: bridge
kafka_net:
external: true # 使用 Kafka 的外部网络
name: <kafka网络名称> # 添加这一行,指定确切的外部网络名称
services:
# 添加ZooKeeper代理容器
zk-proxy:
image: alpine
container_name: zk-proxy
command: sh -c "apk add socat && socat TCP-LISTEN:2181,fork,reuseaddr TCP:zookeeper:2181"
networks:
- spark_net
- kafka_net
restart: always
# Spark Master节点
spark-master:
image: bitnami/spark:3.5.0
container_name: spark-master
environment:
- SPARK_MODE=master
- SPARK_RPC_AUTHENTICATION_ENABLED=no
- SPARK_RPC_ENCRYPTION_ENABLED=no
- SPARK_LOCAL_STORAGE_ENCRYPTION_ENABLED=no
- SPARK_SSL_ENABLED=no
- SPARK_DAEMON_JAVA_OPTS=-XX:+UseG1GC -XX:+DisableExplicitGC -Dspark.deploy.recoveryMode=ZOOKEEPER -Dspark.deploy.zookeeper.url=zk-proxy:2181
ports:
- '8080:8080'
- '7077:7077'
volumes:
- /data/spark/data/master:/opt/bitnami/spark/data
- /data/spark/conf/master:/opt/bitnami/spark/conf
- /data/spark/logs/master:/opt/bitnami/spark/logs
restart: always
networks:
- spark_net
deploy:
resources:
limits:
memory: 4G
reservations:
memory: 2G
# Spark Worker节点1
spark-worker-1:
image: bitnami/spark:3.5.0
container_name: spark-worker-1
environment:
- SPARK_MODE=worker
- SPARK_MASTER_URL=spark://spark-master:7077
- SPARK_WORKER_MEMORY=2G
- SPARK_WORKER_CORES=2
- SPARK_RPC_AUTHENTICATION_ENABLED=no
- SPARK_RPC_ENCRYPTION_ENABLED=no
- SPARK_LOCAL_STORAGE_ENCRYPTION_ENABLED=no
- SPARK_SSL_ENABLED=no
- SPARK_DAEMON_JAVA_OPTS=-XX:+UseG1GC -XX:+DisableExplicitGC
ports:
- '8081:8081'
volumes:
- /data/spark/data/worker1:/opt/bitnami/spark/data
- /data/spark/conf/worker1:/opt/bitnami/spark/conf
- /data/spark/logs/worker1:/opt/bitnami/spark/logs
restart: always
depends_on:
- spark-master
networks:
- spark_net
deploy:
resources:
limits:
memory: 4G
reservations:
memory: 2G
# Spark Worker节点2
spark-worker-2:
image: bitnami/spark:3.5.0
container_name: spark-worker-2
environment:
- SPARK_MODE=worker
- SPARK_MASTER_URL=spark://spark-master:7077
- SPARK_WORKER_MEMORY=2G
- SPARK_WORKER_CORES=2
- SPARK_RPC_AUTHENTICATION_ENABLED=no
- SPARK_RPC_ENCRYPTION_ENABLED=no
- SPARK_LOCAL_STORAGE_ENCRYPTION_ENABLED=no
- SPARK_SSL_ENABLED=no
- SPARK_DAEMON_JAVA_OPTS=-XX:+UseG1GC -XX:+DisableExplicitGC
ports:
- '8082:8081'
volumes:
- /data/spark/data/worker2:/opt/bitnami/spark/data
- /data/spark/conf/worker2:/opt/bitnami/spark/conf
- /data/spark/logs/worker2:/opt/bitnami/spark/logs
restart: always
depends_on:
- spark-master
networks:
- spark_net
deploy:
resources:
limits:
memory: 4G
reservations:
memory: 2G
# Prometheus监控服务
prometheus:
image: prom/prometheus:v2.47.0
container_name: prometheus
volumes:
- /data/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
ports:
- "9090:9090"
restart: always
networks:
- spark_net
# Grafana监控面板
grafana:
image: grafana/grafana:10.1.5
container_name: grafana
depends_on:
- prometheus
ports:
- "3000:3000"
volumes:
- /data/grafana/data:/var/lib/grafana
restart: always
networks:
- spark_net
注意:kafka 网络名称可通过命令查询,命令如下:
# 列出所有网络
docker network ls
效果图如下:
补充说明:
1. Docker Compose 网络命名的机制。Docker Compose 默认给创建的网络加上项目名称作为前缀。项目名称通常是包含 docker-compose.yml 文件的目录名称。当前目录名称是 docker,所以网络名称变成了 docker_kafka_net。
2. 使用代理容器连接ZooKeeper解决Spark与Kafka网络共存的问题。创建一个专门的代理容器,它连接到两个网络并中继ZooKeeper通信。
4. 启动服务
使用自定义名称的 Docker Compose 文件启动服务(笔者Docker版本 26.1.4),命令如下:
docker compose -f spark-docker-compose.yml up -d
效果图如下:
可视化界面效果图依次如下:
注:Grafana 默认登录凭据: admin/admin
5. 备份与维护(可选)
5.1. 创建备份脚本
cat > ~/bin/spark-backup.sh << 'EOF'
#!/bin/bash
# 备份配置和数据
BACKUP_DIR="/data/backup/spark-$(date +%Y%m%d-%H%M%S)"
mkdir -p $BACKUP_DIR
# 备份配置文件
cp -r /data/spark/conf $BACKUP_DIR/
cp -r /data/prometheus $BACKUP_DIR/
cp ~/dev/docker/spark-docker-compose.yml $BACKUP_DIR/
# 备份数据目录
tar -czf $BACKUP_DIR/spark-data-backup.tar.gz /data/spark/data
tar -czf $BACKUP_DIR/spark-logs-backup.tar.gz /data/spark/logs
tar -czf $BACKUP_DIR/grafana-backup.tar.gz /data/grafana/data
echo "Backup completed: $BACKUP_DIR"
EOF
chmod +x ~/bin/spark-backup.sh
5.2. 创建更新脚本
cat > ~/bin/spark-update.sh << 'EOF'
#!/bin/bash
SPARK_COMPOSE="docker compose -f /home/app/dev/docker/spark-docker-compose.yml"
# 拉取最新镜像
"$SPARK_COMPOSE" pull
# 无停机更新Worker节点
"$SPARK_COMPOSE" up -d --no-deps --build spark-worker-1
"$SPARK_COMPOSE" up -d --no-deps --build spark-worker-2
# 等待Worker节点启动
sleep 30
# 更新Master节点
"$SPARK_COMPOSE" up -d --no-deps --build spark-master
echo "Update completed"
EOF
chmod +x ~/bin/spark-update.sh
5.3. 设置定期备份
# 编辑crontab
crontab -e
# 添加以下行,每天凌晨2点执行备份
0 2 * * * /home/app/bin/spark-backup.sh
6. 监控和报警设置
6.1. 初始化Grafana
添加 Prometheus 数据源,操作效果图如下:
6.2. 导入Spark监控仪表盘
1. 在Grafana中,选择"创建" > "导入,操作效果图如下:
2. 输入仪表盘ID: 7890(Spark Metrics仪表盘),操作效果图如下:
3. 选择之前创建的Prometheus数据源,操作效果图如下:
4. 点击 “import” 后的效果图如下: