如何通过dockerfile在ENTRYPOINT之前执行shell命令 [英] How to execute a shell command before the ENTRYPOINT via the dockerfile

查看:2140
本文介绍了如何通过dockerfile在ENTRYPOINT之前执行shell命令的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的nodejs项目有以下文件

I have the following file for my nodejs project

FROM node:boron

# Create app directory
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app

# Install app dependencies
COPY package.json /usr/src/app/
RUN npm install



# Bundle app source
COPY . /usr/src/app

# Replace with env variable
RUN envsubs < fil1 > file2

EXPOSE 8080
CMD [ "npm", "start" ]

我使用提供环境变量的-e标志运行docker容器

I run the docker container with the -e flag providing the environment variable

但是我看不到替代品.当env变量可用时,会否执行Run ccommand?

But I do not see the replacement. Will the Run ccommand be excuted when the env variable is available?

推荐答案

图像是不可变的

Dockerfile定义映像的构建过程.生成后,图像将是不可变的(无法更改).运行时变量不会被添加到此不可变映像中.因此,Dockerfile是解决此问题的错误位置.

Images are immutable

Dockerfile defines the build process for an image. Once built, the image is immutable (cannot be changed). Runtime variables are not something that would be baked into this immutable image. So Dockerfile is the wrong place to address this.

您可能想做的是用自己的脚本覆盖默认的ENTRYPOINT,并让该脚本对环境变量进行处理.由于入口点脚本将在运行时(容器启动时)执行,因此这是收集环境变量并对其进行处理的正确时间.

What you probably want to to do is override the default ENTRYPOINT with your own script, and have that script do something with environment variables. Since the entrypoint script would execute at runtime (when the container starts), this is the correct time to gather environment variables and do something with them.

首先,您需要调整Dockerfile以了解入口点脚本.尽管Dockerfile并不直接参与处理环境变量,但仍需要了解此脚本,因为该脚本将被烘焙到您的映像中.

First, you need to adjust your Dockerfile to know about an entrypoint script. While Dockerfile is not directly involved in handling the environment variable, it still needs to know about this script, because the script will be baked into your image.

Dockerfile:

COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

ENTRYPOINT ["/entrypoint.sh"]
CMD ["npm", "start"]

现在,编写一个入口点脚本,该命令将在命令运行之前进行所有必要的设置,最后,exec命令本身.

Now, write an entrypoint script which does whatever setup is needed before the command is run, and at the end, exec the command itself.

entrypoint.sh:

#!/bin/sh

# Where $ENVSUBS is whatever command you are looking to run
$ENVSUBS < fil1 > file2

npm install

# This will exec the CMD from your Dockerfile, i.e. "npm start"
exec "$@"

在这里,我已经包含了npm install,因为您在评论中对此进行了询问.我会注意到,这将在每次运行时运行npm install .如果合适的话,很好,但是我想指出一下,它将每次都运行,这会增加启动时间的延迟.

Here, I have included npm install, since you asked about this in the comments. I will note that this will run npm install on every run. If that's appropriate, fine, but I wanted to point out it will run every time, which will add some latency to your startup time.

现在重建图像,因此入口点脚本是其中的一部分.

Now rebuild your image, so the entrypoint script is a part of it.

入口点脚本知道如何使用环境变量,但是您仍然必须告诉Docker在运行时导入该变量.您可以将-e标志用于docker run.

The entrypoint script knows how to use the environment variable, but you still have to tell Docker to import the variable at runtime. You can use the -e flag to docker run to do so.

docker run -e "ENVSUBS=$ENVSUBS" <image_name>

在这里,告诉Docker定义一个环境变量ENVSUBS,为其分配的值是当前shell环境中的$ENVSUBS的值.

Here, Docker is told to define an environment variable ENVSUBS, and the value it is assigned is the value of $ENVSUBS from the current shell environment.

我将对此进行详细说明,因为在评论中,您似乎对此不太了解.

I'll elaborate a bit on this, because in the comments, it seemed you were a little foggy on how this fits together.

当Docker启动容器时,它在容器内执行一个(只有一个)命令.就像典型Linux系统上的initsystemd一样,此命令将成为PID 1.此过程负责运行容器需要具有的其他任何过程.

When Docker starts a container, it executes one (and only one) command inside the container. This command becomes PID 1, just like init or systemd on a typical Linux system. This process is responsible for running any other processes the container needs to have.

默认情况下,ENTRYPOINT/bin/sh -c.您可以在Dockerfile或docker-compose.yml中或使用docker命令覆盖它.

By default, the ENTRYPOINT is /bin/sh -c. You can override it in Dockerfile, or docker-compose.yml, or using the docker command.

启动容器时,Docker运行entrypoint命令,并将命令(CMD)作为参数列表传递给它.之前,我们将自己的ENTRYPOINT定义为/entrypoint.sh.这意味着在您的情况下,这就是Docker启动时将在容器中执行的内容:

When a container is started, Docker runs the entrypoint command, and passes the command (CMD) to it as an argument list. Earlier, we defined our own ENTRYPOINT as /entrypoint.sh. That means that in your case, this is what Docker will execute in the container when it starts:

/entrypoint.sh npm start

因为["npm", "start"]被定义为命令,所以该命令将作为参数列表传递给入口点脚本.

Because ["npm", "start"] was defined as the command, that is what gets passed as an argument list to the entrypoint script.

由于我们使用-e标志定义了环境变量,因此该入口点脚本(及其子项)将可以访问该环境变量.

Because we defined an environment variable using the -e flag, this entrypoint script (and its children) will have access to that environment variable.

在入口点脚本的末尾,我们运行exec "$@".因为$@会扩展到传递给脚本的参数列表,所以它将运行

At the end of the entrypoint script, we run exec "$@". Because $@ expands to the argument list passed to the script, this will run

exec npm start

并且由于exec将其参数作为命令运行,因此将替换为当前进程本身,完成后,npm start成为容器中的PID 1.

And because exec runs its arguments as a command, replacing the current process with itself, when you are done, npm start becomes PID 1 in your container.

在注释中,您询问是否可以定义多个CMD条目来运行多个事物.

In the comments, you asked whether you can define multiple CMD entries to run multiple things.

您只能定义一个ENTRYPOINT和一个CMD.这些在构建过程中根本不使用.与RUNCOPY不同,它们在构建期间不会执行.一旦建立图像,它们就会作为元数据项添加到图像中.

You can only have one ENTRYPOINT and one CMD defined. These are not used at all during the build process. Unlike RUN and COPY, they are not executed during the build. They are added as metadata items to the image once it is built.

直到稍后,当图像作为容器运行时,这些元数据字段才被读取并用于启动容器.

It is only later, when the image is run as a container, that these metadata fields are read, and used to start the container.

如前所述,入口点是真正运行的入口点,它作为参数列表传递给CMD.它们分开的原因部分是历史原因.在早期版本的Docker中,CMD是唯一可用的选项,而ENTRYPOINT已修复为/bin/sh -c.但是由于这种情况,Docker最终允许用户定义ENTRYPOINT.

As mentioned earlier, the entrypoint is what is really run, and it is passed the CMD as an argument list. The reason they are separate is partly historical. In early versions of Docker, CMD was the only available option, and ENTRYPOINT was fixed as being /bin/sh -c. But due to situations like this one, Docker eventually allowed ENTRYPOINT to be defined by the user.

这篇关于如何通过dockerfile在ENTRYPOINT之前执行shell命令的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆