如何使Docker在docker-entrypoint.sh执行失败时终止运行?
问题:Docker入口脚本加载AWS SSM参数失败仍继续执行CMD
我尝试在docker-entrypoint.sh中加载AWS SSM参数,测试失败场景时发现,即使加载失败,脚本仍会继续执行CMD。我已经尝试过set -e和set -eo pipefail,但当aws调用失败时,脚本仍会继续启动服务器。请问如何让Docker在docker-entrypoint.sh中出现任何执行失败时停止运行?
补充说明:我怀疑原因是命令本身返回执行成功,但我未处理响应中的错误。
原脚本代码:
#!/bin/bash set -eo pipefail ssm_available() { if [ -z ${SSM_BASE_PATH+x} ]; then return 1 fi return 0 } get_ssm_params() { aws ssm get-parameters-by-path --no-paginate --path ${SSM_BASE_PATH} --with-decryption --query Parameters | \ jq -r 'map("\(.Name | sub("'${SSM_BASE_PATH}'";""))=\(.Value)") | join("\n")' } exec_with_ssm_parameters() { for parameter in `get_ssm_params`; do echo "Info: Exporting parameter ${parameter%%=*}" export ${parameter} done exec "$@" } main() { if ssm_available; then echo "Info: Loading SSM Parameters" >&2 exec_with_ssm_parameters "$@" fi echo "Info: Starting ..." >&2 exec "$@" } main "$@"
核心问题分析
你遇到的问题根源在于:
- 当
aws ssm命令执行失败时,管道后的jq可能仍返回0(成功),导致整个管道的退出码被jq覆盖,set -eo pipefail虽能捕获管道中第一个失败命令,但如果aws的错误输出未被jq处理,或jq在空输入下正常执行,脚本会误以为步骤成功。 get_ssm_params函数未显式处理aws命令的失败,即使aws出错,函数本身可能仍返回0。
修复步骤
- 单独捕获
aws命令的退出码,失败时直接终止并返回错误。 - 检查
jq的执行结果,确保参数解析失败时终止脚本。 - 用
while read替代for循环遍历参数,避免空输出或特殊字符导致的异常。
修复后的脚本
#!/bin/bash set -eo pipefail ssm_available() { if [ -z "${SSM_BASE_PATH+x}" ]; then return 1 fi return 0 } get_ssm_params() { # 单独执行aws命令,捕获输出和退出码 local aws_output aws_output=$(aws ssm get-parameters-by-path --no-paginate --path "${SSM_BASE_PATH}" --with-decryption --query Parameters) local aws_exit_code=$? # aws命令失败则直接返回错误 if [ $aws_exit_code -ne 0 ]; then echo "Error: Failed to fetch SSM parameters" >&2 return $aws_exit_code fi # 解析输出并检查jq执行结果 echo "$aws_output" | jq -r 'map("\(.Name | sub("'"${SSM_BASE_PATH}"'";""))=\(.Value)") | join("\n")' local jq_exit_code=$? if [ $jq_exit_code -ne 0 ]; then echo "Error: Failed to parse SSM parameters with jq" >&2 return $jq_exit_code fi } exec_with_ssm_parameters() { # 用while read处理参数,避免特殊字符问题 get_ssm_params | while read -r parameter; do [ -z "$parameter" ] && continue echo "Info: Exporting parameter ${parameter%%=*}" >&2 export "$parameter" done # 检查get_ssm_params的退出码 local params_exit_code=${PIPESTATUS[0]} if [ $params_exit_code -ne 0 ]; then exit $params_exit_code fi exec "$@" } main() { if ssm_available; then echo "Info: Loading SSM Parameters" >&2 exec_with_ssm_parameters "$@" fi echo "Info: Starting ..." >&2 exec "$@" } main "$@"
额外说明
PIPESTATUS数组用于获取管道中每个命令的退出码,确保get_ssm_params的执行失败能被捕获。while read能更好处理参数值含空格或特殊字符的场景,同时避免空输出时循环不执行但脚本继续的问题。
内容的提问来源于stack exchange,提问作者PGT
相关产品推荐
相关产品推荐

