如何通过dockerfile在ENTRYPOINT之前执行一个shell命令
我有我的nodejs项目的以下文件
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" ]
我运行docker容器与-e标志提供环境variables
但我没有看到替代品。 当envvariables可用时,运行命令是否会被执行?
图像是不可变的
Dockerfile定义了一个图像的构build过程。 一旦build成,图像是不可改变的(不能改变)。 运行时variables不会被烘焙到这个不变的图像中。 所以Dockerfile是解决这个问题的错误地方。
使用入口点脚本
你可能想要做的是用你自己的脚本覆盖默认的ENTRYPOINT
,并让脚本对环境variables做些什么。 由于入口脚本将在运行时(容器启动时)执行,因此这是收集环境variables并对其执行操作的正确时间。
首先,您需要调整Dockerfile以了解入口点脚本。 尽pipeDockerfile并不直接涉及处理环境variables,但仍需要了解该脚本,因为该脚本将被烘焙到您的映像中。
Dockerfile:
COPY entrypoint.sh /entrypoint.sh RUN chmod +x /entrypoint.sh ENTRYPOINT ["/entrypoint.sh"] CMD ["npm", "start"]
现在,编写一个入口脚本, 在运行命令之前进行任何设置,最后exec
命令本身。
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, ie "npm start" exec "$@"
在这里,我已经包含了npm install
,因为你在评论中询问了这个问题。 我会注意到这将在每次运行时运行npm install
。 如果这是合适的,那就好了,但是我想指出它会每次都运行,这会给启动时间增加一些延迟。
现在重build你的图像,所以入口脚本是它的一部分。
在运行时使用环境variables
入口点脚本知道如何使用环境variables,但是你仍然必须告诉Docker在运行时导入variables。 你可以使用-e
标志来docker run
。
docker run -e "ENVSUBS=$ENVSUBS" <image_name>
在这里,Docker被告知定义一个环境variablesENVSUBS
,它被赋值的值是当前shell环境中的$ENVSUBS
的值。
入口点脚本如何工作
我会在这里详细说明一下,因为在评论中,似乎你对这个如何组合起来有点模糊。
当Docker启动一个容器时,它会在容器中执行一个(且只有一个)命令。 该命令变成PID 1,就像典型的Linux系统上的init
或systemd
一样。 这个过程负责运行容器需要的任何其他进程。
默认情况下, ENTRYPOINT
是/bin/sh -c
。 您可以在Dockerfile或docker-compose.yml中或使用docker命令覆盖它。
当容器启动时,Docker运行入口命令,并将命令( CMD
)作为参数列表传递给它。 早些时候,我们将自己的ENTRYPOINT
定义为/entrypoint.sh
。 这意味着在你的情况下,这是Docker在启动时将在容器中执行的内容:
/entrypoint.sh npm start
因为["npm", "start"]
被定义为命令,所以作为参数列表传递给入口点脚本。
因为我们使用-e
标志定义了一个环境variables,所以这个入口点脚本(及其子)将有权访问该环境variables。
在入口脚本的末尾,我们运行exec "$@"
。 因为$@
扩展到传递给脚本的参数列表,所以会运行
exec npm start
而且由于exec
以命令的forms运行它的参数,所以当你完成后, npm start
会在你的容器中变成PID 1。
为什么你不能使用多个CMD
在评论中,你问是否可以定义多个CMD
条目来运行多个事情。
您只能定义一个ENTRYPOINT
和一个CMD
。 这些在构build过程中根本不使用。 与RUN
和COPY
不同,它们在构build期间不会执行。 一旦构build完成,它们将作为元数据项添加到映像中。
只有当图像作为容器运行时,才会读取这些元数据字段,并用于启动容器。
如前所述,入口点是真正运行的,并且将CMD
作为参数列表传递。 他们分开的原因部分是历史的。 在早期版本的Docker中, CMD
是唯一可用的选项,并且ENTRYPOINT
被固定为/bin/sh -c
。 但由于像这样的情况,Docker最终允许用户定义ENTRYPOINT
。
当envvariables可用时,运行命令是否会被执行?
使用-e
标志设置的环境variables在run
容器时设置。
问题是Dockerfile是在容器的build
上读取的,所以RUN
命令不会意识到这个环境variables。
在build上设置环境variables的方法是在Dockerfile中添加ENV
行。 ( https://docs.docker.com/engine/reference/builder/#/environment-replacement )
所以你的Dockerfile可能是:
FROM node:latest WORKDIR /src ADD package.json . ENV A YOLO RUN echo "$A"
而输出:
$ docker build . Sending build context to Docker daemon 2.56 kB Step 1 : FROM node:latest ---> f5eca816b45d Step 2 : WORKDIR /src ---> Using cache ---> 4ede3b23756d Step 3 : ADD package.json . ---> Using cache ---> a4671a30bfe4 Step 4 : ENV A YOLO ---> Running in 7c325474af3c ---> eeefe2c8bc47 Removing intermediate container 7c325474af3c Step 5 : RUN echo "$A" ---> Running in 35e0d85d8ce2 YOLO ---> 78d5df7d2322
在RUN
命令启动时,您会在前一行看到,容器知道设置了环境variables。
- 在NodeJS中存储临时variables
- 如何在JavaScript中从模块中导出variables?
- 节点JS:访问JSON如果string中的variables名?
- 使用docker-compose.test自动testingdocker镜像:缺less环境variables
- 在JavaScript中设置一个variables(node.js)
- 如何在node.js app heroku中访问.env文件中的variables
- 从开发切换到生产环境时,使用grunt切换HTML元素
- 全局variablesexpress node.js
- 不能在html scripttag中将EJSvariables推入数组中?