Reputation: 1781
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:
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
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
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
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