为什么 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 但类似的问题。

我不知道具体如何解决这个问题,因为文件系统中有很多您没有(也可能不能)与我们分享的上下文。

我的策略建议是:

  1. 注释掉从失败行到 Dockerfile 末尾的所有行
  2. 构建局部图像
  3. docker exec -it [image] bash跳进图片
  4. 四处看看,找出问题所在
  5. 重复 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 而不是 cprsync

而不是

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.