Container-ization of the Services

This entry is part 5 of 12 in the series Kubernetes and everything else

Kubernetes is a container orchestrator, or how you are more likely to read about it, Kubernetes does Container Orchestration, a term that we will read about in upcoming articles, but now without further due let’s create Containers Images for our Services.

Containerizing the React Application (Docker intro)

A Dockerfile contains all the instructions needed to build a container. And it starts with a base image and follows up with a sequence of instructions on how to build a container image, that fits your needs. Before we get started defining the Dockerfile, let’s remember the steps we took to serve static files with nginx:

  1. Build the static files (npm run build)
  2. Startup the nginx server
  3. Copy the contents of the build folder from your sa-frontend project to nginx/html.

In the next section, you will notice parallels on how creating a Container is similar to what we did during local React setup.

Defining the Dockerfile for SA-Frontend

The instructions in the Dockerfile for the SA-Frontend is only a two-step task, and that is because the Nginx Team provided us with a base image, which we will use to build on top of. The two steps are:

  1. Start from the base Nginx Image
  2. Copy the sa-frontend/build directory to the containers nginx/html directory.

Converted into a Dockerfile it looks like this:

FROM nginx
COPY build /usr/share/nginx/html

Isn’t it amazing, it’s even humanly readable, let’s recapitulate:

Start from the nginx image (whatever the guys did over there) and copy our build directory to the nginx/html directory in the image. That’s it! And how do I know where to copy the build files? Because it was documented in the nginx image.

The Dockerfile defines how to build the container image, in the next sections we will build and push the image to the Container Registry (DockerHub).

Building and Pushing the container

Before we can push our image we need a Container Registry to host our images. Docker Hub is a free cloud container service that we will use for this demonstration. You have two tasks before continuing:

  1. Register to the Docker Hub.
  2. Login by executing the below command in your Terminal:
docker login -u="$DOCKER_USERNAME" -p="$DOCKER_PASSWORD"

After completing the above tasks navigate to the directory sa-frontend and execute the below command (replace $DOCKER_ID_USER with your docker hub user)

$ docker build -f Dockerfile -t $DOCKER_ID_USER/sentiment-analysis-frontend .

We can drop -f Dockerfile because we are already in the directory containing the Dockerfile.

To push the image, use the docker push command:

$ docker push $DOCKER_USER_ID/sentiment-analysis-frontend

Verify in your docker hub repository that the image was pushed successfully.

Running the container

Now the image in $DOCKER_USER_ID/sentiment-analysis-frontend can be pulled and run by anyone. To pull:

 $ docker pull $DOCKER_USER_ID/sentiment-analysis-frontend

To run:

 $ docker run -d -p 80:80 $DOCKER_ID_USER/sentiment-analysis-frontend

The 80:80 is confusing, let’s elaborate it:

  • The first 80 is the port of the host (i.e. my computer)
  • The second 80 stands for the container port to which the calls should be forwarded.

 

Fig. 1. Port Mapping of Host to Container

It maps from <hostPort> to <containerPort> meaning that calls to host port 80 should be mapped to the port 80 of the container, as shown in figure 1.

 

Because the port was run in the host (your computer) in port 80 it should be accessible on the localhost:80, or if you do not have native docker support you can open the application in <docker-machine ip>:80.

To find your docker-machine ip execute docker-machine ip 😉 If you set up everything correctly then you should be able to access the react application in that endpoint.

The Dockerignore

We saw earlier that building the image for SA-Frontend was slow. That was the case because of the huge build context that had to be sent to the Docker Deamon. In more detail, the build context represents all the data in the directory of the Dockerfile that will be needed to build the image. And in our case, the SA Frontend included the following folders:

sa-frontend:
|   .dockerignore
|   Dockerfile
|   package.json
|   README.md
+---build
+---node_modules
+---public
\---src

But the only data we need is in the build folder, then uploading anything else will be a waste of time and we can improve our build time by dropping the other directories, and that’s where .dockerignore comes into play, for you it will be familiar because it’s like .gitignore, i.e add all directories that you want to ignore in the .dockerignore file, as shown below:

node_modules
src
public

And another important thing is that the .dockerignore file should be in the same folder as the Dockerfile. (i.e. it should be in the build context).

Now building the image takes only seconds.

Conclusion

We learned about the Dockerfile, how to use it to build an image, and the commands to push it to the Docker registry. Additionally, we investigated on how to reduce the number of files sent to the build context by ignoring useless files. In the next article, we will build and push the image for the Java Application and the Python Application.

I encourage you to go through the next article where we will cover containerizing the two applications, a couple of more docker features, and in the end testing that everything works together.

Container-ization of everything else >>
If you enjoyed the article, please share and comment below!
  • Harnit Singh

    Great post! One thing you could potentially do to make the first container deployment easier is to volume mount the build folder to the default nginx container without creating the Dockerfile – e.g. docker run –name docker-nginx -p 80:80 -v local/folder/build:/usr/share/nginx/html -d nginx

    Though I realize it may be something you want people to get their hands dirty with. Otherwise, fantastic post and really easy to follow along.

    • Rinor Maloku

      Thanks Harnit!
      Yeah, as the main goal of the series is to explain Kubernetes, adding Container Volumes to the list made me go into details that would be out of the scope. (And mounting the volume would become more complex in the later phases, i.e. sidecar to pull the repository build the app and supply the data in a external volume shared with the nginx container puhh :p )

  • Marcello Romani

    > without further due
    It’s “without further ado” 🙂