通过环境传递 bash 代码(对于 docker-compose)
Passing bash code through the environment (for docker-compose)
我正在尝试处理 docker-compose 容器启动顺序中的一个已知问题,所以我以一个简单的解决方案结束,有一个脚本来检查环境是否准备好启动命令。
就是这个想法,为容器定义了一些环境变量:
- WAIT_COMMAND 应该是在 sh 脚本中定义逻辑测试的字符串,它必须 return 一个布尔值
- START_CMD 根据 WAIT_COOMAND 结果,带有 运行 命令的字符串,否则重试,直到达到 LOOPS。
- LOOPS尝试多少次
- 睡眠两次尝试之间要睡多久
在那个例子中,我在启动我的应用程序之前等待 elasticSearch 响应,这取决于 ES 数据来启动。
以下脚本将是我在 docker 容器上的入口点。
导出的 ENV 变量
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 变量,脚本应该等到 ES 请求 return 代码 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 函数行中不起作用,它不是 return 布尔值,而是尝试执行 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
如何测试curl响应是否正常?
如何将逻辑测试命令指定为:
WAIT_COMMAND="$(curl --write-out %{http_code} --silent --output /dev/null http://elastic:9200/_cat/health?h=st) == 200"
以及如何评价它:
is_ready() {
eval $WAIT_COMMAND
}
?
不要使用 eval
。相反,只需获取状态
status=$(curl --write-out %{http_code} --silent --output /dev/null http://elastic:9200/_cat/health?h=st)"
那就直接测试吧
is_ready () {
[[ $status -eq 200 ]]
}
如果要存储代码,请不要使用标量变量——使用函数;这就是他们的目的。
如果要通过环境变量传递代码,那么答案是导出函数:
wait_command() {
[ $(curl --write-out %{http_code} --silent --output /dev/null http://elastic:9200/_cat/health?h=st) = 200 ]
}
export -f wait_command
...创建一个如下所示的环境变量(在现代,post-official-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 ]'}
这个答案是不好的做法。请考虑一种不涉及 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
我正在尝试处理 docker-compose 容器启动顺序中的一个已知问题,所以我以一个简单的解决方案结束,有一个脚本来检查环境是否准备好启动命令。
就是这个想法,为容器定义了一些环境变量:
- WAIT_COMMAND 应该是在 sh 脚本中定义逻辑测试的字符串,它必须 return 一个布尔值
- START_CMD 根据 WAIT_COOMAND 结果,带有 运行 命令的字符串,否则重试,直到达到 LOOPS。
- LOOPS尝试多少次
- 睡眠两次尝试之间要睡多久
在那个例子中,我在启动我的应用程序之前等待 elasticSearch 响应,这取决于 ES 数据来启动。
以下脚本将是我在 docker 容器上的入口点。
导出的 ENV 变量
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 变量,脚本应该等到 ES 请求 return 代码 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 函数行中不起作用,它不是 return 布尔值,而是尝试执行 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
如何测试curl响应是否正常?
如何将逻辑测试命令指定为:
WAIT_COMMAND="$(curl --write-out %{http_code} --silent --output /dev/null http://elastic:9200/_cat/health?h=st) == 200"
以及如何评价它:
is_ready() {
eval $WAIT_COMMAND
}
?
不要使用 eval
。相反,只需获取状态
status=$(curl --write-out %{http_code} --silent --output /dev/null http://elastic:9200/_cat/health?h=st)"
那就直接测试吧
is_ready () {
[[ $status -eq 200 ]]
}
如果要存储代码,请不要使用标量变量——使用函数;这就是他们的目的。
如果要通过环境变量传递代码,那么答案是导出函数:
wait_command() {
[ $(curl --write-out %{http_code} --silent --output /dev/null http://elastic:9200/_cat/health?h=st) = 200 ]
}
export -f wait_command
...创建一个如下所示的环境变量(在现代,post-official-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 ]'}
这个答案是不好的做法。请考虑一种不涉及 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 thetest
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