When we talked about the Docker hub we mentioned a scenario wherein we would use an Ubuntu 16.04 image as our base image, update it and install Python 3 on it. In our last post on Docker images we successfully downloaded the Ubuntu 16.04 image that we will be using. In this post, we will explain how to create a new image using a Dockerfile by making changes to the base image.
We will not be going in-depth about all the configuration changes we can make to an image using a Dockerfile and will instead focus on applying some basic modifications.
Creating a dockerfile:
To keep things clean, I’ll be creating a new directory and will create our dockerfile in that directory.
[sahil@linuxnix ~]$ mkdir linuxnix-docker [sahil@linuxnix ~]$ cd linuxnix-docker/
Here is our dockerfile
[sahil@linuxnix linuxnix-docker]$ cat dockerfile FROM ubuntu:16.04 RUN apt-get update RUN apt-get install -y python3 [sahil@linuxnix linuxnix-docker]$
Looks simple, doesn’t it?
The FROM attribute denotes the base image to use for the creation of a new image using this dockerfile. We will be using out ubuntu 16.04 image. In some dockerfiles you might see FROM scratch written. This implies that the image was not created using a base image. Next, we have two RUN statements, one for the image update and another one for the python3 install. Each RUN statement will add a new layer to the image.
Build an image using dockerfile:
To build the image we will run docker build . within the directory where the dockerfile is located. In this we’ve named our dockerfile something other than dockerfile then we would type docker build <file name> to build the image.
[sahil@linuxnix linuxnix-docker]$ docker build . Sending build context to Docker daemon 2.048kB Step 1/3 : FROM ubuntu:16.04 ---> 13c9f1285025 Step 2/3 : RUN apt-get update ---> Running in 1fdb5c619482 Get:1 http://security.ubuntu.com/ubuntu xenial-security InRelease [109 kB] Get:2 http://archive.ubuntu.com/ubuntu xenial InRelease [247 kB] Get:3 http://security.ubuntu.com/ubuntu xenial-security/main amd64 Packages [894 kB] Get:4 http://archive.ubuntu.com/ubuntu xenial-updates InRelease [109 kB] Get:5 http://archive.ubuntu.com/ubuntu xenial-backports InRelease [107 kB] Get:6 http://archive.ubuntu.com/ubuntu xenial/main amd64 Packages [1558 kB] Get:7 http://security.ubuntu.com/ubuntu xenial-security/restricted amd64 Packages [12.7 kB] Get:8 http://security.ubuntu.com/ubuntu xenial-security/universe amd64 Packages [569 kB] Get:9 http://security.ubuntu.com/ubuntu xenial-security/multiverse amd64 Packages [6121 B] Get:10 http://archive.ubuntu.com/ubuntu xenial/restricted amd64 Packages [14.1 kB] Get:11 http://archive.ubuntu.com/ubuntu xenial/universe amd64 Packages [9827 kB] Get:12 http://archive.ubuntu.com/ubuntu xenial/multiverse amd64 Packages [176 kB] Get:13 http://archive.ubuntu.com/ubuntu xenial-updates/main amd64 Packages [1276 kB] Get:14 http://archive.ubuntu.com/ubuntu xenial-updates/restricted amd64 Packages [13.1 kB] Get:15 http://archive.ubuntu.com/ubuntu xenial-updates/universe amd64 Packages [974 kB] Get:16 http://archive.ubuntu.com/ubuntu xenial-updates/multiverse amd64 Packages [19.1 kB] Get:17 http://archive.ubuntu.com/ubuntu xenial-backports/main amd64 Packages [7942 B] Get:18 http://archive.ubuntu.com/ubuntu xenial-backports/universe amd64 Packages [8532 B] Fetched 15.9 MB in 5s (2710 kB/s) Reading package lists... Removing intermediate container 1fdb5c619482 ---> fac336606358 Step 3/3 : RUN apt-get install -y python3 ---> Running in 5dd689d49b7e Reading package lists... Building dependency tree... Reading state information... The following additional packages will be installed: dh-python file libexpat1 libmagic1 libmpdec2 libpython3-stdlib libpython3.5-minimal libpython3.5-stdlib libsqlite3-0 libssl1.0.0 mime-support python3-minimal python3.5 python3.5-minimal Suggested packages: libdpkg-perl python3-doc python3-tk python3-venv python3.5-venv python3.5-doc binutils binfmt-support The following NEW packages will be installed: dh-python file libexpat1 libmagic1 libmpdec2 libpython3-stdlib libpython3.5-minimal libpython3.5-stdlib libsqlite3-0 libssl1.0.0 mime-support python3 python3-minimal python3.5 python3.5-minimal 0 upgraded, 15 newly installed, 0 to remove and 5 not upgraded. Need to get 6438 kB of archives. ------------------------------------output truncated for brevity Fetched 6438 kB in 3s (1845 kB/s) Selecting previously unselected package libssl1.0.0:amd64. (Reading database ... 4777 files and directories currently installed.) Preparing to unpack .../libssl1.0.0_1.0.2g-1ubuntu4.15_amd64.deb ... Unpacking libssl1.0.0:amd64 (1.0.2g-1ubuntu4.15) ... Selecting previously unselected package libpython3.5-minimal:amd64. Preparing to unpack .../libpython3.5-minimal_3.5.2-2ubuntu0~16.04.5_amd64.deb ... Unpacking libpython3.5-minimal:amd64 (3.5.2-2ubuntu0~16.04.5) ... .. Setting up python3 (3.5.1-3) ... running python rtupdate hooks for python3.5... running python post-rtupdate hooks for python3.5... Setting up dh-python (2.20151103ubuntu1.1) ... Processing triggers for libc-bin (2.23-0ubuntu11) ... Removing intermediate container 5dd689d49b7e ---> e1c1d07a11b5 Successfully built e1c1d07a11b5 [sahil@linuxnix linuxnix-docker]$
This completes our image build. We’ll now explain the operations that were performed by the above command to result in the creation of a new image.
Three steps were involved in the process.
In step 1, the base image mentioned after the FROM attribute was identified. In case the base image was not present on our system then it would’ve been pulled from Docker hub.
In step 2, where we run apt-get update we see the following output before the command actually runs:
—> Running in 1fdb5c619482
This is a temporary container being created to run the command. This intermediate container gets terminated once the RUN command completes. After this, another intermediate container is created to run the python3 package install. This container also gets removed once the command completes. The intermediate containers are kept in cache for the duration of the concerned execution and we as users do not have access to them.
In the third and final step, the intermediate container layers get removed and our final image gets created. The image id of the container that gets built e1c1d07a11b5 is the final image id of our new container and we may verify the same in the docker images command output.
[sahil@linuxnix ~]$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE <none> <none> e1c1d07a11b5 About an hour ago 182MB ubuntu 16.04 13c9f1285025 2 weeks ago 119MB [sahil@linuxnix ~]$
This concludes our basic introduction on Dockerfiles. We hope that you found our discussion on Dockerfiles useful and we encourage you to try creating some images on your own.
Latest posts by Sahil Suri (see all)
- Docker networking basics explained - September 20, 2019
- How to push an image to Docker hub - September 18, 2019
- Ansible: insert a line after a string using lineinfile module - September 17, 2019
- Common Docker image and container management commands - September 16, 2019
- Docker Container life cycle explained - September 9, 2019