互联网技术 / 互联网资讯 · 2024年4月5日

Docker 构建中的 Qt 缓存优化实践

在容器化构建中,缓存机制一直发挥着重要作用。每个命令(如 RUN、ADD 等)会形成一个独立的镜像层,未来的构建会复用这些层,只有发生变化时才会重新构建。除了镜像层缓存外,容器内对特定操作(例如编译源码)的缓存也同样重要。

为确保构建可复现并便于团队协作,我们在容器内搭建了一个 Qt 构建环境。由于 Qt 的编译时间较长,使用 ccache 可以显著提升构建速度。实施 ccache 需要将缓存目录从容器外部挂载到构建环境中。

如果你是单人开发,这样的设置通常已经足够。但若希望在团队内共享缓存,情形就会复杂一些。

实现共享缓存有多种途径。

最简单的方法是沿用前述做法,采用磁盘缓存并借助一些工具在 BuildKit 级别提升缓存命中率。随后将缓存打包、分发给团队成员。虽然这种方式不够优雅,但能完成任务。

若希望进一步自动化,可以将缓存的检索作为构建流程的一部分。例如可以采用如下思路:

RUN curl -o /tmp/build-cache.tgz https://some-domain.com/build-cache.tgz &&

tar xfz /tmp/build-cache.tgz -C /tmp &&

rm /tmp/build-cache.tgz

该做法虽然简洁,但意味着需要定期上传缓存以保持最新,而且需要一个存放缓存的地方(如 S3)。

是否有更无缝的做法?答案是肯定的:通过原生 Docker 技术,亦可更高效地实现缓存共享。

如同前文所示,我们可以利用多阶段构建在不同镜像之间传递数据。如果把缓存移入一个专用的缓存镜像,随后在构建过程中引入该镜像,缓存就可以自动获取。

操作思路很简单:在 Docker Hub 上创建两个不同的镜像,例如为缓存与构建环境分别命名。基于前文的思路,使用如下 Dockerfile 作为构建环境的基础镜像。

在 Dockerfile 中,将环境变量 CCACHE_DIR 设置为 /src/ccache。这一步告诉 ccache 缓存放在 /src/ccache。前一版本中,这一步只是把卷挂载进来;现在我们将其改为缓存位于镜像之外的 /src 目录,以便例如 /usr/ccache 这样的位置也能被使用。

现在就可以启动容器了:

$ docker run –rm -t
-v ~/tmp/qt-src:/src
-v ~/tmp/qt-build:/build
-v ~/tmp/ccache:/usr/ccache
Screenly-build-env

编译完成后,可以构建并推送缓存镜像。最终的 Dockerfile 可能如下所示:

FROM scratch

COPY ccache /ccache

要构建此镜像,请执行以下命令:

$ cd ~/tmp
$ docker build
-f /path/to/Dockerfile
-t Screenly/build-cache
$ docker push Screenly/build-cache

完成后,可以在构建环境镜像中引用该缓存层,例如在构建镜像时添加以下指令:

COPY –from=Screenly/build-cache /ccache /usr/ccache

下次重建 Screenly/build-env 时,Docker 将自动从缓存镜像中获取缓存。若需要刷新缓存,只需重新挂载对应的卷即可。