在docker中使用buildkit并运行--mount,为什么cabal install下载缓存的包?

问题描述 投票:0回答:1

我正在创建一个可以构建 haskell 程序的 Dockerfile。 Dockerfile使用ubuntu focus作为基础镜像,安装ghcup,然后构建haskell程序。我这样做的原因有很多;它可以支持低配置的 CI 环境,并且可以帮助尝试构建复杂项目的新开发人员。

为了加快构建时间,我使用 docker v20 和 buildkit。我有一系列这样的事件(这是一个很长的文件,但此摘录是相关部分):

# installs haskell
WORKDIR $HOME
RUN git clone https://github.com/haskell/ghcup-hs.git
WORKDIR ghcup-hs
RUN BOOTSTRAP_HASKELL_NONINTERACTIVE=NO ./bootstrap-haskell
#RUN source ~/.ghcup/env  # Uh-oh: can't do this.
# We recreate the contents of ~/.ghcup/env
ENV PATH=$HOME/.cabal/bin:$HOME/.ghcup/bin:$PATH

# builds application
COPY application $HOME/application
WORKDIR $HOME/application
RUN mkdir -p logs
RUN --mount=type=cache,target=$HOME/.cabal \
    --mount=type=cache,target=$HOME/.ghcup \
    --mount=type=cache,target=$HOME/application/dist-newstyle \
    cabal build |& tee logs/configure.log

但是当我在

application
中更改一些非代码文件(例如 README.md),并构建我的 docker 映像时...

DOCKER_BUILDKIT=1 docker build -t application/application:1.0 .

...这需要相当多的时间,并且

cabal build
的输出包括大量
Downloading [blah]
以及来自 cabal 安装的
Building
/
Installing
/
Completed
消息。

但是,当我进入容器并输入

cabal build
时,速度要快得多(它已经构建好了):

host$ docker run -it application/application:1.0
container$ cabal build  # this is fast

我希望它在之前的情况下也能一样快。由于我并没有真正更改代码文件,并且依赖项都已下载,而且由于我使用的是

RUN --mount

是否有我的

--mount=type=cache
条目未覆盖的文件?是否有一个包注册表文件需要包含在其自己的
--mount=type=cache
行中?据我所知,我的构建应该几乎是即时的,而不是需要几分钟才能完成。

docker haskell cabal-install docker-buildkit
1个回答
0
投票

几年后,但我想我已经有了答案。

因此 OP 方法的问题之一是,在这种情况下 $HOME 不会被任何东西取代。因此,缓存的目标目录包括一个字面意思为

$HOME
的文件夹。

下一步是获取正确的文件夹,您可以通过检查使用“错误”配置生成的图像来完成此操作。如果你使用像dive这样的工具,你可以看到该层的变化包括:

drwx------         0:0      14 MB  └── root
drwxr-xr-x         0:0     461 kB      ├── .cache
drwxr-xr-x         0:0     461 kB      │   └── cabal
drwxr-xr-x         0:0      11 kB      │       ├── logs
-rw-r--r--         0:0      485 B      │       │   ├── build.log
drwxr-xr-x         0:0      11 kB      │       │   └── ghc-9.8.4
-rw-r--r--         0:0      11 kB      │       │       └── text-2.1.2-030cac37f8d77dcf6263d580f
drwxr-xr-x         0:0     450 kB      │       └── packages
drwxr-xr-x         0:0     450 kB      │           └── hackage.haskell.org
drwxr-xr-x         0:0     450 kB      │               └── text
drwxr-xr-x         0:0     450 kB      │                   └── 2.1.2
-rw-r--r--         0:0     450 kB      │                       └── text-2.1.2.tar.gz
drwxr-xr-x         0:0      13 MB      └── .local
drwxr-xr-x         0:0      13 MB          └── state
drwxr-xr-x         0:0      13 MB              └── cabal
drwxr-xr-x         0:0      13 MB                  └── store
drwxr-xr-x         0:0      13 MB                      └── ghc-9.8.4-1b19
drwxr-xr-x         0:0        0 B                          ├── incoming
-rw-r--r--         0:0        0 B                          │   └── text-2.1.2-030cac37f8d77dcf6
drwxr-xr-x         0:0      14 kB                          ├── package.db
-rw-r--r--         0:0     8.6 kB                          │   ├── package.cache
-rw-r--r--         0:0        0 B                          │   ├── package.cache.lock
-rw-r--r--         0:0     5.1 kB                          │   └── text-2.1.2-030cac37f8d77dcf6
drwxr-xr-x         0:0      13 MB                          └── text-2.1.2-030cac37f8d77dcf6263d
-rw-r--r--         0:0      497 B                              ├── cabal-hash.txt
drwxr-xr-x         0:0      13 MB                              ├── lib
drwxr-xr-x         0:0     2.5 MB                              │   ├── Data
drwxr-xr-x         0:0     2.1 MB                              │   │   ├── Text
-rw-r--r--         0:0      12 kB                              │   │   │   ├── Array.dyn_hi
-rw-r--r--         0:0      12 kB                              │   │   │   ├── Array.hi
(more changes omitted)

通过这个我们可以看到文件被缓存的实际位置是

/root/.cache/cabal
/root/.local/state/cabal/store
。 或者至少,在 GHC 和 cabal-install 的配置中就是这种情况,在这个例子中,我使用
haskell:9.8.4
作为基础镜像。

考虑到这一切,这里是一个完整的、多阶段的 Dockerfile,它利用构建缓存(可执行文件称为

example
):

FROM haskell:9.8.4 as builder

WORKDIR /app

COPY . .
RUN --mount=type=cache,target=/root/.local/state/cabal/store \
    --mount=type=cache,target=/root/.cache/cabal \
    --mount=type=cache,target=./dist-newstyle \
    cabal update && \
    mkdir bin && \
    cabal install --install-method=copy --installdir=./bin

FROM debian:12-slim
COPY --from=builder /app/bin/example /usr/local/bin/
CMD ["example"]
© www.soinside.com 2019 - 2024. All rights reserved.