使用 Nginx Docker 容器发布 运行 初始化脚本
Issue Running an Initialization Script with Nginx Docker Container
我正在创建一个 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//CRT | jq '.Parameters[0].Value' -r > /etc/nginx/conf.d/app.crt
aws ssm get-parameters --name /Certificate//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"]
但是如果我使用这个,脚本会 运行 成功地使用参数,但是容器退出并且 Nginx 不会启动。
ENTRYPOINT ["/usr/local/bin/installcerts.sh", "AppName"]
我做错了什么?
当您在图像上设置 ENTRYPOINT
时,docker 会向该脚本传递 CMD
的值(或您在命令行中图像名称后传递的任何值)。例如,如果您有:
ENTRYPOINT ["/entrypoint.sh"]
CMD ["/usr/bin/myprogram"]
然后 docker 有效运行:
/entrypoint.sh /usr/bin/myprogram
也就是说,Docker 本身从不运行 /usr/bin/myprogram
:这完全取决于 ENTRYPOINT
脚本。这就是 exec "$@"
的用途。这是一个 shell 变量,计算结果为:
Expands to the positional parameters, starting from one.
(bash(1) man page, in the "Special Parameters" section)
在我们的示例中,这将计算为:
exec /usr/bin/myprogram
...用 /usr/bin/myprogram
替换当前脚本。但是,如果我们像您在问题中那样设置 ENTRYPOINT
:
ENTRYPOINT ["/entrypoint.sh", "appName"]
那么 exec "$@"
实际上会计算为:
exec appName /usr/bin/myprogram
并且由于 appName
不是一个有效的命令,容器将会失败。
有几种方法可以解决这个问题:
- 您真的需要将参数传递给您的
ENTRYPOINT
脚本吗?改用环境变量怎么样?
如果您 总是 将参数传递给您的脚本,您可以使用 shift
shell 命令从位置使用 $@
之前的参数。例如,对于需要两个参数的脚本:
param1=
param2=
shift 2
...do stuff here...
exec "$@"
...但这仅在您 总是 传递两个参数时有效。
您可以在脚本中实现命令行选项处理,例如使用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
变量。
我正在创建一个 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//CRT | jq '.Parameters[0].Value' -r > /etc/nginx/conf.d/app.crt
aws ssm get-parameters --name /Certificate//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"]
但是如果我使用这个,脚本会 运行 成功地使用参数,但是容器退出并且 Nginx 不会启动。
ENTRYPOINT ["/usr/local/bin/installcerts.sh", "AppName"]
我做错了什么?
当您在图像上设置 ENTRYPOINT
时,docker 会向该脚本传递 CMD
的值(或您在命令行中图像名称后传递的任何值)。例如,如果您有:
ENTRYPOINT ["/entrypoint.sh"]
CMD ["/usr/bin/myprogram"]
然后 docker 有效运行:
/entrypoint.sh /usr/bin/myprogram
也就是说,Docker 本身从不运行 /usr/bin/myprogram
:这完全取决于 ENTRYPOINT
脚本。这就是 exec "$@"
的用途。这是一个 shell 变量,计算结果为:
Expands to the positional parameters, starting from one. (bash(1) man page, in the "Special Parameters" section)
在我们的示例中,这将计算为:
exec /usr/bin/myprogram
...用 /usr/bin/myprogram
替换当前脚本。但是,如果我们像您在问题中那样设置 ENTRYPOINT
:
ENTRYPOINT ["/entrypoint.sh", "appName"]
那么 exec "$@"
实际上会计算为:
exec appName /usr/bin/myprogram
并且由于 appName
不是一个有效的命令,容器将会失败。
有几种方法可以解决这个问题:
- 您真的需要将参数传递给您的
ENTRYPOINT
脚本吗?改用环境变量怎么样? 如果您 总是 将参数传递给您的脚本,您可以使用
shift
shell 命令从位置使用$@
之前的参数。例如,对于需要两个参数的脚本:param1= param2= shift 2 ...do stuff here... exec "$@"
...但这仅在您 总是 传递两个参数时有效。
您可以在脚本中实现命令行选项处理,例如使用
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
变量。