【问题标题】:source in every Dockerfile RUN call每个 Dockerfile RUN 调用中的源
【发布时间】:2021-03-02 13:05:58
【问题描述】:

我有一个 Dockerfile,我发现自己经常需要调用 source /opt/ros/noetic/setup.bash

例如:

RUN source /opt/ros/noetic/setup.bash \
    && SOME_COMMAND

RUN source /opt/ros/noetic/setup.bash \
    && SOME_OTHER_COMMAND

有没有一种方法可以在 Dockerfile 中的每个 RUN 调用中对此进行初始化?

尝试添加到 ~/.bash_profile 和 Docker 的 ENV 命令,但没有成功。

【问题讨论】:

  • 我试图回答,我失败了。简短的回答:不。长答案:如果这看起来太难看,请编写一个包装脚本。

标签: bash docker ubuntu dockerfile ros


【解决方案1】:

TL;DR:您想要的可以通过将您的 .sh 脚本复制到 /etc/profile.d/ 并使用 SHELL Dockerfile 命令来调整默认 shell。

详情:

首先,请考虑以下示例脚本setup.sh

#!/bin/sh
echo "# setup.sh"
ENV_VAR="some value"
some_fun() {
    echo "## some_fun"
}

那么,可以注意到bash提供了--login CLI选项:

当 Bash 作为交互式登录 shell 或作为带有 --login 选项的非交互式 shell 调用时,它首先从文件 /etc/profile 中读取并执行命令,如果该文件存在的话。读取该文件后,它会按顺序查找~/.bash_profile~/.bash_login~/.profile,并从第一个存在且可读的文件中读取并执行命令。当 shell 启动时可以使用--noprofile 选项来禁止这种行为。

当交互式登录 shell 退出或非交互式登录 shell 执行 exit 内置命令时,Bash 会从文件 ~/.bash_logout(如果存在)读取并执行命令。

https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Bash-Startup-Files

此外,您可以利用/etc/profile.d 文件夹,而不是在/etc/profile 中附加setup.sh 代码,大多数发行版都以以下方式读取该文件夹:

$ docker run --rm -i debian:10 cat /etc/profile | tail -n 9

if [ -d /etc/profile.d ]; then
  for i in /etc/profile.d/*.sh; do
    if [ -r $i ]; then
      . $i
    fi
  done
  unset i
fi

特别注意.sh 扩展是强制性的,因此上面的最小工作示例的命名为:setup.sh(不是setup.bash)。

最后,可以依靠SHELL command 替换RUN 使用的默认shell(代替["/bin/sh", "-c"])来合并bash--login 选项。

具体来说,您可以这样表达您的Dockerfile

FROM debian:10

# WORKDIR /opt/ros/noetic
# COPY setup.sh .
# RUN . /opt/ros/noetic/setup.sh && echo "ENV_VAR=$ENV_VAR"

# empty var here
RUN echo "ENV_VAR=$ENV_VAR"

# enable the extra shell init code
COPY setup.sh /etc/profile.d/

SHELL ["/bin/bash", "--login", "-c"]

# nonempty var and function
RUN echo "ENV_VAR=$ENV_VAR" && some_fun

# DISABLE the extra shell init code!
RUN rm /etc/profile.d/setup.sh

# empty var here
RUN echo "ENV_VAR=$ENV_VAR"

结果:

$ docker build -t test .
Sending build context to Docker daemon  6.144kB
Step 1/7 : FROM debian:10
 ---> ef05c61d5112
Step 2/7 : RUN echo "ENV_VAR=$ENV_VAR"
 ---> Running in 87b5c589ec60
ENV_VAR=
Removing intermediate container 87b5c589ec60
 ---> 6fdb70be76f9
Step 3/7 : COPY setup.sh /etc/profile.d/
 ---> e6aab4ebf9ef
Step 4/7 : SHELL ["/bin/bash", "--login", "-c"]
 ---> Running in d73b0d13df23
Removing intermediate container d73b0d13df23
 ---> ccbe789dc36d
Step 5/7 : RUN echo "ENV_VAR=$ENV_VAR" && some_fun
 ---> Running in 42fd1ae14c17
# setup.sh
ENV_VAR=some value
## some_fun
Removing intermediate container 42fd1ae14c17
 ---> de74831896a4
Step 6/7 : RUN rm /etc/profile.d/setup.sh
 ---> Running in bdd969a63def
# setup.sh
Removing intermediate container bdd969a63def
 ---> 5453be3271e5
Step 7/7 : RUN echo "ENV_VAR=$ENV_VAR"
 ---> Running in 0712cea427f1
ENV_VAR=
Removing intermediate container 0712cea427f1
 ---> 216a421f5659
Successfully built 216a421f5659
Successfully tagged test:latest

【讨论】:

    猜你喜欢
    • 2022-08-11
    • 2014-01-05
    • 1970-01-01
    • 2016-09-24
    • 1970-01-01
    • 1970-01-01
    • 2020-03-09
    相关资源
    最近更新 更多