You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使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。

修复步骤

  1. 单独捕获aws命令的退出码,失败时直接终止并返回错误。
  2. 检查jq的执行结果,确保参数解析失败时终止脚本。
  3. 用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 09:48:18