PS: I am not a big fan of this approach. I prefer having separate dockerfiles for local and CI. That allows both of them to diverge independently, even though there might be some duplication. But if you want to have multiple builds with minor differences using the same dockerfile, you can consider this approach.
Docker Multi-Stage build is a powerful tool that can help you in a lot of different scenarios. The scenario we’re going to discuss today is actually quite simple: We want all our hosted environments and our local environments to run the app differently. For example, on the local machine, you would not want your Java build to be created everytime, or you might want to run your node app in watch mode.
Here is an example of how you can achieve it.
I’ve taken the simplest possible node app you can create. We have 2 ways to start the app —
start:local . Assume that
start runs the app in a standard manner, whereas
start:local runs it in watch mode.
You can use this Dockerfile to support both local and hosted environments —
FROM node:16 as local
COPY . .
RUN yarn install
RUN yarn build
CMD ["yarn", "start:local"]
FROM local as integration
CMD ["yarn", "start"]
With multi-stage builds, docker will use the entire Dockerfile to build the app, and the last
CMD will replace the one above it, unless we pass an intermediate stage as our target.
If we explicitly specify the target
local , it will then run the app in watch mode (
docker build --target local .
If we explicitly specify integration as our target, we’ll get the hosted version (
docker build --target integration .
If we don’t specify any target, it builds the app till the end, and the last
CMD replaces the previous one, so we get the hosted version (
docker build .
Important Note for Docker Compose
Docker Compose has a bug (or a feature), which will not give you the correct build even if you specify the correct intermediate target, unless you explicitly pass the
--build flag, which defeats the purpose. So if you’re using
docker-compose for local development, multi-stage builds could very well be meaningless.