简体   繁体   English

在 NGINX docker 容器中启动之前运行 bash 脚本

[英]Running a bash script before startup in an NGINX docker container

I'm trying to run a javascript app on localhost:8000 using docker.我正在尝试使用 docker 在 localhost:8000 上运行一个 javascript 应用程序。 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 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.但是 docker 容器仍然关闭。 Is there something I'm missing?有什么我想念的吗?

NGINX 1.19 has a folder /docker-entrypoint.d on the root where place startup scripts executed by the docker-entrypoint.sh script. NGINX 1.19 在根目录下有一个文件夹/docker-entrypoint.d ,用于放置由docker-entrypoint.sh脚本执行的启动脚本。 You can also read the execution on the log.您还可以读取日志上的执行情况。

/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration /docker-entrypoint.sh: /docker-entrypoint.d/ 不为空,会尝试执行配置

/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/ /docker-entrypoint.sh:在 /docker-entrypoint.d/ 中寻找 shell 脚本

/docker-entrypoint.sh: Launching /docker-entrypoint.sh:启动

[..........] […………]

/docker-entrypoint.sh: Configuration complete; /docker-entrypoint.sh:配置完成; ready for start up准备启动

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 $1 ]]; 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' < $1 > $1

# 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.问题是WORKDIR ,没有它 nginx 命令将不会被执行。 If you want to apply this to other containers be sure to set the WORKDIR accordingly.如果您想将此应用于其他容器,请务必相应地设置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 $1 ]]; 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} $1
  # Variables to be replaced should have the format: ${TEST}
  grep -rl $i $1 | xargs sed -i "s/\${$i}/${!i}/Ig"
done

exec "${@:2}"

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.这意味着来自nginx:alpine容器的启动 CMD 将运行。 The above script will inject the specified environment variables into a config file.上面的脚本会将指定的环境变量注入到配置文件中。 By doing this in runtime yo can override the environment variables.通过在运行时执行此操作,您可以覆盖环境变量。

Update the CMD line as below in the your dockerfile.更新 dockerfile 中的 CMD 行,如下所示。 Please note that if runfile.sh does not succeed ( exit 0; inside it) then the next nginx command will not be executed.请注意,如果runfile.sh不成功( exit 0; inside),那么下一个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 commnd to start the server on the base image you use. nginx docker 文件使用 CMD 命令在您使用的基本映像上启动服务器。 When you use the CMD command in your dockerfile you overwrite the one in their image.当您在 dockerfile 中使用 CMD 命令时,您会覆盖其映像中的命令。 As it is mentioned in the dockerfile documentation :正如dockerfile 文档中提到的:

There can only be one CMD instruction in a Dockerfile.一个 Dockerfile 中只能有一个 CMD 指令。 If you list more than one CMD then only the last CMD will take effect.如果你列出了多个 CMD,那么只有最后一个 CMD 会生效。

nginx container already defines ENTRYPOINT. nginx 容器已经定义了 ENTRYPOINT。 If you define also CMD it will combine them both like 'ENTRYPOINT CMD' in such way that CMD becomes argument of ENTRYPOINT.如果您还定义了 CMD,它将像“ENTRYPOINT CMD”一样将它们组合起来,这样 CMD 就会成为 ENTRYPOINT 的参数。 That is why you need to redefine ENTRYPOINT to get it working.这就是为什么您需要重新定义 ENTRYPOINT 以使其工作的原因。

Usually ENTRYPOINT is defined in such way, that if you also pass CMD, it will be executed by ENTRYPOINT script.通常 ENTRYPOINT 是这样定义的,如果你也通过 CMD,它将被 ENTRYPOINT 脚本执行。 However this might not be case with every container.然而,这可能不是每个容器的情况。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM