使用本地文件在 Windows 上构建 docker 映像时使用 --squash 的替代方案

MrB*_*rta 5 docker dockerfile docker-for-windows

我们有一些本地安装程序和 zip 文件,用于构建 docker 映像。让它在 Dockerfile 中工作很容易:

FROM mcr.microsoft.com/windows/nanoserver

COPY myinstaller.exe .
RUN myinstaller.exe; \
    del myinstaller.exe
Run Code Online (Sandbox Code Playgroud)

这里的问题是它为 COPY 线生成了一个图层,这增加了图像的大小。一种常见的解决方法是使用一个 RUN 行,从 Internet 下载文件,运行命令,然后删除安装文件。如上所述,问题在于安装程序位于本地文件系统上。

我发现docker有一个--squash命令:

docker build --squash -t mytestimage .
Run Code Online (Sandbox Code Playgroud)

这正是我想要的:它为我提供了一个图像,而没有这个不必要的额外安装程序文件。要运行此命令,您需要启用实验性功能。还有一个悬而未决的问题可以简单地删除此功能:

https://github.com/moby/moby/issues/34565

在 Windows 上运行时,是否有其他方法可以在 Dockerfile 中使用本地安装程序,而不涉及设置服务器来提供文件?

MrB*_*rta 2

我们最终设置nginx为在构建时提供文件。在我们的构建服务器上,构建 docker 镜像的机器和具有安装程序文件的服务器之间有很好的连接,因此下载大文件并不是一个真正的问题。

说到--squash,Windows 上的 Docker 就被窃听了。这是它的相关问题:

https://github.com/moby/moby/issues/31468

有一个问题需要移出--squash实验,但似乎没有得到很多支持:

https://github.com/moby/moby/issues/38657

有些人提出的替代方案--squash是多阶段构建,这里讨论:

https://github.com/moby/moby/issues/34565

如果您有本地安装程序文件--squash,并且不想设置 Web 服务器,并且希望 docker 映像较小,并且运行的是 Windows,则还有一种替代方法:使用映射驱动器。

在 Windows 中,您可以与网络上的其他用户共享文件夹。Docker 容器就像在物理机上运行的另一台计算机,它可以访问这些网络驱动器。

首先设置一个新用户,例如用户名share和密码password1。在计算机上的某个位置创建一个文件夹。然后右键单击它,单击properties,然后转到Sharing选项卡并单击“共享”。使用小下拉菜单和 找到您刚刚创建的用户Find people ...,然后与该用户共享文件夹。

为您的测试项目创建一个文件夹。setupshare.bat创建一个如下所示的批处理文件:

@echo off
for /f "tokens=2 delims=:" %%i in ('ipconfig ^| findstr "Default Gateway"') do (
    set hostip=%%i
    goto :end
)
:end
set hostip=%hostip: =%
net use O: \\%hostip%\vms /USER:share password1
Run Code Online (Sandbox Code Playgroud)

该文件的第一部分只是查找 docker 容器可以用来访问其主机的 IP 地址。这不是我组装过的最漂亮的东西,所以让我知道是否有更好的方法!

它使用 for 循环,因为这是将命令的输出保存到批处理文件中的变量的方法。该命令是 ipconfig,我们通过管道将其传输到 findstr 并搜索Default Gateway. 我们需要使用^|而不只是|因为它在 for 循环中。for 循环的第一部分将每一行与分隔符上的命令分开,:在本例中,我们只采用第二个标记。如果有多个条目具有默认网关,则 for 循环仅处理第一行。如果有多个条目并且第一个条目不正确,则此脚本不起作用。

该行set hostip=%hostip: =%用于删除字符串开头的空格。

然后我们将要使用的 IP 地址存储在hostip. 我们在net use命令中使用它,它将映射到具有 IP 的计算机上的O:\共享文件夹。我们使用用户名和密码。请注意,这是处理密码的一种非常糟糕的方式,因为它们应该是秘密的!vmshostipsharepassword1

有了这样的批处理文件,我们就可以这样设置 Dockerfile:

# escape=`
FROM mcr.microsoft.com/dotnet/core/sdk:3.0

COPY setupshare.bat .

RUN setupshare.bat && `
    copy O:\file.txt file.txt
Run Code Online (Sandbox Code Playgroud)

该RUN命令将首先调用setupshare.bat正确设置网络共享。然后我们可以使用我们共享的任何文件(例如一个巨大的安装程序)并安装我们想要的东西。在本例中,我只共享了一个测试文件file.txt来查看它是否有效,因此只需更改该行即可。

例如,我仍然建议大家只设置一个小型 Web 服务器,nginx并使用编写 Dockerfile 的标准方法,下载文件并在同一RUN命令中运行它。这就是人们看到 Dockerfile 时所期望的,它应该是一个更强大的解决方案。

我们也可以希望Docker人要么制作一个COPY可以在同一层复制、运行和删除安装程序的命令,要么--squash正确实现。