在Docker中安装Rust工具链时,Bash`source`命令不起作用

时间:2018-04-05 15:45:59

标签: linux bash docker

我正在尝试创建一个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中?

4 个答案:

答案 0 :(得分:2)

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

因此,在RUN命令中运行“source”(几乎总是)是无用的。它会加载货物环境然后退出,从而失去所有的环境变化。

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

第二个选项是基本上将源作为每个RUN命令的一部分运行,并在Dockerfile的其余部分中需要它。例如RUN bash -c 'source $HOME/.cargo/env; command goes here。这对于每个RUN行都有更多的工作,但是当你需要时,环境将明确地存在,而不是在你不需要时。

大部分时间,第一个选项就是你想要的。 很少你想要第二个。也就是说,有时你只需要这个环境用于设置目的,而你不希望它持续存在 - 这种情况很少见,尽管我已经有过这种情况了几次。

答案 1 :(得分: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

答案 2 :(得分:0)

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using DotRas; namespace vpnConsole { class Program { static void Main(string[] args) { string vpnName = "VPN Essai"; string destination = "113.244.66.3"; string preSharedKey = "Gs0r2!-8753"; try { RasPhoneBook phoneBook = new RasPhoneBook(); phoneBook.Open(); RasEntry vpnEntry = RasEntry.CreateVpnEntry(vpnName,destination,RasVpnStrategy.L2tpFirst,RasDevice.Create(vpnName,RasDeviceType.Vpn),false); vpnEntry.Options.UsePreSharedKey = true; vpnEntry.Options.UseLogOnCredentials = true; vpnEntry.Options.RequirePap = true; phoneBook.Entries.Add(vpnEntry); vpnEntry.UpdateCredentials(RasPreSharedKey.Client, preSharedKey); vpnEntry.Options.RequirePap = true; [enter image description here][1]bool isUpdated = vpnEntry.Update(); Console.WriteLine(@"Connection created and Updated with PreSharedKey=true, LogOnCredentials=true,RequirePap=true, RecordIsUpdated=" + isUpdated); } catch (Exception ex) { Console.WriteLine(@"ERROR: " + ex.Message + " Details: " + ex.Source ); Environment.Exit(999); } } } } (或source)是一个内置命令的shell - 它运行来自当前shell中作为参数给出的文件中的命令。这对于配置脚本中配置的当前环境(别名,函数和环境变量)非常有用,不适用于启动它的父shell,.可以配置它们。这就是source失败的原因 - 没有名为RUN的可执行文件。 (它可能适用于sourceRUN

的shell形式

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

SHELL

如果要将变量应用于容器内的shell,则需要将source命令添加到shell启动时获取的其中一个bash文件,例如: RUN bash -c 'source ~/.cargo/env; cargo <whatever>' ~/.bashrc(取决于登录shell是否已启动)或(在大多数发行版上)~/.bash_profile

中的.sh文件

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

/etc/profile.d/

答案 3 :(得分:0)

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上有rust images,您可以使用它们(在FROM中,而不是ubuntu:16.04中)运行或构建Rust应用。比通过apt和curl安装所有内容更快,更容易。

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