6

I have Dockerfile for NodeJS application and need to copy migrations, seeds folders inside container. But the problem is that all our applications use same Dockerfile, but not all of them work with DB and have migrations, seeds.

Dockerfile:

...
# * 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/
...

Everything work ok, but if we don't have migrations folder we will get:

 => 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

What is the best way to do it?

orlovw
  • 405
  • 3
  • 11
  • Does this answer your question? [Conditional COPY/ADD in Dockerfile?](https://stackoverflow.com/questions/31528384/conditional-copy-add-in-dockerfile) – Hans Kilian Nov 24 '21 at 13:07
  • @HansKilian sort of, but it's about files not folders + `Make sure foo exists`, this will work even if `foo` doesn't exist – orlovw Nov 24 '21 at 13:14

2 Answers2

18

TL;DR;

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

More detailed answer

We can use glob patterns to achieve such behavior, Docker will not fail if it won't find any valid source, there are 3-most used globs:

  1. ? - any character, doesn't match empty character
  2. * - any characters sequence of any length, matches empty character
  3. [abc] - sequence of characters to match, just like ?, but it matches only characters defined in brackets

So there are 3 ways to solve this

  1. COPY ./migration?/ /app/migrations/ - will also match migrationZ, migration2 and so on..
  2. COPY ./migrations*/ /app/migrations/ - will also match migrations-cool, migrations-old
  3. COPY ./migration[s]/ /app/migrations/ - will match only migrations, because we are using glob that is saying match any character from 1-item sequence [s] and it just can't anything except letter "s"

More about globs: https://en.wikipedia.org/wiki/Glob_(programming)

orlovw
  • 405
  • 3
  • 11
  • 3
    For some reason I get an error : Step 3/12 : COPY ./migration?/ /app/migrations/ COPY failed: no source files were specified Docker version 20.10.7, build f0df350 – Eyal Solomon Mar 17 '22 at 18:43
  • And square brackets are working? – orlovw Mar 18 '22 at 20:41
  • @EyalSolomon I see this failed message too when building in Jenkins. Locally, even though it doesn't copy, I still am amble to produce an image and use it. – JoshGough Jan 05 '23 at 15:43
  • Not working for me : => ERROR [ 6/16] COPY ./bdoc-portal/apps/_shell/dist*/ /bdoc-portal/apps/_shell/dist/ 0.0s ------ > [ 6/16] COPY ./bdoc-portal/apps/_shell/dist*/ /bdoc-portal/apps/_shell/dist/: ------ lstat /var/lib/docker/tmp/buildkit-mount3057941185/bdoc-portal/apps/_shell: no such file or directory – Olivier Masseau May 24 '23 at 17:33
  • This worked for me on `Docker version 24.0.2, build cb74dfc` and `Docker Compose version v2.18.1`. – Raphael Setin Jun 23 '23 at 20:29
3

As an alternative solution I would advice you to create several docker images that inherit from a common base image. The base image is holding what is mutual and the child images having specifics requirements as in your case having the migrations and seeds folders.

Having conditionals in docker images is in my opinion not what an image is intended to do, as it is to create a common state shared between all clients.

sitick
  • 86
  • 8