如何在 Dockerfile 中使用命令替换

How do I use command substition in Dockerfile

在我的 Dockerfile 中,我需要使用命令替换来添加一些环境变量。我要设置

ENV PYTHONPATH /usr/local/$(python3 -c 'from distutils import sysconfig; print(sysconfig.get_python_lib())')

但它不起作用。结果是

foo@bar:~$ echo $PYTHONPATH
/usr/local/$(python3 -c from distutils import sysconfig; print(sysconfig.get_python_lib()))

怎么了?

出了什么问题

您尝试的 $( ... ) command substitution 是针对 Bash,而 Dockerfile 不是 Bash。所以 docker 不知道该怎么办,它只是 docker 的纯文本,docker 只是吐出你写的内容 as-is.

推荐

为了避免 hard-coding 值进入 Dockerfile,而是在构建期间将设置或自定义变量动态更改为 PYTHONPATH,也许 ARG ...--build-arg docker 功能可能最有帮助,结合 ENV ... 以确保它持续存在。

在你的 Dockerfile 中:

ARG PYTHON_PATH_ARG

ENV PYTHONPATH ${PYTHON_PATH_ARG}

在 Bash 构建容器的位置:

python_path="/usr/local$(python3 -c 'from distutils import sysconfig; print(sysconfig.get_python_lib())')"

docker build --build-arg PYTHON_PATH_ARG=$python_path .

说明

根据文档,ARG

The ARG instruction defines a variable that users can pass at build-time to the builder with the docker build command using the --build-arg <varname>=<value> flag.

因此,在 Bash 我们首先:

python_path="/usr/local$(python3 -c 'from distutils import sysconfig; print(sysconfig.get_python_lib())')"
  • $(...) Bash命令替换用于动态拼凑一个Python路径值
  • 为清楚起见,此值临时存储在 Bash 变量中 $python_path
docker build --build-arg PYTHON_PATH_ARG=$python_path .
  • Bash 变量 $python_path 值传递给 docker 的 --build-arg PYTHON_PATH_ARG

在 Dockerfile 中:

ARG PYTHON_PATH_ARG
  • 所以 PYTHON_PATH_ARG 存储来自 --build-arg PYTHON_PATH_ARG...
  • 的值

ARG 变量不等同于 ENV 变量,所以我们不能只做 ARG PYTHONPATH 就完事了。根据有关 Using arg variables 的文档:

ARG variables are not persisted into the built image as ENV variables are.

最后:

ENV PYTHONPATH ${PYTHON_PATH_ARG}
  • 我们使用Dockerfile的${...}约定获取PYTHON_PATH_ARG的值,并保存到你原来命名的PYTHONPATH环境变量

与原始代码的差异

你最初写道:

ENV PYTHONPATH /usr/local/$(python3 -c 'from distutils import sysconfig; print(sysconfig.get_python_lib())')

我 re-wrote Python 路径查找部分作为 Bash 命令,并在我的机器上测试:

$ python_path="/usr/local/$(python3 -c 'from distutils import sysconfig; print(sysconfig.get_python_lib())')"

$ echo $python_path
/usr/local//usr/lib/python3/dist-packages

注意有一个双正斜杠 ... local//usr ... ,不确定这是否会破坏你的任何东西,取决于你如何在你的代码中使用它。

相反,我将其更改为:

$ python_path="/usr/local$(python3 -c 'from distutils import sysconfig; print(sysconfig.get_python_lib())')"

结果:

$ echo $python_path
/usr/local/usr/lib/python3/dist-packages

所以这个新代码将没有双正斜杠。

如果可能,您应该使用ARG。但有时您确实需要对动态变量使用命令替换。只要您将所有命令放在同一个 RUN 语句中,那么您仍然可以访问该值。

RUN foo=$(date) && \
    echo $foo