前言
问题描述
在编写zookeeper群起脚本时,想要基于ssh命令来启动集群中所有zookeeper服务器节点。但是在使用ssh远程执行远端脚本时,控制台输出显示远端脚本已经正常运行结束,远端zookeeper进程实际上却未能运行。使用的ssh命令如下:
[ tomandersen@hadoop101 bin] $ ssh hadoop102 "$ZOOKEEPER_HOME /bin/zkServer.sh start"
ZooKeeper JMX enabled by default
Using config: /opt/module/zookeeper-3.4.14/bin/.. /conf/zoo.cfg
Starting zookeeper .. . STARTED
解决过程
1)查看远端主机的运行日志zookeeper.out:
zookeeper.out默认输出在启动zkServer.sh脚本的当前路径下,查看其中内容,如下所示:
[ tomandersen@hadoop102 runtime] $ cat zookeeper.out
nohup: 无法运行命令"java" : 没有那个文件或目录
发现脚本中无法找到java
命令(猜测可能是环境变量的问题)
2)尝试在脚本zkServer.sh中定位java命令使用位置:
[ tomandersen@hadoop102 bin] $ cat zkServer.sh | grep java -n
20:
39:
但发现其中都是注释,并没有显示调用java命令。然后查看zkServer.sh中的内容,发现此脚本在开头还使用. zkEnv.sh
的方式运行了zkEnv.sh脚本,因此我们再去此脚本中定位java命令
3)尝试在脚本zkEnv.sh中定位java命令使用位置:
[ tomandersen@hadoop102 bin] $ cat zkEnv.sh | grep java -n
49:if [ -f "$ZOOCFGDIR /java.env" ]
51: . "$ZOOCFGDIR /java.env"
69: JAVA= "$JAVA_HOME /bin/java"
71: JAVA= java
68 if [ "$JAVA_HOME " != "" ] ; then
69 JAVA= "$JAVA_HOME /bin/java"
70 else
71 JAVA= java
72 fi
结果发现此段程序并没有什么异常,于是尝试验证之前的推测,可能是环境变量导致此次错误
4)查看远端环境变量主机设置:
[ tomandersen@hadoop102 bin] $ echo $JAVA_HOME
/opt/module/jdk1.8.0_221
[ tomandersen@hadoop102 bin] $ which java
/opt/module/jdk1.8.0_221/bin/java
[ tomandersen@hadoop102 bin] $ echo $PATH | grep $JAVA_HOME
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/opt/module/jdk1.8.0_221/bin:/opt/module/hadoop-2.7.7/bin:/opt/module/hadoop-2.7.7/sbin:/opt/module/zookeeper-3.4.14/bin:/home/TomAndersen/.local/bin:/home/TomAndersen/bin
结果发现环境变量配置正常,然后尝试使用ssh命令远程调用Java环境变量,查看是否能正常输出:
[ tomandersen@hadoop101 bin] $ ssh hadoop102 "echo \$JAVA_HOME "
[ tomandersen@hadoop101 bin] $ ssh hadoop102 "which java"
which: no java in ( /usr/local/bin:/usr/bin)
[ tomandersen@hadoop101 bin] $ ssh hadoop102 "echo \$PATH "
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin
注意 :在远端执行命令读取远端变量时,需要将美元符号转义即\$
显然使用ssh远程直接执行Shell命令既不能读取之前设置的环境变量(如JAVA_HOME和PATH),也无法使用java命令,但是远端主机各个环境变量设置正常 于是猜测是不是使用ssh工具执行远端脚本时,没有加载环境变量。
5)验证猜想
接下来在远端主机上创建测试脚本test.sh
,用于测试是否使用ssh工具远端执行此脚本时无法读取环境变量,其中测试脚本内容如下:
1 echo $PATH
2 echo $JAVA_HOME
3 which java
[ tomandersen@hadoop101 ~] $ ssh hadoop102 "~/test.sh"
/usr/local/bin:/usr/bin
which: no java in ( /usr/local/bin:/usr/bin)
至此我们可以得出结果,使用ssh执行远端脚本时,在脚本内是没有加载环境变量的,即没有加载/etc/profile
文件,因此我们修改原始ssh远程执行命令,在前面加上source /etc/profile
,即主动加载系统环境变量,然后发现脚本能够正常调用环境变量:
[ tomandersen@hadoop101 ~] $ ssh hadoop102 "source /etc/profile;~/test.sh"
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/opt/module/jdk1.8.0_221/bin:/opt/module/hadoop-2.7.7/bin:/opt/module/hadoop-2.7.7/sbin:/opt/module/zookeeper-3.4.14/bin
/opt/module/jdk1.8.0_221
/opt/module/jdk1.8.0_221/bin/java
解决方案
① 在ssh远程执行的正式命令之前加上source /etc/profile;
,即主动加载环境变量
② 同理在远程主机对应用户的~/.bashrc
文件末尾加入source /etc/profile
,也是同样的效果(但不建议)
③ 在使用ssh时,使用重定向输入的方式执行命令,会自动加载环境变量,参考
参考资料
ssh连接远程主机执行脚本的环境变量问题
End~