Welcome to the second part of our Docker tutorial series. In this part we will build a Docker image by writing a very simple Dockerfile and we will publish the image on Dockerhub. This very simple example will make it easy for you to understand the steps rather than involving you in understanding a complex Dockerfile at this stage!
In part one of this tutorial, we created our first Docker container and it was based on Alpine Linux image. We’ll resume exactly where we concluded the previous part. Running the following command in terminal creates and runs an alpine container (after pulling the image from Dockerhub, if it doesn’t already exist in local repository).
> docker container run -it alpine /bin/sh
After running the container, this command also moves us into the shell of container. As we saw in first part we can execute the standard Linux file system commands like
mkdir and so on.
However, as this is a minimal Linux image, it doesn’t come shipped with many tools/packages pre-installed. Instead we can decide which tools are required for our application and we can install only those tools or packages so avoiding the useless stuff and keeping the size of our image minimal.
Lets try something… in your container’s shell, try to execute
curl does not come preinstalled in
alpine image so you’ll get the error
curl not found.
> curl https://google.com
As this is a (containerised) Linux machine, you should be able to install any package and tool with normal Alpine Linux commands. Alpine Linux uses
apk tool as its package manager. As you are still inside your container shell, execute the following command.
> apk add curl
So this results in successful installation of curl. Now execute
curl https://google.com, this time it will not fail.
Consider a simple scenario that all your team of five persons needs is a lightweight
alpine machine which has
curl installed. Let’s also assume that there is no such existing image available on Dockerhub. The solution is pretty simple that you will build a Docker image yourself and your team members will use your new Docker image 🙂
Build a new Docker image using Dockerfile
To build a new Docker image, you first need to be able to define its structure. Considering the scenario stated above, we need a container image that has following two characteristics…
- It should be a light-weight
- It should have curl enabled.
From the discussion so far, we know following already…
- The Linux
alpineimage doesn’t come shipped with
- The Linux
alpineimage does have
apkpackage manager tool available.
- When we executed
apk add curl, it installed
curlsuccessfully in the
Based on this information, let’s write instructions in a Dockerfile which will be used to build our new Docker image! Do following steps:
- Create a folder
curl-alpine(or any other suitable name)
- Create a file named
Dockerfileinside that folder and paste following code in that file.
- While you are inside
curl-alpinefolder, execute the following command (we will explain it in a while).
> docker build -t curl-alpine:latest .
Awesome! You have built your own first Docker image. Before we move ahead, lets see what does this build command do!
docker build command
Let’s explain the command
docker build -t curl-alpine:latest .
docker, you know, is the utility/tool.
buildis the name of command
-tis the flag which can be used to specify a name for the image and optionally a tag. In our command, we have named the image
curl-alpineand tagged it
latest. The syntax is
.is the build context. It must be path to a directory. This
.here implies that the build context is current directory. If your
Dockerfileis somewhere else, you can specify the path to the directory which contains it.
Our example is so basic so our
Dockerfile contains only two commands. See below the output of
The output clearly shows where the two steps of our Dockerfile. You can see that
Step 1/2 : FROM alpine:latest results in just linking to the existing image that we downloaded in first part.
The second step (
Step 2/2 : RUN apk add --no-cache curl) involves the downloading and installing
curl as well as its dependencies.
Now any container created using our
curl-alpine image will have pre-installed
curl unlike the official
The beauty of Docker:
The beauty of Docker lies in the fact that it builds images layer by layer. Each command in Dockerfile is a layer for which an intermediary image is created. As you have seen in the output of
docker build command, it didn’t pull the
alpine image again instead it referenced to the existing image in local repository. This results not only in faster processing of
build command but it also saves the disk space by avoiding multiple copies of same image.
This is a very basic example but in next tutorials you’ll see Docker files with more commands (i.e. more layers) and you’ll recognise that how useful is this layered structure.
Running the container
Good job so far! Next step is to run the container which is same as we did in first part. Run the following command…
> docker container run -it curl-alpine /bin/sh
So you are inside the shell of your containerised
Alpine Linux machine which is unlike the one we created in first part in that that it already has
curl installed because we made
curl part of our
curl-alpine image using the commands we listed in
Dockerfile. Now if you try to execute following command,
> curl https://google.com
This time it will run successfully without having to install
curl manually. So you’re good to share your
Dockerfile with your team members and they can simply
docker build and
docker run to have this simple identical machine across the team.
You can use command
docker container ls to see the list of containers running (use flag
-a to see stopped ones also). You can see that the new container is built using our own image
docker container run command
Let’s see what are the components of command
docker container run -it curl-alpine /bin/sh
dockeris the utility/tool.
containerwhich is a parent command, you can think of it as a namespace for other commands which are related to containers like
runis the command to run a container.
-itthese are two flags together;
-t(allocate a pseudo terminal).
curl-alpineis the name of Docker image which is used to create this container. (We have built this image in the section above: Build a new Docker image using Dockerfile).
/bin/shwe can specify any command here that we want to execute after container runs.
/bin/shopens the shell of container. You can use any valid command, for example try following.
> docker container run -it curl-alpine curl https://google.com
As you see, this time the control does not shift inside the container’s shell but instead the
curl command gets executed inside and the output is displayed in the host shell.
Publishing your Docker image to Dockerhub
You can push your Docker images to Dockerhub and those will be accessible to the people all over or even if you want to share within your team Dockerhub is a good central place. Let us now push the image we created in section above (Build a new Docker image using Dockerfile).
To push a Docker image to your Dockerhub account, you need to name your image prefixed with your account name and then push it. For example my Dockerhub account name is atifazad so the commands for me are as follows (replace atifazad with your account name):
> docker tag curl-alpine atifazad/curl-alpine:latest > docker push atifazad/curl-alpine
When everything goes good, these commands result in similar to…
On Dockerhub, you can view this image here: https://hub.docker.com/r/atifazad/curl-alpine and you can see the command to pull this image.
docker pull atifazad/curl-alpine
Now with your image available on Dockerhub, your teammates don’t have to take the
build the image. Instead they can simply execute
docker pull <your_dockerhub_username>/curl-alpine and then
docker container run as explained above 🙂
This tutorial explains how to build and publish your own Docker image with a very simple
Dockerfile example. When you have to create a Docker setup for your projects you’ll follow similar steps but with a more detailed and sophisticated
Dockerfile and probably also using
docker-compose to support your development environment.
In the next tutorial in this series, we will build upon what we have learned so far and we will Dockerise a simple application. Till then good bye 🙂