我正在尝试创建一个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中?
答案 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
的可执行文件。 (它可能适用于source
或RUN
)
要运行包含从该文件设置的项目的命令,您应该能够逃脱:
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。