EMR Core 节点 Flink Client 部署方案:从 Master 打包到 Bootstrap Action 自动分发的完整技术路径
问题背景
Amazon EMR 上跑 Apache Flink 时,Flink Client 工具链(flink、flink-sql-client、yarn-session.sh)默认只装在 Master 节点。Core 节点的职责是运行 YARN NodeManager 和 HDFS DataNode,负责计算和存储。
随着企业数据平台的演进,越来越多团队在 Core 节点上部署 DolphinScheduler、Airflow 等工作流调度系统的 Worker 组件。这些 Worker 需要直接调用 Flink 命令提交作业,但 Core 节点上没有 Flink Client。
SSH 回 Master 执行是一种绕路方案,但增加了架构复杂度、维护成本和故障点。本文介绍一种通过 Bootstrap Action 自动分发的方案,实现一次打包、多次复用。
技术方案
架构概览
Master 节点打包 → S3 存储 → Bootstrap Action → Core/Task 节点安装
环境:EMR 7.10.0 / Flink 1.20.0-amzn-4(AWS 定制构建,与 EMR 发行版绑定)。
打包流程
连接 Master 节点后执行:
# 验证环境
sudo -u hadoop /usr/lib/flink/bin/yarn-session.sh -d -jm 1024 -tm 2048
yarn application -list
# 打包
tar -czf flink-client-1.20.0-amzn-4.tar.gz -C /usr/lib flink
tar -czf flink-conf.tar.gz -C /etc flink
# 上传 S3
aws s3 cp flink-client-1.20.0-amzn-4.tar.gz s3://<bucket>/emr/bootstrap/
aws s3 cp flink-conf.tar.gz s3://<bucket>/emr/bootstrap/
注意:必须用 hadoop 用户或完整路径,否则 $bin 路径解析报错。EMR 中 Flink 版本号 1.20.0-amzn-4 是 AWS 基于开源版本的定制构建。
Bootstrap Action 脚本
#!/bin/bash
set -e
S3_PREFIX="s3://<bucket>/emr/bootstrap"
IS_MASTER=$(cat /emr/instance-controller/lib/info/instance.json | jq -r '.isMaster')
if [ "$IS_MASTER" = "false" ]; then
# 下载解压
aws s3 cp "${S3_PREFIX}/flink-client-1.20.0-amzn-4.tar.gz" /tmp/
sudo tar -xzf /tmp/flink-client-1.20.0-amzn-4.tar.gz -C /usr/lib/
aws s3 cp "${S3_PREFIX}/flink-conf.tar.gz" /tmp/
sudo tar -xzf /tmp/flink-conf.tar.gz -C /etc/
# 修复 broken symlink
if [ -L "/etc/flink/conf" ] && [ ! -e "/etc/flink/conf" ]; then
sudo rm -f /etc/flink/conf
[ -d "/etc/flink/conf.dist" ] && sudo cp -r /etc/flink/conf.dist /etc/flink/conf || sudo mkdir -p /etc/flink/conf
fi
[ -L "/usr/lib/flink/conf" ] && [ ! -e "/usr/lib/flink/conf" ] && sudo rm -f /usr/lib/flink/conf && sudo ln -sf /etc/flink/conf /usr/lib/flink/conf
# wrapper scripts(避免 symlink 的 $bin 路径问题)
sudo tee /usr/bin/flink > /dev/null << 'W'
#!/bin/bash
exec /usr/lib/flink/bin/flink "$@"
W
sudo chmod +x /usr/bin/flink
sudo tee /usr/bin/flink-sql-client > /dev/null << 'W'
#!/bin/bash
exec /usr/lib/flink/bin/sql-client.sh "$@"
W
sudo chmod +x /usr/bin/flink-sql-client
sudo tee /usr/bin/yarn-session.sh > /dev/null << 'W'
#!/bin/bash
exec /usr/lib/flink/bin/yarn-session.sh "$@"
W
sudo chmod +x /usr/bin/yarn-session.sh
cat << 'EOF' | sudo tee /etc/profile.d/flink.sh
export FLINK_HOME=/usr/lib/flink
export PATH=$FLINK_HOME/bin:$PATH
EOF
rm -f /tmp/flink-*.tar.gz
fi
关键细节:为什么用 wrapper 而不是 symlink
Flink 的 bin 脚本内部用 . "$bin"/config.sh 做相对路径引用。symlink 会把 $bin 解析为 symlink 所在的 /usr/bin/ 而不是实际的 /usr/lib/flink/bin/,导致 config.sh 加载失败。
wrapper scripts 用 exec 直接调用原始路径的脚本,$bin 自然解析为正确路径。
关于 broken symlink
EMR Master 节点上 /etc/flink/conf 是指向 /etc/alternatives/flink-conf 的 symlink,但 Core 节点上这个 alternatives 目标不存在。从 Master 打包后解压到 Core,symlink 就是 broken 的。脚本会检测并用 conf.dist 目录替代。
创建集群
aws emr create-cluster \
--release-label emr-7.10.0 \
--applications Name=Flink Name=Hadoop \
--bootstrap-actions Path=s3://<bucket>/emr/bootstrap/install_flink_client.sh,Name="Install Flink Client on Core" \
--instance-type m5.xlarge --instance-count 3 \
--service-role EMR_DefaultRole \
--ec2-attributes InstanceProfile=EMR_EC2_DefaultRole \
--name "Flink-Cluster"
验证
从 Master SSH 到 Core 节点,执行 flink --version、flink-sql-client --help。排查看 /var/log/bootstrap-actions/1/stdout。
方案评估
| 维度 | 说明 |
|---|---|
| 复用性 | 同版本 EMR 直接复用,EMR 升级时重新打包 |
| 执行时机 | 集群启动时自动,无人工干预 |
| 范围 | 仅 Core/Task 节点 |
| 耗时 | S3 下载 + 解压约 30 秒 |
| 依赖 | jq(EMR 默认自带) |
生产建议:上线前通过 Bootstrap 日志验证安装结果,避免调度系统因环境缺失静默失败。
本文参考亚马逊云科技官方博客:在 AWS EMR Core 节点部署 Flink Client 的实战指南

浙公网安备 33010602011771号