【问题标题】:When installing Rust toolchain in Docker, Bash `source` command doesn't work在 Docker 中安装 Rust 工具链时,Bash `source` 命令不起作用
【发布时间】:2018-09-15 12:28:27
【问题描述】:

我正在尝试创建一个 docker 映像,该映像将为构建 Rust 项目设置一个 Linux 环境。到目前为止,这是我的Dockerfile

FROM ubuntu:16.04

# Update default packages
RUN apt-get update

# Get Ubuntu packages
RUN apt-get install -y \
    build-essential \
    curl

# Update new packages
RUN apt-get update

# Get Rust
RUN curl https://sh.rustup.rs -sSf | bash -s -- -y

我需要做的最后一件事是配置 Rust,这样我就可以使用cargo。文档说要使用

source $HOME/.cargo/env

但是当我在 Dockerfile 的 RUN 命令中尝试这样做时,它说 source 无法识别。我发现的另一个选择是使用

RUN /bin/bash -c "source ~/.cargo/env"

这不会出错,但是当我运行我的容器时,cargo 不是一个可识别的命令。

当我打开容器时,这两种方法都适用于 Bash,但我希望这可以作为图像的一部分自动化。

如何将它集成到我的 Dockerfile 中?

【问题讨论】:

  • bash -c 'source anything' only sources 一个文件进入单个bash 实例,该实例在命令完成时退出。使用它的正确方法是 bash -c 'source ~/.cargo/env && cargo whatever',在实际需要使用您添加的内容的同一 shell 中运行 source
  • (另外,考虑. 而不是source -- 后者的名称是一种bashism,而前者是POSIX 规定的)。

标签: linux bash docker


【解决方案1】:

您必须在 .bashrc 中添加源代码。

这行得通:

FROM ubuntu:16.04

# Update default packages
RUN apt-get update

# Get Ubuntu packages
RUN apt-get install -y \
    build-essential \
    curl

# Update new packages
RUN apt-get update

# Get Rust
RUN curl https://sh.rustup.rs -sSf | bash -s -- -y

RUN echo 'source $HOME/.cargo/env' >> $HOME/.bashrc

编辑

代替

RUN echo 'source $HOME/.cargo/env' >> $HOME/.bashrc

你可以使用

ENV PATH="/root/.cargo/bin:${PATH}"

这是一个更少的 bash-only 解决方案

【讨论】:

  • .bashrc 不受(所有)非交互式 shell 的支持。因此,对于这个用例来说,这不是一个特别合适的选择。
  • 我知道,我这样回答是因为在我看来这就是他想要做的:在 docker 容器内使用交互式 bash 并提供可用的货物命令
  • 您可以使用ENV PATH="/root/.cargo/bin:${PATH}",这是使cargo 可见的一种很好且透明的方式。附言注意 /root 在我的示例中,您可以通过 dockerfile 中的 USER root 以 root 身份构建,或者您可以将 /root 更改为所需的目录。
  • ENV PATH=... 的解决方案似乎通常更适用于大多数 docker 图像
  • 如果你不介意,你能解释一下bash -s -- -y 是如何工作的吗?该命令有效,但我不明白它如何从提示中选择第一个选项?从 url 下载的 shell 文件是否接受 -y 作为参数?如果是这样,你是怎么找到的,它没有写在下载页面的任何地方。我在这里很迷茫
【解决方案2】:

source ~/.cargo/env 唯一做的就是

export PATH="$HOME/.cargo/bin:$PATH"

所以我的建议是在你的 Dockerfile 中明确设置 PATH:

FROM ubuntu:16.04

# Update default packages
RUN apt-get -qq update

# Get Ubuntu packages
RUN apt-get install -y -q \
    build-essential \
    curl

# NOTE: no need to run update again at this point
# RUN apt-get update

# Get Rust; NOTE: using sh for better compatibility with other base images
RUN curl https://sh.rustup.rs -sSf | sh -s -- -y

# Add .cargo/bin to PATH
ENV PATH="/root/.cargo/bin:${PATH}"

# Check cargo is visible
RUN cargo --help

这比source .cargo/env 稍微透明一点,如果你不熟悉 Rust,更容易掌握。

另外,请注意 DockerHub 上有 rustimages,您可以使用它们(在 FROM,而不是 ubuntu:16.04)运行或构建 Rust 应用程序。这将比通过 apt 和 curl 安装所有东西更快、更容易。

对于构建应用程序,您可能会发现multistage docker builds 很有用。他们是pretty flexible

【讨论】:

    【解决方案3】:

    我想你可能误解了source 的作用。这个内置命令告诉当前 shell(几乎)加载以下代码,就好像它在当前提示符下运行一样(您也可以在其他脚本中使用 source)。它基本上是一个“在此处包含文件”命令。它主要用于设置您的环境(PATH、LIBPATH 和其他 shell 函数),而不是做实际工作。

    因此(几乎总是)在 RUN 命令中运行“源代码”是无用的。它将加载货物环境然后退出,从而丢失所有环境更改。

    这为您提供了两个基本选项。一种是按照 michael_bitard 的建议进行操作,并将其添加到您的 .bashrc。这将意味着该容器(由该用户)中的所有命令都将设置环境。如果您只需要它进行设置,那么它会在运行时污染您的 shell 环境。

    第二个选项基本上是在 Dockerfile 的其余部分中将源代码作为每个需要它的 RUN 命令的一部分运行。 RUN bash -c 'source $HOME/.cargo/env; command goes here 例如。这在每条 RUN 行上都需要做更多的工作,但环境会在您需要时显式出现,而不是在您不需要时。

    大多数时候,第一个选项就是你想要的。 很少你想要第二个。也就是说,有时您只需要此环境来进行设置,并且您不希望它持续存在 - 这种情况很少见,尽管我曾多次遇到这种情况。

    【讨论】:

    • 谢谢。我根本不了解source 的本质。我对 Bash 和 Linux 很陌生。
    【解决方案4】:

    source(或.)是一个shell内置命令——它运行当前shell中作为参数给出的文件中的命令。这对于配置脚本中配置的当前环境(别名、函数和环境变量)非常有用,不适用于启动它的父 shell,source 可以配置这些。这就是RUN 失败的原因——没有名为source 的可执行文件。 (它可能适用于RUNSHELL 的shell 形式)

    要使用从该文件设置的项目运行命令,您应该能够逃脱:

    RUN bash -c 'source ~/.cargo/env; cargo <whatever>'
    

    如果您希望将变量应用于容器内的 shell,则需要将 source 命令添加到启动 shell 时获取的 bash 文件之一,例如~/.bashrc~/.bash_profile(取决于登录 shell 是否启动)或(在大多数发行版上)/etc/profile.d/ 中的 .sh 文件

    执行此操作的一种方法是在 Dockerfile 中使用以下内容:

    RUN ln -s $HOME/.cargo/env /etc/profile.d/cargo_env.sh
    

    【讨论】:

      猜你喜欢
      • 2014-06-09
      • 2018-06-15
      • 1970-01-01
      • 1970-01-01
      • 2019-07-31
      • 2016-10-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多