Dockerfile CMD exec表单如何定位二进制文件



如果我有这样的Dockerfile:

FROM ubuntu 
CMD [ "ps", "-ef" ]

如果我构建并运行图像,我会得到

$ docker run -it 156a9f959f43
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 07:12 pts/0    00:00:00 ps -ef

这与文献一致。

问题:当容器运行时,二进制ps是如何首先定位的?

exec语法使用在父映像(ubuntu:latest(中定义的PATH环境变量。
$ docker image inspect ubuntu:latest
[
{
...
"Config": {
...
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/bin/bash"
],
....

如果你在Dockerfile中查看这个基本映像。。。您将看到PATH变量并没有在那里定义。我们可以去看scratch,但那是一个虚像。

因此,让我们在scratch上构建一个没有任何内容的图像,看看定义了什么变量:

$ cat df.scratch 
FROM scratch
$ docker build -t test-scratch -f df.scratch .
...
$ docker image inspect test-scratch:latest
[
{
...
"Config": {
...
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
...

因此,PATH正在scratch映像中创建。这个旧问题和相关的PR显示docker包含了一个开箱即用的PATH。

你如何调整这条路?您需要使用ENV行。如果在RUN行中设置了一个变量,则在该RUN行完成后,该变量将不会保留。如果您在容器中追加到.bashrc,则这不适用于像/bin/sh这样的非bash shell、任何使用exec语法但没有shell的shell以及任何非交互式bash shell(因为.bashrc在处理非交互式shell的过程中中途停止了处理(。以下是一个不同图像/构建的例子:

$ cat df.path 
FROM ubuntu
# before state from the base image
RUN [ "env" ]
# attempting to modify the .bashrc
RUN echo "export PATH="$PATH:/my/custom/bin/dir"" >> ~/.bashrc 
RUN [ "env" ]
# modifying the image environment variable directly
ENV PATH=${PATH}:/opt/custom/bin
RUN [ "env" ]
$ docker build -t test-path -f df.path .
Sending build context to Docker daemon  31.23kB
Step 1/6 : FROM ubuntu
---> 4e5021d210f6
Step 2/6 : RUN [ "env" ]
---> Running in 5bb72abb386d
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=5bb72abb386d
HOME=/root
Removing intermediate container 5bb72abb386d
---> c438fb269c70
Step 3/6 : RUN echo "export PATH="$PATH:/my/custom/bin/dir"" >> ~/.bashrc
---> Running in 127b10aff046
Removing intermediate container 127b10aff046
---> 4af50595c271
Step 4/6 : RUN [ "env" ]
---> Running in c5ff46ba3b82
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=c5ff46ba3b82
HOME=/root
Removing intermediate container c5ff46ba3b82
---> 455325a5e484
Step 5/6 : ENV PATH=${PATH}:/opt/custom/bin
---> Running in e7960d9ce18a
Removing intermediate container e7960d9ce18a
---> ed532bff78b4
Step 6/6 : RUN [ "env" ]
---> Running in 9c1558a61ab7
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/custom/bin
HOSTNAME=9c1558a61ab7
HOME=/root
Removing intermediate container 9c1558a61ab7
---> f08993f21b97
Successfully built f08993f21b97
Successfully tagged test-path:latest

请注意,在步骤2中路径的原始值,在步骤4中保持不变,并且在步骤6中具有定义的值。

在docker容器中(与大多数操作系统类似(有一个$PATH环境变量,它保存可执行文件所在的目录路径(用:分隔(。

例如,$PATH变量可能包含类似/usr/local/bin:/usr/bin:/home/ubuntu/bin的值,这意味着当您运行类似ps的命令时,它将在这些目录中查找可执行文件。

您可以在此处了解有关$PATH变量的更多信息https://en.wikipedia.org/wiki/PATH_(可变(

注意:$PATH变量将因容器而异(因为它们是独立的单元(,并且很可能包含docker映像所使用的基本发行版的实际值。

要在基于linux的系统上更改$PATH变量,可以运行export PATH="$PATH:/custom/bin/dir",它会将/custom/bin/dir附加到变量中。要使此更改永久化,您应该将此命令添加到.bashrc、.profile、.zshrc或类似文件(取决于您使用的shell(中

因此,要更新docker容器中的变量,您应该在docker文件中添加这样的内容

FROM ubuntu 
RUN echo "export PATH="$PATH:/my/custom/bin/dir"" >> ~/.bashrc 

最新更新