为什么 docker 没有完全删除我的文件?
Why is docker not completely deleting my file?
我正在尝试构建使用:
FROM mcr.microsoft.com/dotnet/core/sdk:2.1 AS builder
COPY pythonnet/src/ pythonnet/src
WORKDIR /pythonnet/src/runtime
RUN dotnet build -f netstandard2.0 -p:DefineConstants=\"MONO_LINUX\;XPLAT\;PYTHON3\;PYTHON37\;UCS4\;NETSTANDARD\" Python.Runtime.15.csproj
# copy myApp csproj and restore
COPY src/myApp/*.csproj /src/myApp/
WORKDIR /src/myApp
RUN dotnet restore
# now copy everything else as separate docker step
# (copy to staging folder, remove csproj, and copy down - so we don't overwrite project above)
WORKDIR /
COPY src/myApp/ ./staging/src/myApp
RUN rm ./staging/src/myApp/*.csproj \
&& cp -r ./staging/* ./ \
&& rm -rf ./staging
这工作正常,在 Windows 10 中仍然如此,但在 CentOS 7 中我得到:
Step 10/40 : RUN rm ./staging/src/myApp/*.csproj && cp -r ./staging/* ./ && rm -rf ./staging
---> Running in 6b17ae0fae89
cp: cannot stat './staging/src/myApp/myApp.csproj': No such file or directory
使用 ls
而不是 cp
会引发类似的文件未找到错误,所以看起来 Docker 仍然知道 myApp.csproj
但看不到它,因为它已经已删除。
有办法解决这个问题吗?我试过使用 rsync
但类似的问题。
我不知道具体如何解决这个问题,因为文件系统中有很多您没有(也可能不能)与我们分享的上下文。
我的策略建议是:
- 注释掉从失败行到 Dockerfile 末尾的所有行
- 构建局部图像
docker exec -it [image] bash
跳进图片
- 四处看看,找出问题所在
- 重复 1-4 直到事情按预期进行
当然,它不如一个非常有洞察力的答案那么有趣,但这是一个非常有效的算法,即使它很乏味和烦人。
编辑
我的疯狂猜测是,不知何故,linux 机器由于某种原因没有将文件放在预期的位置,因此它根本没有被复制到图像中,这就是为什么 docker 构建过程找不到它。但是如果不调试构建过程就无法知道。
只要源是符号 link 并且 link 的 target 不是存在。它不会将 link 复制到不存在的文件。
所以我的猜测是,在您 运行 COPY src/myApp/ ./staging/src/myApp
之后,您的文件 ./staging/src/myApp/myApp.csproj
是一个符号 link 到一个不存在的文件。为什么以下RUN rm ./staging/src/*.csproj
不删除它并对此保持沉默,我不知道答案。
为了帮助证明我的理论,请参阅下面显示的 cp 在 Centos 7 上的 symlink 上失败。
[547] $ docker run --rm -it centos:7
Unable to find image 'centos:7' locally
7: Pulling from library/centos
524b0c1e57f8: Pull complete
Digest: sha256:e9ce0b76f29f942502facd849f3e468232492b259b9d9f076f71b392293f1582
Status: Downloaded newer image for centos:7
[root@a47b77cf2800 /]# ln -s /tmp/foo /tmp/bar
[root@a47b77cf2800 /]# ls -l /tmp/foo
ls: cannot access /tmp/foo: No such file or directory
[root@a47b77cf2800 /]# ls -l /tmp/bar
lrwxrwxrwx 1 root root 8 Jul 6 05:44 /tmp/bar -> /tmp/foo
[root@a47b77cf2800 /]# cp /tmp/foo /tmp/1
cp: cannot stat '/tmp/foo': No such file or directory
[root@a47b77cf2800 /]# cp /tmp/bar /tmp/2
cp: cannot stat '/tmp/bar': No such file or directory
请注意您如何复制报告,它无法统计符号 link 的源或目标。这正是您所看到的症状。
如果你只是想克服这个问题,你可以尝试 tar
而不是 cp
或 rsync
。
而不是
cp -r ./staging/* ./
改用这个:
tar -C ./staging -cf - . | tar -xf -
tar 将愉快地复制不存在的符号link。
我简单地忽略了这个问题,只是在有问题的行上添加 ;exit 0
。不是很好,但是很管用。
编辑:这对我有用,因为我无法升级 CemtOS 的版本。如果可以,请查看 Alexander Block 的回答。
您很可能遇到了很久以前在更新的内核中修复的内核错误。自 https://de.wikipedia.org/wiki/CentOS 起,CentOS 7 基于 Linux 内核 3.10,该内核已经相当陈旧,并且在存储后端(覆盖文件系统)方面没有很好的 Docker 支持。
CentOS 试图向后移植所需的修复和功能到 3.10,但在覆盖支持方面似乎没有完全成功。当您在互联网上搜索“CentOS 7 overlay driver”时,您可以找到与此相关的多个(略有不同的)问题。它们都有一个共同点,即从父叠加层中删除文件无法按预期工作。
对我来说,看起来 rm
调用文件 return 成功,即使文件没有完全删除。目录列表(例如,根据您的情况,通过 ls
或 shell 扩展)仍然列出文件,而访问文件则失败(无论文件是读、写还是删除)。
我假设您所看到的只是这些问题的另一种体现。您应该切换到 CentOS 8 或升级您的内核(据我所知,CentOS 并未正式支持内核)。或者更激进,切换到与 Docker 结合使用更频繁的发行版,并且通常提供更新的内核,例如Debian 或 Ubuntu.
我正在尝试构建使用:
FROM mcr.microsoft.com/dotnet/core/sdk:2.1 AS builder
COPY pythonnet/src/ pythonnet/src
WORKDIR /pythonnet/src/runtime
RUN dotnet build -f netstandard2.0 -p:DefineConstants=\"MONO_LINUX\;XPLAT\;PYTHON3\;PYTHON37\;UCS4\;NETSTANDARD\" Python.Runtime.15.csproj
# copy myApp csproj and restore
COPY src/myApp/*.csproj /src/myApp/
WORKDIR /src/myApp
RUN dotnet restore
# now copy everything else as separate docker step
# (copy to staging folder, remove csproj, and copy down - so we don't overwrite project above)
WORKDIR /
COPY src/myApp/ ./staging/src/myApp
RUN rm ./staging/src/myApp/*.csproj \
&& cp -r ./staging/* ./ \
&& rm -rf ./staging
这工作正常,在 Windows 10 中仍然如此,但在 CentOS 7 中我得到:
Step 10/40 : RUN rm ./staging/src/myApp/*.csproj && cp -r ./staging/* ./ && rm -rf ./staging
---> Running in 6b17ae0fae89
cp: cannot stat './staging/src/myApp/myApp.csproj': No such file or directory
使用 ls
而不是 cp
会引发类似的文件未找到错误,所以看起来 Docker 仍然知道 myApp.csproj
但看不到它,因为它已经已删除。
有办法解决这个问题吗?我试过使用 rsync
但类似的问题。
我不知道具体如何解决这个问题,因为文件系统中有很多您没有(也可能不能)与我们分享的上下文。
我的策略建议是:
- 注释掉从失败行到 Dockerfile 末尾的所有行
- 构建局部图像
docker exec -it [image] bash
跳进图片- 四处看看,找出问题所在
- 重复 1-4 直到事情按预期进行
当然,它不如一个非常有洞察力的答案那么有趣,但这是一个非常有效的算法,即使它很乏味和烦人。
编辑
我的疯狂猜测是,不知何故,linux 机器由于某种原因没有将文件放在预期的位置,因此它根本没有被复制到图像中,这就是为什么 docker 构建过程找不到它。但是如果不调试构建过程就无法知道。
所以我的猜测是,在您 运行 COPY src/myApp/ ./staging/src/myApp
之后,您的文件 ./staging/src/myApp/myApp.csproj
是一个符号 link 到一个不存在的文件。为什么以下RUN rm ./staging/src/*.csproj
不删除它并对此保持沉默,我不知道答案。
为了帮助证明我的理论,请参阅下面显示的 cp 在 Centos 7 上的 symlink 上失败。
[547] $ docker run --rm -it centos:7
Unable to find image 'centos:7' locally
7: Pulling from library/centos
524b0c1e57f8: Pull complete
Digest: sha256:e9ce0b76f29f942502facd849f3e468232492b259b9d9f076f71b392293f1582
Status: Downloaded newer image for centos:7
[root@a47b77cf2800 /]# ln -s /tmp/foo /tmp/bar
[root@a47b77cf2800 /]# ls -l /tmp/foo
ls: cannot access /tmp/foo: No such file or directory
[root@a47b77cf2800 /]# ls -l /tmp/bar
lrwxrwxrwx 1 root root 8 Jul 6 05:44 /tmp/bar -> /tmp/foo
[root@a47b77cf2800 /]# cp /tmp/foo /tmp/1
cp: cannot stat '/tmp/foo': No such file or directory
[root@a47b77cf2800 /]# cp /tmp/bar /tmp/2
cp: cannot stat '/tmp/bar': No such file or directory
请注意您如何复制报告,它无法统计符号 link 的源或目标。这正是您所看到的症状。
如果你只是想克服这个问题,你可以尝试 tar
而不是 cp
或 rsync
。
而不是
cp -r ./staging/* ./
改用这个:
tar -C ./staging -cf - . | tar -xf -
tar 将愉快地复制不存在的符号link。
我简单地忽略了这个问题,只是在有问题的行上添加 ;exit 0
。不是很好,但是很管用。
编辑:这对我有用,因为我无法升级 CemtOS 的版本。如果可以,请查看 Alexander Block 的回答。
您很可能遇到了很久以前在更新的内核中修复的内核错误。自 https://de.wikipedia.org/wiki/CentOS 起,CentOS 7 基于 Linux 内核 3.10,该内核已经相当陈旧,并且在存储后端(覆盖文件系统)方面没有很好的 Docker 支持。
CentOS 试图向后移植所需的修复和功能到 3.10,但在覆盖支持方面似乎没有完全成功。当您在互联网上搜索“CentOS 7 overlay driver”时,您可以找到与此相关的多个(略有不同的)问题。它们都有一个共同点,即从父叠加层中删除文件无法按预期工作。
对我来说,看起来 rm
调用文件 return 成功,即使文件没有完全删除。目录列表(例如,根据您的情况,通过 ls
或 shell 扩展)仍然列出文件,而访问文件则失败(无论文件是读、写还是删除)。
我假设您所看到的只是这些问题的另一种体现。您应该切换到 CentOS 8 或升级您的内核(据我所知,CentOS 并未正式支持内核)。或者更激进,切换到与 Docker 结合使用更频繁的发行版,并且通常提供更新的内核,例如Debian 或 Ubuntu.