Dockerfile CMD exec form如何定位binary

How does Dockerfile CMD exec form locate the binary

如果我有这样的 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 for this base image...,您实际上会发现 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"
            ],
...

因此在 scratch 映像中创建了 PATH。 This old issue and associated PR 表明 docker 包含开箱即用的 PATH。

如何调整该路径?您需要使用 ENV 行。如果您在 RUN 行中设置变量,则在 RUN 行完成后它不会被保留。如果您附加到容器中的 .bashrc,则不适用于非 bash shell,如 /bin/sh,任何使用不带 [=42 的 exec 语法的东西=],以及任何非交互式 bash shells(因为 .bashrc 在非交互式 shells 中途停止处理)。这是一个不同的 image/build:

的例子
$ 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_(variable)

注意:$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