Home > front end >  Dockerfile: COPY folder if it exists (conditional COPY)
Dockerfile: COPY folder if it exists (conditional COPY)

Time:11-25

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?

CodePudding user response:

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.

CodePudding user response:

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)

  • Related