Lei Mao bio photo

Lei Mao

Machine Learning, Artificial Intelligence, Computer Science.

Twitter Facebook LinkedIn GitHub   G. Scholar E-Mail RSS

Introduction

Sometimes, when we would like to use arguments to build our Docker image from Docker files, we could use --build-arg to build the Docker image dynamically.


In this blog post, I am going to show how we could use --build-arg to dynamically select Docker base images and the caveats of doing so.

Example

Dockerfile

We have prepared a Dockerfile build-args.Dockerfile. The content of the Dockerfile is as follows.

ARG _UBUNTU_VERSION=18.04

FROM ubuntu:${_UBUNTU_VERSION}

ARG _CUDA_VERSION=10.0

RUN echo ${_CUDA_VERSION}
RUN echo ${_UBUNTU_VERSION}
RUN cat /etc/lsb-release

With ARG, we have prepared two arguments _UBUNTU_VERSION and _CUDA_VERSION with their default values set to 18.04 and 10.0, respectively.

Building Without Custom Arguments

$ docker build -f build-args.Dockerfile --no-cache --tag=ubuntu:custom .
Sending build context to Docker daemon  2.048kB
Step 1/6 : ARG _UBUNTU_VERSION=18.04
Step 2/6 : FROM ubuntu:${_UBUNTU_VERSION}
 ---> 4c108a37151f
Step 3/6 : ARG _CUDA_VERSION=10.0
 ---> Running in e8ea62c039fb
Removing intermediate container e8ea62c039fb
 ---> 9862cc2743d6
Step 4/6 : RUN echo ${_CUDA_VERSION}
 ---> Running in b89f1788f822
10.0
Removing intermediate container b89f1788f822
 ---> 31bd45aab0c4
Step 5/6 : RUN echo ${_UBUNTU_VERSION}
 ---> Running in 640da900d0e5

Removing intermediate container 640da900d0e5
 ---> ea9022c7619b
Step 6/6 : RUN cat /etc/lsb-release
 ---> Running in 352e5ba34e1d
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=18.04
DISTRIB_CODENAME=bionic
DISTRIB_DESCRIPTION="Ubuntu 18.04.2 LTS"
Removing intermediate container 352e5ba34e1d
 ---> 15df659b939f
Successfully built 15df659b939f
Successfully tagged ubuntu:custom

We could see that there are actually two scopes for the arguments. _UBUNTU_VERSION would not be available after the base image was built. But _UBUNTU_VERSION was definitely available before the base image was built because the image was “Ubuntu 18.04.2 LTS” which was exactly the same as our default value.

Building With Custom Arguments

$ docker build -f build-args.Dockerfile --build-arg _CUDA_VERSION=10.2 --build-arg _UBUNTU_VERSION=16.04 --no-cache --tag=ubuntu:custom .
Sending build context to Docker daemon  2.048kB
Step 1/6 : ARG _UBUNTU_VERSION=18.04
Step 2/6 : FROM ubuntu:${_UBUNTU_VERSION}
 ---> c6a43cd4801e
Step 3/6 : ARG _CUDA_VERSION=10.0
 ---> Running in b93c73bb14b1
Removing intermediate container b93c73bb14b1
 ---> ca1e8b65bf5b
Step 4/6 : RUN echo ${_CUDA_VERSION}
 ---> Running in 9546a32abbd4
10.2
Removing intermediate container 9546a32abbd4
 ---> 529e4f08ae49
Step 5/6 : RUN echo ${_UBUNTU_VERSION}
 ---> Running in 4353a17ec826

Removing intermediate container 4353a17ec826
 ---> a84f1b8dc62a
Step 6/6 : RUN cat /etc/lsb-release
 ---> Running in ac5adeb44920
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=16.04
DISTRIB_CODENAME=xenial
DISTRIB_DESCRIPTION="Ubuntu 16.04.6 LTS"
Removing intermediate container ac5adeb44920
 ---> 637557dc9ecd
Successfully built 637557dc9ecd
Successfully tagged ubuntu:custom

With --build-arg provided, we could see that the default argument values had been overwritten. However, _UBUNTU_VERSION, which was defined before the base image was built, was still not available after the base image was built.

Conclusions

Be aware of the scope of Docker building arguments.