【问题标题】:How to get git clone to play nice with Docker cache?如何让 git clone 与 Docker 缓存配合得很好?
【发布时间】:2021-07-11 04:20:10
【问题描述】:

当我克隆一个存储库两次时,例如:

git clone <repo_X> --depth 1 clone1
git clone <repo_X> --depth 1 clone2

然后做一个差异

diff -r clone1 clone2

这显示了差异:

Binary files clone1/.git/index and clone2/.git/index differ
...
diff -r clone1/.git/logs/HEAD clone2/.git/logs/HEAD
...
diff -r clone1/.git/logs/refs/remotes/origin/HEAD 
...

似乎克隆的时间记录在一个文件中。

我想向 Docker 映像添加一些存储库。当文件没有改变时,Docker 使用它的缓存。不幸的是,在克隆后,由于文件更改,Docker 总是使缓存无效。

  1. 是否有可能让一个 repo 的两个克隆生成完全相同的文件? (注意:我不想删除 .git 目录,因为我希望能够在图像中使用 git 来检查 repo 的版本。)

  2. 是否可以让 Docker 在缓存时忽略 .git 文件夹(注意 .git 文件夹仍然必须添加到映像中,所以 .dockerignore 不是一个选项?)

【问题讨论】:

  • 如何使用 docker COPY 命令将预克隆的 git 文件夹从主机文件系统移动到映像?
  • 这不起作用: 1. 我在文件夹 X 中克隆 repo 2. 使用 COPY 将文件夹 X 添加到映像 3. 构建映像 4. 删除 X 5. 重新克隆 X现在,当您重建 docker 映像时,docker 不会将缓存用于 COPY X 步骤。
  • 对不起,我猜我错了,我认为 repo 内容在 2 个图像之间保持不变,您不需要删除 X 并再次重新克隆。
  • 同一台机器上的不同用户也将修改 Docker Image,因此他也将克隆一个 repo。如果 repo 没有改变,Docker 会使用它的缓存。但是,即使克隆的 repo 在同一次提交时,也会根据 Docker 更改一些文件。

标签: git docker caching


【解决方案1】:

您可以使用新的 Docker 的 BuildKit 功能 --mount=cache。 Dockerfile 的玩具示例:

FROM ubuntu
RUN --mount=type=cache,target=/var/cache/apt \
    apt update && apt upgrade -y && apt install -yq git
RUN echo A00
RUN --mount=type=cache,target=/tmp/git_cache/ \
    git clone --depth=1 https://github.com/qtox/qtox/ /tmp/git_cache/qtox/; \
    cd /tmp/git_cache/qtox/ && git pull && cp -r ./ /tmp/my_qtox/
RUN echo B00

上面的dockerfile可以通过命令构建:

sudo env DOCKER_BUILDKIT=1 docker build -f Dockerfile .

注意DOCKER_BUILDKIT=1 环境变量的存在,必须在 docker build 中启用所有 BuildKit 功能。您可以阅读有关 BuildKit 的功能here

例如我克隆了上面的qTox repo,因为它非常大。

--mount=cache 功能自动创建用于缓存的临时目录并将其挂载到容器内的/tmp/git_cache/(目标)中。如果之前的一些层发生了变化,例如echo A00 更改为 echo A01 然后立即完成此克隆,因为它只是从缓存中获取的。

此外,正如您所要求的,使用此缓存将使克隆存储库完全相同。只有当新的提交出现在存储库中时,git pull 才完成并且存储库更改。除非有新的提交,否则这个缓存的存储库将保持不变。因此,每次再次运行 docker build 时,您都会拥有相同的 git repo。

只有极少数情况下,如果缓存目录长时间不使用或磁盘可用空间不足,Docker 会自动删除。

从上面的 docker-file 中可以看到,最终的 git repo 将出现在容器的 /tmp/my_qtox/ 文件夹中。您可以将此路径更改为您的案例所需的任何路径。

另外你可能已经注意到我在安装 APT 包时使用了相同的缓存机制。这非常方便,因为在重建映像时,所有包都不会从远程 Ubuntu 服务器重新下载,而是从缓存目录中获取。当 apt install 之前的 docker 层发生变化或将新的 apt 包添加到安装列表时,这很有用,在这两种情况下,apt install 都会非常快速地重新运行。

【讨论】:

    【解决方案2】:

    不要使用git-clone(1),而是使用git-archive(1)(至少在最后)。它还包含已归档的修订,您可以在包含修订的文件中添加标记,例如创建一个标志文件。

    对于需要完整克隆的存储库,同时克隆(或将克隆后的元数据更改为基线)。

    通常完整的克隆应该不是特别需要的。如果,您还可以考虑在流程中使用 tar-pipe 来简化结果,以便缓存保持有效(仅在需要时失效)。

    【讨论】:

      猜你喜欢
      • 2014-04-07
      • 2019-05-18
      • 2016-10-04
      • 2010-09-11
      • 1970-01-01
      • 2011-10-24
      • 2016-08-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多