I have a monorepo managed by Yarn, I'd like to take advantage of the Docker cache layers to speed up my builds, to do so I'd like to first copy the package.json
and yarn.lock
files, run yarn install
and then copy the rest of the files.
This is my repo structure:
packages/one/package.json
packages/one/index.js
packages/two/package.json
packages/two/index.js
package.json
yarn.lock
And this is the interested part of the Dockerfile:
COPY package.json .
COPY yarn.lock .
COPY packages/**/package.json ./
RUN yarn install --pure-lockfile
COPY . .
The problem is that the 3rd COPY
command doesn't copy anything, how can I achieve the expected result?
To follow-up @FezVrasta's comment to my first answer, if you can't possibly enumerate all the subdirectories at stake in the Dockerfile, but want to copy all the files in two steps to take advantage of Docker cache capabilities, you could try the following workaround:
package.json
files to a separate directory (say, .deps/
) built with a similar hierarchy, then call docker build …
yarn install --pure-lockfile
…All things put together, this could lead to the following files:
### ./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" .
and
### ./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...)