Alec
Alec

Reputation: 653

Re-use Dockerfile with different base image

I have a Dockerfile that currently uses the node:10.21.0-buster-slim as its base. That works well for running in production since I get a nice small image (I'd rather not use Alpine since I've had issues with this code on Alpine previously and I'm already stuck running a MySQL image based on buster-slim in production). However, for development, it would obviously be nice to have an image with more tools for diagnosing issues that crop up (presumably based on either debian:buster or buildpack-deps:buster).

Is there some way I can run the same steps with two different base images without having to duplicate the Dockerfile contents? I assume the answer is yes with some multi-stage build magic, but I haven't figured out how that's supposed to work. In my dream world there are also a few minor differences between the dev and prod build steps (e.g. the --only=production argument to npm install, but I'm willing to sacrifice that if I have to to avoid maintaining two nearly identical Dockerfiles.

Upvotes: 3

Views: 1840

Answers (1)

wmorrell
wmorrell

Reputation: 5337

Multi-stage build magic is one way to do it:

ARG TARGET="prod"

FROM node:10.21.0-buster-slim as prod
# do stuff

FROM debian:buster as dev
# do other stuff, like apt-get install nodejs

FROM ${TARGET}
# anything in common here

Build the image with DOCKER_BUILDKIT=1 docker build --build-arg 'TARGET=dev' [...] to get the development-specific stuff. Build image with DOCKER_BUILDKIT=1 docker build [...] to get the existing "prod" stuff. Switch out the value in the first ARG line to change the default behavior if the --build-arg flag is omitted.

Using the DOCKER_BUILDKIT=1 environment flag is important; if you leave it out, builds will always do all three stages. This becomes a much bigger problem the more phases you have and the more conditional stuff you do. When you include it, the build executes the last stage in the file, and only the previous stages that are necessary to complete the multi-stage build. Meaning, for TARGET=prod, the dev stage never executes, and vice versa.

Upvotes: 3

Related Questions