EMR Core 节点部署 Flink Client 实战:Bootstrap Action 一次打包多次复用,解决调度系统提交任务的痛点

在 EMR 上跑 Flink 的同学应该都碰到过一个问题:Flink Client 只装在 Master 节点上,Core 节点默认没有。

这在大多数场景下没问题------反正任务从 Master 提交就行了。但如果你在 Core 节点上跑 DolphinScheduler、Airflow 这类调度系统的 Worker 组件,问题就来了:Worker 想直接调用 flinkflink-sql-clientyarn-session.sh 提交任务,发现命令不存在。

只能绕路 SSH 到 Master 节点执行,架构复杂度和维护成本都上去了。

这篇文章记录我怎么用 Bootstrap Action 解决这个问题:从 Master 打包 Flink 二进制 → 上传 S3 → 新集群启动时自动分发到 Core/Task 节点。整个方案遵循"一次打包、多次复用"的原则,只要 EMR 版本不变,打包产物可以反复用。

环境说明

  • Amazon EMR 7.10.0
  • Flink 1.20.0-amzn-4(AWS 基于开源版本的定制构建,包含安全补丁和服务集成优化)
  • EMR 中的 Flink 版本与发行版绑定,选 emr-7.10.0 自动获得 Flink 1.20.0-amzn-4

第一步:创建打包用集群

先起一个临时集群用来打包 Flink 二进制文件:

bash 复制代码
aws emr create-cluster \
  --release-label emr-7.10.0 \
  --applications Name=Flink Name=Hadoop \
  --instance-type m5.xlarge \
  --instance-count 3 \
  --service-role EMR_DefaultRole \
  --ec2-attributes InstanceProfile=EMR_EC2_DefaultRole \
  --name "Flink-Source-Cluster"

等集群进入 WAITING 状态(约 5-10 分钟),记下 ClusterId

SSH 或 SSM 连接到 Master 节点:

bash 复制代码
# 验证 Flink 版本
flink --version

# 验证 Flink 在 YARN 上能跑
sudo -u hadoop /usr/lib/flink/bin/yarn-session.sh -d -jm 1024 -tm 2048
yarn application -list

踩坑提醒:在 Master 节点上必须用完整路径 /usr/lib/flink/bin/yarn-session.sh,否则会因 $bin 路径解析问题报错。同时需要用 hadoop 用户才有 HDFS 写权限。

打包并上传 S3:

bash 复制代码
# 打包二进制文件(bin、lib、opt、plugins、examples)
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://<your-bucket>/emr/bootstrap/
aws s3 cp flink-conf.tar.gz s3://<your-bucket>/emr/bootstrap/

这两个文件就是以后反复用的产物,只要 EMR 版本不变就不用重新打包。

第三步:编写 Bootstrap Action 脚本

这是核心部分。脚本会检测节点类型,只在 Core/Task 节点上执行安装:

bash 复制代码
#!/bin/bash
# install_flink_client.sh
set -e

S3_BUCKET="<your-bucket>"
FLINK_TARBALL="flink-client-1.20.0-amzn-4.tar.gz"
FLINK_CONF_TARBALL="flink-conf.tar.gz"
S3_PREFIX="s3://${S3_BUCKET}/emr/bootstrap"

IS_MASTER=$(cat /emr/instance-controller/lib/info/instance.json | jq -r '.isMaster')

if [ "$IS_MASTER" = "false" ]; then
    echo "Core/Task node detected, installing Flink client..."

    # 1. 下载并解压 Flink 二进制
    aws s3 cp "${S3_PREFIX}/${FLINK_TARBALL}" /tmp/
    sudo tar -xzf "/tmp/${FLINK_TARBALL}" -C /usr/lib/

    # 2. 下载并解压配置文件
    aws s3 cp "${S3_PREFIX}/${FLINK_CONF_TARBALL}" /tmp/
    sudo tar -xzf "/tmp/${FLINK_CONF_TARBALL}" -C /etc/

    # 3. 修复 /etc/flink/conf 的 broken symlink
    if [ -L "/etc/flink/conf" ] && [ ! -e "/etc/flink/conf" ]; then
        echo "Fixing broken symlink /etc/flink/conf..."
        sudo rm -f /etc/flink/conf
        if [ -d "/etc/flink/conf.dist" ]; then
            sudo cp -r /etc/flink/conf.dist /etc/flink/conf
        else
            sudo mkdir -p /etc/flink/conf
        fi
    fi

    # 4. 修复 /usr/lib/flink/conf 的 broken symlink
    if [ -L "/usr/lib/flink/conf" ] && [ ! -e "/usr/lib/flink/conf" ]; then
        sudo rm -f /usr/lib/flink/conf
        sudo ln -sf /etc/flink/conf /usr/lib/flink/conf
    fi

    # 5. 创建 wrapper scripts(不用 symlink!)
    sudo tee /usr/bin/flink > /dev/null << 'WRAPPER'
#!/bin/bash
exec /usr/lib/flink/bin/flink "$@"
WRAPPER
    sudo chmod +x /usr/bin/flink

    sudo tee /usr/bin/flink-sql-client > /dev/null << 'WRAPPER'
#!/bin/bash
exec /usr/lib/flink/bin/sql-client.sh "$@"
WRAPPER
    sudo chmod +x /usr/bin/flink-sql-client

    sudo tee /usr/bin/yarn-session.sh > /dev/null << 'WRAPPER'
#!/bin/bash
exec /usr/lib/flink/bin/yarn-session.sh "$@"
WRAPPER
    sudo chmod +x /usr/bin/yarn-session.sh

    # 6. 环境变量
    cat << 'ENVEOF' | sudo tee /etc/profile.d/flink.sh
export FLINK_HOME=/usr/lib/flink
export PATH=$FLINK_HOME/bin:$PATH
ENVEOF

    # 7. 清理
    rm -f "/tmp/${FLINK_TARBALL}" "/tmp/${FLINK_CONF_TARBALL}"
    echo "Flink client installation completed."
else
    echo "Master node detected, skipping."
fi

上传脚本:

bash 复制代码
aws s3 cp install_flink_client.sh s3://<your-bucket>/emr/bootstrap/

这是个踩过的坑。Flink 的 bin 目录下的脚本内部会用 . "$bin"/config.sh 这样的相对路径引用。如果用 symlink(ln -s /usr/lib/flink/bin/flink /usr/bin/flink),$bin 会解析为 /usr/bin/ 而不是 /usr/lib/flink/bin/,导致 config.sh 找不到。

用 wrapper scripts 的 exec 命令则不会有这个问题------它直接调用原始路径的脚本,$bin 自然解析为 /usr/lib/flink/bin/

EMR 在 Master 节点上会创建 /etc/flink/conf → /etc/alternatives/flink-conf 这个 symlink,但 Core 节点上 /etc/alternatives/flink-conf 不存在。打包配置文件后解压到 Core,这个 symlink 就是 broken 的。

脚本的处理逻辑:如果 /etc/flink/conf.dist 存在就复制一份,否则创建空目录。

第四步:创建正式集群

bash 复制代码
aws emr create-cluster \
  --release-label emr-7.10.0 \
  --applications Name=Flink Name=Hadoop \
  --bootstrap-actions Path=s3://<your-bucket>/emr/bootstrap/install_flink_client.sh,Name="Install Flink Client on Core Nodes" \
  --instance-type m5.xlarge \
  --instance-count 3 \
  --service-role EMR_DefaultRole \
  --ec2-attributes InstanceProfile=EMR_EC2_DefaultRole \
  --name "Flink-Production-Cluster"

第五步:验证

Core 节点没有公网 IP,需要通过 Master 跳转。SSH 到 Master 后跳到任意 Core 节点:

bash 复制代码
flink --version
flink-sql-client --help
yarn-session.sh --help

排查问题看 Bootstrap Action 日志:

bash 复制代码
sudo cat /var/log/bootstrap-actions/1/stdout
sudo cat /var/log/bootstrap-actions/1/stderr

方案总结

维度 说明
适用版本 EMR 7.10.0 + Flink 1.20.0-amzn-4
复用性 同版本 EMR 可直接复用 S3 上的打包文件
执行时机 集群启动时自动执行,无需手动干预
影响范围 仅 Core/Task 节点,Master 节点跳过
维护成本 EMR 升级时需重新打包

整个方案的核心思路:把 Master 节点上已有的东西打包搬运到 Core 节点,而不是从头装一遍。简单直接,没有魔法。

生产环境建议:上线前通过 Bootstrap Action 日志和节点级命令验证确认安装结果,避免调度系统在生产中因环境缺失而静默失败。

本文参考亚马逊云科技官方博客:在 AWS EMR Core 节点部署 Flink Client 的实战指南

相关推荐
前端若水17 小时前
最小化可行智能体(MVP Agent)的设计原则
大数据·人工智能
随身数智备忘录17 小时前
MES安灯管理程序这套方法,专治MES安灯管理程序中的流程空转
大数据·服务器·网络
北京软秦科技有限公司17 小时前
IACheck AI报告审核:汽车内饰缝线歪斜检测报告,签章零遗漏、合规不踩坑
大数据·人工智能·汽车
AC赳赳老秦17 小时前
OpenClaw与思维导图工具联动:自动生成工作规划脑图、拆解任务节点,适配职场管理
java·大数据·服务器·数据库·python·php·openclaw
阳艳讲ai18 小时前
中小企业AI技术方案选型评估框架:四类架构与评估指标分析
大数据·人工智能·企业ai培训·ai获客·九尾狐ai·ai应用工具
易观Analysys18 小时前
中美Agent生态的路径差异——《重构与崛起——OpenClaw时代的中国Agent产业生态报告》解读三
大数据·人工智能
zhojiew18 小时前
AWS云上使用Redshift Test Drive进行负载重放测试的实践
大数据·redshift
移动云开发者联盟19 小时前
存智赋能 共筑AI存储新生态,移动云聚力技术创新夯实AI数据基石
大数据·人工智能
TDengine (老段)19 小时前
TDengine 数据库创建与参数详解
大数据·数据库·物联网·时序数据库·iot·tdengine·涛思数据
面向Google编程19 小时前
从零学习Kafka:调优
大数据·kafka