0

我正在创建一个 Nginx docker 映像,我将在 AWS 的 ECS/Fargate 中将其用作反向代理组件。我使用官方 Nginx 镜像作为基础镜像(1.17.5)。

当容器启动时,我尝试从 ENTRYPOINT 运行 bash 脚本以访问 AWS Parameter Store 并检索证书信息。这工作正常,但是当我尝试添加一个参数以传递给 bash 脚本时(例如 ENTRYPOINT ["installcerts.sh", "AppName"] 它执行脚本但容器终止而没有错误。

我希望容器在参数化批处理脚本之后继续启动 Nginx。

这是我的 Docker 文件:

FROM nginx:1.17.5

# Install AWS CLI/BOTO3, JQ
RUN apt-get update &&  apt-get install -y &&  apt-get install awscli -y && apt-get install jq -y

# Copy Nginx config to etc/nginx
COPY proxy_ssl.conf /etc/nginx/conf.d/

VOLUME ["/etc/nginx/conf/d"]

# Copy entrypoint bash script to install certs from the AWS Parameter Store
COPY installcerts.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/installcerts.sh

#Pull certs from Parameter Store
ENTRYPOINT ["/usr/local/bin/installcerts.sh", "AppName"]

CMD ["nginx", "-g", "daemon off;"]

这是我的“installcerts.sh”脚本,显示了使用从 ENTRYPOINT 传入的参数。

#!/usr/bin/env bash
-e
echo Installing certs...
aws ssm get-parameters --name /Certificate/$1/CRT | jq '.Parameters[0].Value' -r > /etc/nginx/conf.d/app.crt
aws ssm get-parameters --name /Certificate/$1/KEY | jq '.Parameters[0].Value' -r > /etc/nginx/conf.d/app.key
echo Exiting script.
exec "$@"

bash 脚本中的 "exec "$@" 是必需的,但老实说,即使经过数小时的尝试追踪它,我也不完全理解它是如何或为什么起作用的。

短篇小说是:

如果我使用它,容器会执行我希望它执行的操作,但我无法将参数发送到 bash 脚本。

ENTRYPOINT ["/usr/local/bin/installcerts.sh"]

但是如果我使用它,脚本将成功运行 WITH 参数,但容器退出并且 Nginx 没有启动。

ENTRYPOINT ["/usr/local/bin/installcerts.sh", "AppName"]

我究竟做错了什么?

4

1 回答 1

2

当您ENTRYPOINT在图像上设置 an 时,docker 会将该脚本的值CMD(或您在图像名称后的命令行上传递的任何值)传递给该脚本。例如,如果您有:

ENTRYPOINT ["/entrypoint.sh"]
CMD ["/usr/bin/myprogram"]

然后 docker 有效地运行:

/entrypoint.sh /usr/bin/myprogram

也就是说,Docker 本身永远不会运行/usr/bin/myprogram:这完全取决于ENTRYPOINT脚本。这就是它的exec "$@"用途。这是一个 shell 变量,计算结果为:

扩展到位置参数,从一个开始。(bash(1) 手册页,在“特殊参数”部分)

在我们的示例中,这将评估为:

exec /usr/bin/myprogram

...将当前脚本替换为/usr/bin/myprogram. 但是,如果我们要ENTRYPOINT按照您的问题进行设置:

ENTRYPOINT ["/entrypoint.sh", "appName"]

然后exec "$@"实际上将评估为:

exec appName /usr/bin/myprogram

而且由于appName不是一个有效的命令,容器只会失败。

有几种方法可以解决这个问题:

  1. 您真的需要将参数传递给您的ENTRYPOINT脚本吗?那么使用环境变量呢?
  2. 如果您总是将参数传递给脚本,则可以使用shiftshell 命令在使用$@. 例如,对于需要两个参数的脚本:

    param1=$1
    param2=$2
    shift 2
    
    ...do stuff here...
    
    exec "$@"
    

    ...但这仅在您始终传递两个参数时才有效。

  3. 您可以使用以下命令在脚本中实现命令行选项处理getopts

    while getopts a:b: ch; do
      case $ch in
        (a) param1=$OPTARG
            ;;
        (b) param2=$OPTARG
            ;;
      esac
    done
    shift $(( $OPTIND - 1 ))
    
    ...do stuff here...
    
    exec "$@"
    

话虽如此:我会选择选项 1(使用环境变量)作为最简单的解决方案:

docker run -e PARAM1="some value" ...

然后在您的ENTRYPOINT脚本中,您可以$PARAM1在需要的地方使用该变量。

于 2019-11-12T23:05:58.263 回答