如何在 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
在我的 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 asENV
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