如何让 git clone 与 Docker 缓存一起玩?

dwj*_*man 5 git caching docker

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

git clone <repo_X> --depth 1 clone1
git clone <repo_X> --depth 1 clone2
Run Code Online (Sandbox Code Playgroud)

然后做一个差异

diff -r clone1 clone2
Run Code Online (Sandbox Code Playgroud)

这显示了差异:

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 
...
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

Art*_*oul 4

您可以使用新的 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
Run Code Online (Sandbox Code Playgroud)

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

sudo env DOCKER_BUILDKIT=1 docker build -f Dockerfile .

注意DOCKER_BUILDKIT=1环境变量的存在,有必要在 docker build 中启用所有 BuildKit 的功能。您可以在此处了解 BuildKit 的功能。

例如,我克隆了上面的qTox存储库,因为它非常巨大。

--mount=cache功能会自动创建用于缓存的临时目录并将其安装到/tmp/git_cache/容器内的(目标)中。如果某些先前的层发生更改,例如echo A00更改为echo A01,则此克隆将立即完成,不会延迟,因为它只是从缓存中获取。

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

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

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

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