我正在尝试处理容器启动的docker-compose顺序中的已知问题,所以我以一个简单的解决方案结束,有一个脚本来检查环境是否已准备好启动命令。
这个想法是,为容器定义了一些环境变量:
在该示例中,我在启动应用程序之前等待elasticSearch响应,这取决于要启动的ES数据。
以下脚本将是docker容器上的ENTRYPOINT。
导出的ENV vars
WAIT_COMMAND="$(curl --write-out %{http_code} --silent --output /dev/null http://elastic:9200/_cat/health?h=st) == 200"
LOOPS=3
START_CMD="python my_script_depending_on_elastic.py"
SLEEP=2
如果上述ENV vars可用,脚本应该等到ES请求返回代码 200
#!/bin/bash
is_ready() {
eval $WAIT_COMMAND
}
# wait until is ready
i=0
while ! is_ready; do
i=`expr $i + 1`
if [ $i -ge $LOOPS ]; then
echo "$(date) - still not ready, giving up"
exit 1
fi
echo "$(date) - waiting to be ready"
sleep $SLEEP
done
#start the script
exec $START_CMD
问题是代码在 is_ready 函数行中不起作用,它不返回布尔值但尝试执行 200 作为命令
# ./wait_elastic.sh
./wait_elastic.sh: line 9: 200: command not found
Fri Jul 3 18:26:43 UTC 2015 - waiting to be ready
./wait_elastic.sh: line 9: 200: command not found
Fri Jul 3 18:26:45 UTC 2015 - waiting to be ready
./wait_elastic.sh: line 9: 200: command not found
Fri Jul 3 18:26:47 UTC 2015 - still not ready, giving up
如何进行测试以检查卷曲响应是否正常?
如何将逻辑测试命令指定为:
WAIT_COMMAND="$(curl --write-out %{http_code} --silent --output /dev/null http://elastic:9200/_cat/health?h=st) == 200"
以及如何评估它:
is_ready() {
eval $WAIT_COMMAND
}
答案 0 :(得分:3)
这个答案是不好的做法。请考虑一种不涉及eval
的方法。
wait_command='[ $(curl --write-out %{http_code} --silent --output /dev/null http://elastic:9200/_cat/health?h=st) = 200 ]'
is_ready() {
eval "$wait_command"
}
与原始代码的区别:
test
命令同义词[
(先前版本不是合法的bash比较语法)。==
(在POSIX [
中不是有效的运算符)切换到=
(POSIX允许)。见the standards document for the test
command。curl
在eval
被调用之前不会运行。eval
的内容,以防止在代码到达eval
命令之前发生字符串拆分和glob扩展。在docker-compose
的上下文中实现此功能可能如下所示:
app:
command: docker/wait
environment:
- wait_command=[ $(curl --write-out %{http_code} --silent --output /dev/null http://elastic:9200/_cat/health?h=st) = 200 ]
- wait_loops=10
- wait_sleep=30
...使用类似以下内容的脚本:
#!/bin/bash
s_ready() { eval "$wait_command"; }
# wait until is ready
i=0
while ! is_ready; do
if (( ++i >= wait_loops )); then
echo "$(date) - still not ready, giving up"
exit 1
fi
echo "$(date) - waiting to be ready"
sleep $wait_sleep
done
答案 1 :(得分:2)
如果要存储代码,请不要使用标量变量 - 使用函数;这就是他们的目的。
如果要通过环境变量传递代码,则答案是导出的函数:
wait_command() {
[ $(curl --write-out %{http_code} --silent --output /dev/null http://elastic:9200/_cat/health?h=st) = 200 ]
}
export -f wait_command
...创建一个如下所示的环境变量(在现代的,官方后的shellshock-patch bash中):
BASH_FUNC_wait_command%%=() { [ $(curl --write-out %{http_code} --silent --output /dev/null http://elastic:9200/_cat/health?h=st) = 200 ]
...你可以这样运行,没有eval
:
wait_command
再次重申,更清楚一点:导出的函数只是具有特殊名称和值的环境变量。如果您创建一个名称以BASH_FUNC_
开头且以%%
结尾且其值以() {
开头的环境变量,则您刚刚创建了一个导出函数,该函数可在shell中运行在环境中开始。
因此,在.yml
文件中,您可以使用以下内容:
environment: {BASH_FUNC_wait_command%%: '() { [ $(curl --write-out %{http_code} --silent
--output /dev/null http://elastic:9200/_cat/health?h=st) = 200 ]'}
答案 2 :(得分:1)
不要使用eval
。相反,只需获取状态
status=$(curl --write-out %{http_code} --silent --output /dev/null http://elastic:9200/_cat/health?h=st)"
然后直接测试。
is_ready () {
[[ $status -eq 200 ]]
}