Build a Docker Image just like how you would configure a VM

Intro

Containerization is the modern way of deploying applications as it provides an array of features and advantages over the old school deployment strategies. But this article is not about that. Rather, this article is about providing a starting point or a practical guide for a beginner to get started with containerization of their application.

Docker is the widely used tool in the industry when it comes to containerizing applications. Container Orchestration is however a different topic and I will cover that in the future. Dockerfile is the commonly used file format to build a docker image which then be used to run a container. Writing a Dockerfile is fairly easy.

Goal

Goal of this article is to introduce docker to absolute beginners and show them how easy it is to write a docker image just like how they would configure a VM. Please note that due to this reason I have used an anti pattern in this article instead of multi stage docker builds to make it less complex for the beginners.

Pre-requisites

You need to have installed Docker in your machine. Please follow these steps if you haven’t here.

Getting started

Let’s go ahead with a python example. I’m going to use a flask + react starter in python available here. Take a closer look at its readme.md file. It has all the instructions on how to run it in your local machine. Let’s containerize this.

First you need to clone this repository. This is required to get a copy of the source code in your local machine. If you are going to containerize your own code already available in your machine, then this step is not needed.

git clone https://github.com/bonniee/react-flask
cd react-flask

Okay, now we have cloned the repository and have changed the current directory into the root of the application. Now you have to create a new file called Dockerfile in this directory and open it with your favorite text editor.

In Docker, there are a lot of starter images, available in their image registry called Docker Hub which you can checkout here. Search for python and you will see a massive amount of results appearing up created by the community. Let’s use the official docker image for python, which often appears as the first result. You can check it out here in this link.

As you can see, there are many tags available in that image, each with a different version of the image. You can read more about docker tags here. We are going to use the alpine version and we are going to follow the instructions available in our readme.md to write the dockerfile.

Making Necessary changes in the codebase

Before we get started however, in order to make this application work with docker, we need to do a slight change in the codebase. Open app.py and replace line 9 with the following code.

app.run(host = ‘0.0.0.0’, debug=True)

Notice that I added the host to be 0.0.0.0 instead of the default127.0.0.1. This is required later to bind the application port in the container to the localhost of your machine. Whatever the language you use, don’t forget to change the host!

Writing the Dockerfile

Alright! now to get started properly, open Dockerfile and insert the following lines.

FROM python:3.6.5-alpine3.7
WORKDIR /usr/src/app
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txtCOPY . .

The word WORKDIR allows us to change the working directory. Then we use COPY command to copy the requirements.txt in our local machine to the image being built and then we run a pip install command to install the python dependancies required to this particular project. In the final COPY command we copy everything in the current repository available in our local machine into the work directory of the image being built.

Trial by Error on building custom images

Okay. Now comes the fun part. In a normal python application, this is all that you need to do. But this particular application requires NodeJS as well to build it’s javascript elements. Note that we are using a starter image built for python 3. How do we do this in a practical way? What I would usually do is build the above half written image and run a container for it and then ssh into it and try to install node in a trial by error method. Let’s try it out that way.

Type the following command in your terminal. This would build an image on your local machine tagged with the name flask-node using the Dockerfile we have written above.

docker build -t flask-node .

Now let’s quickly spin up a container from that image and go inside that container using sh. Note that I use /bin/sh here because the alpine image does not contain /bin/bash. This will depend upon the starter image you use for your dockerfile. — rm here tells docker to immediately remove the container as soon as you exit the sh shell.

docker run -it --rm flask-node /bin/sh

Now inside the container, let’s try to install node and webpack as they are needed to build our application. Now if you google on how to install nodeJS in an alpine image, there would be a lot of answers. We can try them out inside our shell and figure out exactly which one would work.

So let’s run the following commands in our shell and see.

apk update
apk add nodejs
node -v

This should install nodejs in your container and you would see that you have installed the latest version of node. Alright! now we have verified that this works, let’s add these commands to our Dockerfile. In the bottom of dockerfile add the above commands like this. When copying, please ignore the three dots on top.

...
RUN apk update
RUN apk add nodejs

Okay now for the final step. They have asked us to do an npm install and then a webpack global install in order to build the javascript frontend of the application. Let’s try it out in the container shell.

npm install
npm run build

The first line would install node dependancies required for the application and the second line would run a webpack build as the commands written in scripts key in the package.json. It should build successfully. So again since this worked, we would update our Dockerfile as following.

...RUN npm install
RUN npm run build

Now you can exit the shell by typing exit. Alright! to finish things off, we tell our dockerfile to start the python app at the start of a container. We do that by adding the following lines.

...EXPOSE 5000
CMD [ "python", "./app.py" ]

The EXPOSE command exposes the port 5000 to from the container as 5000 is the port which this application runs on.

Running the application

Okay! now let us build the image again.

docker build -t flask-node .

Now once it’s built successfully, let’s run the following command to spin up the container and bind the port 5000 in container to the localhost of your machine.

docker run -p 5000:5000 --name flask-app flask-node

Now the container will be running and if you navigate to http://localhost:5000 and your application will be running.

I hope this helped you to get started around Docker and build custom images on a trial by error basis as it feels just like configuring a virtual machine. I will post more advanced tutorials around docker with multi stage builds, mounts etc in the future.

src Build a Docker Image just like how you would configure a VM by Nilesh Jayanandana