Anton Krug
Anton Krug

Reputation: 1781

Build 2 images with Docker from a single Dockerfile while using different base images

I'm building 2 variants of the final container a full version and the slim version. And both variants build their containers in 2 steps:

  1. Get all the requirements for the full/slim version and make a base full/slim container
  2. Install the app on the full/slim base container and make the final full/slim container

Both full/slim builds have an identical second step, they just use a different base container. And I would like to generalize the second step so I wouldn't have two Dockerfiles containing the same content with just different FROM field.

So I wonder what would be the best approach to have the last step as a single Dockerfile which would generate 2 images and only switch between 2 different FROM. I was thinking about a couple of different ways doing it:

But I wonder, is there any better approach? Or do I miss something?

Upvotes: 10

Views: 9103

Answers (3)

Anton Krug
Anton Krug

Reputation: 1781

Other option is to generate multiple files from single file dynamically. Problem is that Docker 1.7.1 is not supporting --build-arg and to be sensible it's failing quietly

So if the Dockerfile needs to work on modern and older dockers then it need to comply with the 1.7.1 which is the newest which can run centos/rhel 6 (6.9 in my case).

I had to resort to use envsubst to replace the variables with the values before running the docker build. You can stream the result of the envsubst directly into docker or save it into the file first. Saving it into the file first will allow you to troubleshoot the input. For example one pitfal is to use all variables which in the end might try resolve more than you would prefer, I personally use envsubst always with argument listing what variables it can resolve so it will not try to resolve anything else.

Upvotes: 0

Tom Rijntjes
Tom Rijntjes

Reputation: 654

You could use build-time configuration with ARG.

FROM instructions support variables that are declared by any ARG instructions that occur before the first FROM. An ARG declared before a FROM is outside of a build stage, so it can’t be used in any instruction after a FROM. To use the default value of an ARG declared before the first FROM use an ARG instruction without a value inside of a build stage:

Dockerfile:

ARG imagename
FROM $imagename
RUN echo $imagename

Run with two different base images:

docker build --build-arg imagename=alpine .

outputs:

Step 1/3 : ARG imagename
Step 2/3 : FROM $imagename
latest: Pulling from library/alpine
ff3a5c916c92: Pull complete 
Digest: sha256:e1871801d30885a610511c867de0d6baca7ed4e6a2573d506bbec7fd3b03873f
Status: Downloaded newer image for alpine:latest
 ---> 3fd9065eaf02
Step 3/3 : RUN echo $imagename
 ---> Running in 96b45ef959c3

Removing intermediate container 96b45ef959c3
 ---> 779bfc103e9e
Successfully built 779bfc103e9e

Alternatively:

docker build --build-arg imagename=busybox .

results in:

Step 1/3 : ARG imagename
Step 2/3 : FROM $imagename
latest: Pulling from library/busybox
07a152489297: Pull complete 
Digest: sha256:141c253bc4c3fd0a201d32dc1f493bcf3fff003b6df416dea4f41046e0f37d47
Status: Downloaded newer image for busybox:latest
 ---> 8c811b4aec35
Step 3/3 : RUN echo $imagename
 ---> Running in 6027fe4f5b7b

Removing intermediate container 6027fe4f5b7b
 ---> 28640f123967
Successfully built 28640f123967

See also this blogpost for more ideas.

Upvotes: 9

Tarun Lalwani
Tarun Lalwani

Reputation: 146630

You can use ARG in FROM as well

ARG BASE_IMAGE
FROM $BASE_IMAGE
....

So pass the BASE_IMAGE as the build arg in your second part and do it that way. Multiple FROM in a dockefile is for a multistage build and is not applicable to this use case, because multistage docker files still yield one final container only

Upvotes: 4

Related Questions