如何防止Dockerfile缓存git clone

74

我有一个Dockerfile,试图将一个Web应用程序打包并部署到容器中。在构建Docker镜像时,应用程序的代码从Git存储库中获取。 以下是Dockerfile快照:

........
RUN git clone --depth=1 git-repository-url $GIT_HOME/
RUN mvn package -Dmaven.test.skip
........

我希望 Docker 在构建镜像时不缓存 RUN git clone --depth=1 git-repository-url $GIT_HOME/ 步骤,以便正在更新的代码能够反映在镜像中。这是否可行?

8个回答

82

另一个解决方法:

如果您使用 GitHub(或 gitlab 或 bitbucket),您可以将 GitHub API 对您的存储库的表示添加到虚拟位置。

ADD https://api.github.com/repos/$USER/$REPO/git/refs/heads/$BRANCH version.json
RUN git clone -b $BRANCH https://github.com/$USER/$REPO.git $GIT_HOME/

API调用将在头部更改时返回不同的结果,从而使docker缓存失效。
如果您正在处理私有存储库,可以使用github的x-oauth-basic身份验证方案个人访问令牌,方法如下:
ADD https://$ACCESS_TOKEN:x-oauth-basic@api.github.com/repos/$USER/$REPO/git/refs/heads/$BRANCH version.json

感谢@captnolimar提供的建议编辑,以澄清身份验证。


1
在 GitHub 上运行得非常完美。有私人 GitLab 的示例吗? - Ivan
2
不错的解决方案。以下是在 Bitbucket 上执行的方法。ADD https://[USER]:[PASS]@api.bitbucket.org/2.0/repositories/[ORG-NAME]/[REPO-NAME]/commit/[BRANCH] /info RUN git clone --depth 1 --branch [BRANCH] https://[USER]:[PASS]@bitbucket.org/[ORG-NAME]/[REPO-NAME].git /repo我建议创建一个专门的“集成”用户并使用“应用程序密码”来管理 Bitbucket。https://confluence.atlassian.com/bitbucket/app-passwords-828781300.html 将其与多阶段构建相结合,似乎是目前最完美的解决方案。 - McP
4
为了以完全通用、独立于服务提供商的方式完成此操作,这里有一种选项:ADD http://worldtimeapi.org/api/ip /time.tmp - Jay
5
截至2020年,Github API似乎已经发生了变化,URL https://api.github.com/repos/$USER/$REPO/git/refs/heads/$BRANCH不再起作用,因为API已经更新。请建议更新后的URL。 - Hemant Kumar
1
对于GitLab: ADD https://gitlab.example.com/api/v4/projects/$PROJECT_ID/repository/branches/$BRANCH_NAME/ version.json - undefined
显示剩余3条评论

17

我曾经遇到过同样的问题,我决定在构建镜像时使用--no-cache选项,而不是试图单独找出git仓库。

docker build --no-cache -t my_image .

对于我的简单用例,这是提出的解决方案中最简单/最容易的。谢谢@tomgsmith99。 - James Adams

16

问题1996目前还没有解决,但是您可以使用以下解决方法

FROM foo
ARG CACHE_DATE=2016-01-01
RUN git clone ...

docker build --build-arg CACHE_DATE=$(date) ....

这将使每次构建后的ARG CACHE_DATE行之后的缓存失效。

或者:

ADD http://www.convert-unix-time.com/api?timestamp=now /tmp/bustcache
RUN git pull

这将在ADD命令执行后使缓存失效。

类似的想法:

Add ARG command to your Dockerfile:

# Dockerfile
# add this and below command will run without cache
ARG CACHEBUST=1

When you need to rebuild with selected cache, run it with --build-arg option

$ docker build -t your-image --build-arg CACHEBUST=$(date +%s) .

then only layer below ARG command in Dockerfile will rebuild.


谢谢您的建议。但是,我使用云CaaS来构建Docker镜像,因此这种方法对我无效。没有办法传递Docker参数。 - Raindy
不适用于我。Docker版本17.05.0-ce,构建89658be。 - Stephan Richter
@StephanRichter 和 https://github.com/moby/moby/pull/10682#issuecomment-178794901? - VonC

8

对于遇到Gitlab代码库问题的人:

在调用Gitlab API时,Gitlab有这种令人恼火的分支ID方法。该ID将出现在您的代码库名称下方。 enter image description here

# this will copy the last change from your brach and it'll invalidate the cache if there was a new change
ADD "https://gitlab.com/api/v4/projects/${PROJECT_ID}/repository/branches/master?private_token=${GIT_TOKEN}" /tmp/devalidateCache

# the actual clone
RUN git clone --depth=1 https://${GIT_USER}:${GIT_TOKEN}@gitlab.com/${git_file_uri} ${BASE_BUILD_PATH}

7
如果您使用 Github,可以使用 Github API 来不缓存特定的 RUN 命令。您需要安装 jq 来解析 JSON:apt-get install -y jq。
示例:
docker build --build-arg SHA=$(curl -s 'https://api.github.com/repos/Tencent/mars/commits' | jq -r '.[0].sha') -t imageName .

在 Dockerfile 中(ARG 命令应该紧随在 RUN 命令之前):
ARG SHA=LATEST
RUN SHA=${SHA} \
    git clone https://github.com/Tencent/mars.git

或者如果您不想安装jq
SHA=$(curl -s 'https://api.github.com/repos/Tencent/mars/commits' | grep sha | head -1)

如果存储库有新的提交,将会执行git clone。

1

0
感谢 @anq 的想法,但提供的 API 已过时,最新的 API 文档在 Get a reference
请使用 https://api.github.com/repos/{owner}/{repo}/git/ref/heads/{ref}
例如:https://api.github.com/repos/wind8866/hello-react/git/ref/heads/main

-3

对于 Github 私有仓库,您也可以传递您的用户名和密码:

RUN git clone -b$BRANCH https://$USER:$PASSWORD@github.com/$USER/$REPO.git $GIT_HOME/


1
如果我只允许管理员克隆一个仓库,我不想传递我的用户密码。 - Kangur

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接