I recently came across a Dockerfile that was taking 23 minutes to build that looked something like the following:
... setup
mkdir app
WORKDIR app
RUN npm config set registry "<some npm registry url>"
RUN npm config set some_other_key "<some other value>"
RUN npm config set strict-ssl false
RUN npm install
RUN cd /app/server
RUN npm install
RUN cd /app
RUN npm run build:dist
RUN mv /app /app1
RUN mkdir /app
RUN mv /app1/dist /app/dist
RUN mv /app1/server /app/server
RUN rm -rf /app1
... rest
I erroneously assumed that the copying of files into and out of app to isolate the built files was what was causing the build to take so long. My first refactor cut the build by 80% to about 4.5 minutes, and included the following three changes:
- Combine a slew of RUN commands to reduce layers
- Update
.dockerignore
to cut down on files copied - Create multi-stage build to ensure I was only copying the output files I cared about.
Out of intellectual curiosity, I decided to try and isolate each of these three changes to better understand what their relative impact was on the build. Much to my surprise, over 90% of the gains experienced were related to reducing the number of layers being created.