背景
使用容器部署azkban。azkaban的任务会使用系统变量EMR_CLUSTER_ID作为参数,来选择emr集群执行命令。
最初的设计EMR是固定的,在启动容器时配置系统变量就好了。偶尔重启EMR,需要修改系统变量重启azkaban executor。
后面为了节省成本,EMR集群改成了动态开启和关闭,那就需要azkaban能动态修改job执行时系统变量。
方案
尝试修改容器系统变量
容器在启动后,会将首个用户进程 Pid设置为1。而且该进程退出后容器就退出了。所以容器不像真实的linux一样,可以配置/etc/profile然后重启来修改环境变量。
最开始想到的是注册一个信号接收的handler,通过向进程发送信号来修改系统变量。
以下是测试脚本
test.sh
#!/bin/bash
echo $$ > /task.pid # Save the pid
function do_stuff {
echo "I am doing stuff"
export env_test=$(cat env.log)
}
trap do_stuff SIGTERM
export env_test=111
while `true`
do
echo asdf${env_test}
python task.py
sleep 5
done
task.py
import os
import time
while True:
time.sleep(1)
print(os.environ.get('env_test'))
这样通过发送TERM信号来修改环境变量就可行了。
pid=`cat /task.pid` # Read the pid
kill -s TERM $pid
问题
实际为了将azkaban executor进程放在pid1,以及log可以被容器log收集,没有将进程放在后台执行,而是使用exec在前台执行。就导致写的handle失效,azkaban的handle会替换它。
即使放在后台执行,父进程的系统变量修改后,子进程没有重启也更新不了。
修改azkaban的配置文件
读了azkaban源码,在azkaban启动job时,会将plugins/jobtypes/common.properties文件中evn.
开头的变量设置为子进程的系统变量。在执行任务的时候会打印出来。
Environment variables: {JOB_OUTPUT_PROP_FILE=/opt/azkaban-exec-server-0.1.0-SNAPSHOT/executions/2/jobb_output_8275396890888167415_tmp, JOB_PROP_FILE=/opt/azkaban-exec-server-0.1.0-SNAPSHOT/executions/2/jobb_props_918335858548553107_tmp, KRB5CCNAME=/tmp/krb5cc__test_project__basic1__jobb__2__root, EMR_CLUSTER_ID=null, JOB_NAME=jobb}
修改完common.properties后,需要重新加载一下JobTypePlugins,使common.properties生效。
cluster_id="$(aws emr list-clusters --cluster-states WAITING --query "Clusters[?Name == '\''${cluster_name}'\''].Id|[0]" | sed '\''s/\"//g'\'')"
echo env.EMR_CLUSTER_ID="${cluster_id}" > plugins/jobtypes/common.properties
curl -G "localhost:12321/executor?action=reloadJobTypePlugins" && echo
就可以修改job的系统变量。
cluster_id为获取状态为WAITING,名字为${cluster_name}的第一个集群的id。