在Windows Docker容器中添加PATH的内容

40

我需要在 Windows Docker 容器中添加路径,我已经尝试了很多变化。

ENV PATH=%PATH%;C:\\Foo\\bin
ENV PATH=$PATH;C:\\Foo\\bin
ENV PATH="%PATH%;C:\Foo\bin"
ENV PATH="$PATH;C:\Foo\bin"
RUN "set PATH=%PATH%;C:\Foo\bin"

这些都不可行:它们不能评估预先存在的 PATH 变量。

如何正确地追加到 PATH?我能否在 Docker 内部追加 PATH?(在类似的 Linux 容器上可以)


传递给Docker容器的环境变量仅对由docker可执行文件执行的进程可见。它们不会在整个机器上可见。但是,如果您对此没有问题,为什么不在启动期间读取此变量,并在容器内部将其附加到PATH变量中呢?关于环境变量在系统范围内不可见的问题,请参见https://github.com/docker/docker/issues/30192。 - Gregory Suvalian
1
@GSA,如果没有解决方案,我也认为那是一个答案。但我很惊讶“将路径附加到我的容器环境”对于Windows容器来说不是已经解决的用户故事。 - macetw
9个回答

66

很遗憾,ENV不能工作,因为Windows环境变量与Linux有些不同。 更多信息

目前唯一的方法是通过RUN来实现。

但是您不需要创建单独的文件来执行此操作。可以通过以下简单的单行命令完成:

RUN setx path "%path%;C:\Foo\bin"


28
PS等价命令:运行 "setx /M PATH $($Env:PATH + ';C:\Foo\bin)",此命令将"C:\Foo\bin"添加到系统环境变量"PATH"中。 - JasonCoder
9
@JasonCoder - 谢谢!只是在最后一个括号之前漏掉了一个单引号。 - Glenn
今天我们尝试了您的解决方案,但遇到了问题,setx无法工作,只能使用ENV,如此处所建议:https://github.com/PowerShell/PowerShell-Docker/issues/164 我感到很困惑;但是我们很快就会转向Linux容器... - Hermann.Gruber
PS equiv 2: RUN setx /M PATH \"$Env:PATH;C:\Foo\bin\". 花了几个额外的恼人小时重新发现,在Dockerfile-windows-powershell中需要转义双引号\"才能在命令中使用双引号。请参见https://github.com/StefanScherer/dockerfiles-windows/tree/789fa0b54c0d0263fa9464025cfe12ec2fe0cd6c/quotes。换句话说,上述代码等同于在交互式powershell会话中执行`setx /M PATH "$Env:Path;C:\Foo\bin"`。 - solstice333
实际上,这比我最初意识到的要复杂一些。你可能还想了解三种类型的环境变量:机器/系统、用户和进程。请参考此链接 - solstice333

13

您可以使用PowerShell脚本永久设置容器中的环境变量。

在您的Docker上下文中创建一个PowerShell脚本(例如,setpath.ps1),包含以下内容:

[Environment]::SetEnvironmentVariable("Path", $env:Path + ";C:\Foo\bin", [EnvironmentVariableTarget]::Machine)
将此脚本添加到您的容器 Dockerfile 中并运行该脚本。在你的 Dockerfile 中添加类似于这样的内容:

将此脚本添加到您的容器 Dockerfile 中并运行该脚本。在你的 Dockerfile 中添加类似于这样的内容:

ADD ./setpath.ps1 c:/MyScripts/setpath.ps1
RUN powershell -Command c:\MyScripts\setpath.ps1

这对我不起作用。无论我是否在dockerfile中加入这行代码,PATH变量都与之前相同。有什么想法吗? - Jonas Sourlier
1
这对我在 dotnet 框架容器(4.7.1)上运行成功。唯一需要补充的是,为了使任何“RUN powershell...”命令正常工作,我必须在 FROM 之后的 dockerfile 顶部添加 ENTRYPOINT ["powershell.exe"] 行。 - Khoward

10

[环境变量]::SetEnvironmentVariable 是一个不错的方法,但在nanoserver中无法使用。 最佳选择是:

RUN setx path '%path%;C:\Foo\bin'

这对我来说是个问题:ERROR:系统找不到指定的注册表路径。针对镜像mcr.microsoft.com/dotnet/sdk:7.0...那个镜像没有PowerShell,也无法尝试PowerShell解决方案。但是Mark Nguyen建议使用USER ContainerAdministrator,然后在setx命令中使用/M标志确实有效。 - nl-x

10

这对我有效!在Windows Nano Server 1909上进行了测试。 - Vitalii Ilchenko
太棒了,谢谢。在 Server 2019 上使用 mcr.microsoft.com/dotnet/framework/sdk:4.7.2 镜像进行了工作。由于我的 Dockerfile 中的所有其他命令都使用转义反斜杠作为路径分隔符,因此我修改了命令以 RUN "setx /M PATH \"%PATH%;C:\\Program Files\\Git\\bin\"" 的形式呈现。 - Jürgen Steinblock

2

尽管之前的答案已经很详细了,但我在某些环境中遇到了问题。在自定义本地测试环境中,使用%PATH%;C:\foo\bar方式设置路径时,即使文件夹名字带有空格,比如C:\Program Files,也能正常工作。但是在生产环境中就不行了。 当我们查看微软在他们自己的镜像上安装基础包时所做的事情时,发现更好、更可靠的方法是使用以下命令:

RUN setx /M PATH $(${Env:PATH} + \";${Env:ProgramFiles(x86)}\foo\bar\")

这样,Docker 就可以获取正确的路径并正确更新 PATH 数据。 编辑: 我已经修复了命令中缺少的尾随 \,感谢 Robin Ding :)

末尾缺失反斜杠:RUN setx /M PATH $(${Env:PATH} + \";${Env:ProgramFiles(x86)}\foo\bar\") 空格也可以使用: RUN setx /M PATH $(${Env:PATH} + \";${Env:ProgramFiles(x86)}\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\") - Robin Ding

0

以下内容适用于我在nanoserver-1809中(来自这个GitHub问题):

ENV PATH="$WindowsPATH;C:\Foo\bin"

对我来说,PATH变量在此之后看起来是这样的:;C:\Foo\bin。似乎你无法在ENV命令中访问当前的PATH/WindowsPATH变量。 - undefined

0
以下命令在使用基础镜像mcr.microsoft.com/windows/servercore:ltsc2019Dockerfile中对我有效。
(我的场景是将Java设置到PATH中。即使路径中有空格,它也可以正常工作)
(请确保使用您的应用程序/工具更新JAVA_HOME环境变量)
ENV JAVA_HOME="C:\Program Files\Java\jdk-17"

RUN $newPath = ('{0}\bin;{1}' -f $env:JAVA_HOME, $env:PATH); \
     [Environment]::SetEnvironmentVariable('PATH', $newPath, [EnvironmentVariableTarget]::Machine)

CMD ["java", "--version"]

顺便提一下,当我尝试这里的其他答案时,我确实遇到了以下错误(原因是路径中有空格,或者环境变量${Env:ProgramFiles}未能正确解析等)

  • 术语“C:\Program”不被识别为cmdlet的名称。
  • 表达式或语句中的意外标记'\Java\jdk-17\bin'。

0

我的答案与mirsik的类似,但不需要单独的脚本。只需将以下内容放入您的Dockerfile中

RUN $env:PATH = 'C:\Foo\bin;{0}' -f $env:PATH ; \
[Environment]::SetEnvironmentVariable('PATH', $env:PATH, [EnvironmentVariableTarget]::Machine)

0
我使用了Mirsik解决方案。 我的问题是我有带有空格和未知版本号的目录。
例如:"C:\Program Files\Prog\Vers_*\bin" 这是我问题的解决方案:
1. 导航到目录并从目标文件夹创建一个符号链接,将其放置在可访问的位置(C:) RUN powershell -Command "cd 'C:\Program Files\Prog\Vers_*\bin';$path = (Get-Location).Path; New-Item -ItemType SymbolicLink -Path 'C:\' -Name 'Prog.lnk' -Target $path" 2. 将符号链接添加到PATH环境变量中 RUN setx /M PATH "%PATH%;C:\Prog.lnk\" 这不是一个漂亮的工作流程,但对我来说有效。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接