使用glob模式的Docker COPY文件?

Fez*_*sta 13 docker dockerfile yarnpkg

我有一个由Yarn管理的monorepo,我想利用Docker缓存层来加速我的构建,这样做我想首先复制package.jsonyarn.lock文件,运行yarn install然后复制其余的文件.

这是我的回购结构:

packages/one/package.json
packages/one/index.js
packages/two/package.json
packages/two/index.js
package.json
yarn.lock
Run Code Online (Sandbox Code Playgroud)

这是Dockerfile的感兴趣部分:

COPY package.json .
COPY yarn.lock .
COPY packages/**/package.json ./
RUN yarn install --pure-lockfile
COPY . .
Run Code Online (Sandbox Code Playgroud)

问题是第3个COPY命令没有复制任何东西,我怎样才能达到预期的效果?

mbe*_*sky 19

有一个基于多阶段构建功能的解决方案:

FROM node:12.18.2-alpine3.11

WORKDIR /app
COPY ["package.json", "yarn.lock", "./"]
# Step 2: Copy whole app
COPY packages packages

# Step 3: Find and remove non-package.json files
RUN find packages \! -name "package.json" -mindepth 2 -maxdepth 2 -print | xargs rm -rf

# Step 4: Define second build stage
FROM node:12.18.2-alpine3.11

WORKDIR /app
# Step 5: Copy files from the first build stage.
COPY --from=0 /app .

RUN yarn install --frozen-lockfile

COPY . .

# To restore workspaces symlinks
RUN yarn install --frozen-lockfile

CMD yarn start
Run Code Online (Sandbox Code Playgroud)

Step 5该层高速缓存,即使在任何文件将被重用packages目录已经更改。

  • 你的第四层:“复制包包”破坏了缓存。因此,每次构建都会一遍又一遍地重新计算“COPY --from=0 /app .”。 (5认同)

Joo*_*ost 19

使用 Docker 的新 BuildKit 执行器,可以使用绑定挂载到 Docker 上下文中,然后您可以根据需要从中复制任何文件。

例如,以下代码片段将 Docker 上下文中的所有 package.json 文件复制到映像的目录/app/(以下示例中的 workdir)

不幸的是,更改挂载中的任何文件仍然会导致层缓存未命中。这可以使用@mbelsky 提出的多阶段方法来解决,但这次不再需要显式删除。

# syntax = docker/dockerfile:1.2
FROM ... AS packages

WORKDIR /app/
RUN --mount=type=bind,target=/docker-context \
    cd /docker-context/; \
    find . -name "package.json" -mindepth 0 -maxdepth 4 -exec cp --parents "{}" /app/ \;

FROM ...

WORKDIR /app/
COPY --from=packages /app/ .

Run Code Online (Sandbox Code Playgroud)

指定mindepth/maxdepth参数是为了减少要搜索的目录数量,可以根据您的用例进行调整/删除。

可能需要使用环境变量启用 BuildKit 执行器DOCKER_BUILDKIT=1,因为传统执行器会默默地忽略绑定安装。

有关 BuildKit 和绑定边界的更多信息可以在此处找到


Eri*_*kMD 8

要跟进@FezVrasta对我的第一个答案的评论,如果您无法枚举Dockerfile中所有受威胁的子目录,但是想要分两步复制所有文件以利用Docker缓存功能,则可以尝试以下解决方法:

  • 设计一个包装器脚本(例如,以bash package.json格式),将所需文件复制到.deps/具有类似层次结构的单独目录(例如)中,然后调用docker build …
  • 修改Dockerfile以预先复制(并重命名)单独的目录,然后调用yarn install --pure-lockfile

所有东西放在一起,这可能会导致以下文件:

### ./build.bash ###
#!/bin/bash

tag=copy-example:latest

rm -f -r .deps  # optional, to be sure that there is
# no extraneous "package.json" from a previous build

find . -type d \( -path \*/.deps \) -prune -o \
  -type f \( -name "package.json" \) \
  -exec bash -c 'dest=".deps/$1" && \
    mkdir -p -- "$(dirname "$dest")" && \
    cp -av -- "$1" "$dest"' bash '{}' \;
# instead of mkdir + cp, you may also want to use
# rsync if it is available in your environment...

sudo docker build -t "$tag" .
Run Code Online (Sandbox Code Playgroud)

### ./Dockerfile ###
FROM ...

WORKDIR /usr/src/app

# COPY package.json .  # subsumed by the following command
COPY .deps .
# and not "COPY .deps .deps", to avoid doing an extra "mv"
COPY yarn.lock .
RUN yarn install --pure-lockfile

COPY . .
# Notice that "COPY . ." will also copy the ".deps" folder; this is
# maybe a minor issue, but it could be avoided by passing more explicit
# paths than just "." (or by adapting the Dockerfile and the script and
# putting them in the parent folder of the Yarn application itself...)
Run Code Online (Sandbox Code Playgroud)


v.k*_*chy 5

官方Dockerfile参考中所述COPY <src> <dest>

COPY指令从中复制新文件或目录<src>,并将它们添加到路径中容器的文件系统中<dest>

对于你的情况

每个都可能包含通配符,并且将使用Go的filepath.Match规则进行匹配。

这是规则。它们包含以下内容:

'*'匹配任何非分隔符字符序列

因此,请尝试在您的模式中使用*而不是**

  • 知道如何在复制时使文件夹结构匹配吗?仅使用此命令即可将其全部转到当前目录 (14认同)
  • @GiovanniBassi,您评论中的脚本无法按预期工作。每个 .csproj 应复制到适当的子文件夹(例如 app/foo/foo.csproj)而不是根 app/foo.csproj (7认同)
  • 我刚刚用这个 dockerfile 试了一下,它可以工作:```FROM ubuntu WORKDIR /app COPY */*.csproj /app/ ``` 当我运行它时,这是正确的输出:```$ docker run - -rm -ti temp ls /app foo.csproj bar.csproj ``` (5认同)