在 NGINX docker 容器中启动之前运行 bash 脚本
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/40608055/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Running a bash script before startup in an NGINX docker container
提问by chiloutus
I'm trying to run a javascript app on localhost:8000 using docker. Part of what I would like to do is swap out some config files based on the docker run command, I'd like to pass an environment variable into the container so that the bash script can use that as a parameter.
我正在尝试使用 docker 在 localhost:8000 上运行一个 javascript 应用程序。我想做的一部分是根据 docker run 命令换出一些配置文件,我想将环境变量传递到容器中,以便 bash 脚本可以将其用作参数。
What my dockerfile is looking like is this:
我的 dockerfile 是这样的:
FROM nginx
COPY . /usr/share/nginx/html
CMD ["bash","/usr/share/nginx/html/runfile.sh"]
And the bash script looks like this:
bash 脚本如下所示:
#!/bin/bash
if [ "$SECURITY_VERSION" = "OPENAM" ]; then
sed -i -e 's/localhost/openam/g' authConfig.js
fi
docker run -p 8000:80 missioncontrol:latest -e SECURITY_VERSION="TEST"
Docker gives me an exception saying -e exec command not found.
Docker 给了我一个异常,说 -e exec 命令未找到。
However if I change the dockerfile to use ENTRYPOINT instead of CMD, the -e flag works but the webserver does not start up.
但是,如果我将 dockerfile 更改为使用 ENTRYPOINT 而不是 CMD,则 -e 标志有效,但网络服务器不会启动。
Is there something I'm missing here? Is the ENTRYPOINT being overriden or something?
有什么我在这里想念的吗?是入口点被覆盖还是什么?
EDIT:
编辑:
So I've updated my dockerfile to use ENTRYPOINT ["bash","/usr/share/nginx/html/runfile.sh", ";", " nginx -g daemon off;"]
所以我更新了我的 dockerfile 以使用 ENTRYPOINT ["bash","/usr/share/nginx/html/runfile.sh", ";", " nginx -g daemon off;"]
But the docker container still shuts down. Is there something I'm missing?
但是 docker 容器仍然关闭。有什么我想念的吗?
回答by Daniel Habenicht
For my future self and everybody else, this is how you can set up variable substitution at startup (for nginx, may also work for other images):
对于我未来的自己和其他人,这是在启动时设置变量替换的方法(对于 nginx,也可能适用于其他图像):
I've also wrote a more in depth blog post about it: https://danielhabenicht.github.io/docker/angular/2019/02/06/angular-nginx-runtime-variables.html
我还写了一篇关于它的更深入的博客文章:https: //danielhabenicht.github.io/docker/angular/2019/02/06/angular-nginx-runtime-variables.html
Dockerfile:
Dockerfile:
FROM nginx
ENV TEST="Hello variable"
WORKDIR /etc/nginx
COPY ./substituteEnv.sh ./substituteEnv.sh
# Execute the subsitution script and pass the path of the file to replace
ENTRYPOINT ["./substituteEnv.sh", "/usr/share/nginx/html/index.html"]
CMD ["nginx", "-g", "daemon off;"]
subsitute.sh: (same as @Daniel West's answer)
subsitute.sh:(与@Daniel West 的回答相同)
#!/bin/bash
if [[ -z ]]; then
echo 'ERROR: No target file given.'
exit 1
fi
#Substitute all environment variables defined in the file given as argument
envsubst '$TEST $UPSTREAM_CONTAINER $UPSTREAM_PORT' < >
# Execute all other paramters
exec "${@:2}"
Now you can run docker run -e TEST="set at command line" -it <image_name>
现在你可以运行 docker run -e TEST="set at command line" -it <image_name>
The catch was the WORKDIR
, without it the nginx command wouldn't be executed. If you want to apply this to other containers be sure to set the WORKDIR
accordingly.
问题是WORKDIR
,没有它 nginx 命令将不会被执行。如果您想将此应用于其他容器,请务必相应地设置WORKDIR
。
If you want to do the substitution recursivly in multiple files this is the bash script you are looking for:
如果你想在多个文件中递归地进行替换,这就是你正在寻找的 bash 脚本:
# Substitutes all given environment variables
variables=( TEST )
if [[ -z ]]; then
echo 'ERROR: No target file or directory given.'
exit 1
fi
for i in "${variables[@]}"
do
if [[ -z ${!i} ]]; then
echo 'ERROR: Variable "'$i'" not defined.'
exit 1
fi
echo $i ${!i}
# Variables to be replaced should have the format: ${TEST}
grep -rl $i | xargs sed -i "s/${$i}/${!i}/Ig"
done
exec "${@:2}"
回答by Jouni Rajala
nginx container already defines ENTRYPOINT. If you define also CMD it will combine them both like 'ENTRYPOINT CMD' in such way that CMD becomes argument of ENTRYPOINT. That is why you need to redefine ENTRYPOINT to get it working.
nginx 容器已经定义了 ENTRYPOINT。如果您还定义了 CMD,它将像“ENTRYPOINT CMD”一样将它们组合起来,从而使 CMD 成为 ENTRYPOINT 的参数。这就是为什么您需要重新定义 ENTRYPOINT 以使其工作的原因。
Usually ENTRYPOINT is defined in such way, that if you also pass CMD, it will be executed by ENTRYPOINT script. However this might not be case with every container.
通常 ENTRYPOINT 是这样定义的,如果你也通过 CMD,它将被 ENTRYPOINT 脚本执行。然而,这可能不是每个容器的情况。
回答by Daniel West
I know this is late but I found this thread while searching for a solution so thought I'd share.
我知道这已经晚了,但我在寻找解决方案时发现了这个线程,所以我想分享一下。
I had the same issue. Your ENTRYPOINT script should also include exec "$@"
我遇到过同样的问题。您的 ENTRYPOINT 脚本还应包括exec "$@"
#!/bin/sh
set -e
envsubst '$CORS_HOST $UPSTREAM_CONTAINER $UPSTREAM_PORT' < /srv/api/default.conf > /etc/nginx/conf.d/default.conf
exec "$@"
That will mean the startup CMD from the nginx:alpine
container will run. The above script will inject the specified environment variables into a config file. By doing this in runtime yo can override the environment variables.
这将意味着来自nginx:alpine
容器的启动 CMD将运行。上面的脚本会将指定的环境变量注入到配置文件中。通过在运行时执行此操作,您可以覆盖环境变量。
回答by Qutory
Update the CMD line as below in the your dockerfile. Please note that if runfile.sh
does not succeed (exit 0;
inside it) then the next nginx
command will not be executed.
更新 dockerfile 中的 CMD 行,如下所示。请注意,如果runfile.sh
不成功(exit 0;
在它里面)那么下一个nginx
命令将不会被执行。
FROM nginx
COPY . /usr/share/nginx/html
CMD /usr/share/nginx/html/runfile.sh && nginx -g 'daemon off;'
nginx docker file is using a CMD commndto start the server on the base image you use. When you use the CMD command in your dockerfile you overwrite the one in their image. As it is mentioned in the dockerfile documentation:
nginx docker 文件使用 CMD 命令在您使用的基本映像上启动服务器。当您在 dockerfile 中使用 CMD 命令时,您会覆盖其映像中的命令。正如dockerfile 文档中提到的:
There can only be one CMD instruction in a Dockerfile. If you list more than one CMD then only the last CMD will take effect.
一个 Dockerfile 中只能有一个 CMD 指令。如果您列出多个 CMD,则只有最后一个 CMD 生效。