Dockerfile:COPY文件夹如果存在(有条件的COPY)

Dockerfile: COPY folder if it exists (conditional COPY)

我有用于 NodeJS 应用程序的 Dockerfile,需要在容器内复制 migrations、seeds 文件夹。但问题是我们所有的应用程序都使用相同的 Dockerfile,但并非所有应用程序都使用 DB 并具有 migrations、seeds.

Docker 文件:

...
# * package json, to be able run `npm run ...`
COPY ./package.json /app/
# * migrations, seeds if they exist
COPY ./migrations/ /app/migrations/
COPY ./seeds/ /app/seeds/
...

一切正常,但如果我们没有 migrations 文件夹,我们将得到:

 => CACHED [app 4/9] COPY --from=builder /app/node_modules /app/node_modules                                                                                                                                                                                              0.0s
 => CACHED [app 5/9] COPY --from=builder /app/dist /app/dist                                                                                                                                                                                                              0.0s
 => CACHED [app 6/9] COPY ./package.json /app/                                                                                                                                                                                                                            0.0s
 => ERROR [app 7/9] COPY ./migrations/ /app/migrations/                                                                                                                                                                                                                   0.0s
------
 > [app 7/9] COPY ./migrations/ /app/migrations/:
------
failed to compute cache key: "/migrations" not found: not found

最好的方法是什么?

TL;DR;

COPY ./migration[s]/ /app/migrations/

更详细的回答

我们可以使用 glob 模式来实现这种行为,Docker 如果找不到任何有效源也不会失败,有 3 个最常用的 glob:

  1. ? - 任意字符,不匹配空字符
  2. * - 任意长度的任意字符序列,匹配空字符
  3. [abc] - 要匹配的字符序列,就像 ? 一样,但它只匹配括号中定义的字符

所以有3种方法可以解决这个问题

  1. COPY ./migration?/ /app/migrations/ - 也将匹配 migrationZmigration2 等等..
  2. COPY ./migrations*/ /app/migrations/ - 还将匹配 migrations-coolmigrations-old
  3. COPY ./migration[s]/ /app/migrations/ - 将匹配 only migrations,因为我们使用的是匹配 1- 中的任何字符的 glob项目序列 [s] 并且除了字母“s”
  4. 什么都不能

关于 glob 的更多信息: https://en.wikipedia.org/wiki/Glob_(programming)

作为替代解决方案,我建议您创建多个 docker 继承自公共基础图像的图像。基本图像包含相互的内容,子图像具有特定要求,如您的情况,具有 migrationsseeds 文件夹。

我认为在 docker 图像中使用条件不是图像的目的,因为它是为了创建一个在所有客户端之间共享的公共状态。