Docker None to Done

Subham Misra
7 min readApr 19, 2020

I recently joined NullCon2020, attended a training on Container Security and thus, got introduced to Docker, which is one of the most famous implementation of container technology these days. So, first of all why Containerization came in place?? To understand this, we must discuss about the challenges of traditional application development and hosting infrastructure.

Traditional application dev & hosting infra

This diagram represents a traditional infrastructure for developing and hosting a MERN (Mongo Express React Node) stack application.

Challenges:

  • Every component of the MERN stack depends on each other’s version and different libraries provided by hardware manufacturers and OS
  • So, every time some component or library gets a new version, compatibility issue arises
  • Also, each and every time a new developer joins the team, his/her development environment needs to be set up considering a complex list of dependencies
  • After development, application may not run in production environment due to library and dependency issues

Solution was indeed Containers. Containerize all application components and run each of them with its own libraries and dependencies in separate containers.

MERN stack app in Container

Containerization is not very new, linux containers like LXC and LXD were in use from a long ago. But, they were not that popular and Docker changed the game, it made containers manageable more than ever.

Features:

  • Docker has a client server architecture. Docker daemon or the server software gets installed on top of OS, just like any other application
  • Docker uses linux kernel features such as cgroups, namespace, SELinux/Apparmor and capabilities to isolate containers from host OS
  • These containers are basically runtime instance of an image. Images can be transferred between different docker installations. Images can be a bare-bone ubuntu kernel or nginx (any app) installed and configured on top of ubuntu kernel.
  • Docker containers are light-weight, fast, highly-scalable and easily deployable solution for modern web development ecosystem
  • Although Docker containers are isolated from each other, they share kernel of underlying OS
  • Each container have their own process, network and persistent storage (optional)
  • Since containers share OS kernel, it is not possible to run windows container in linux host machine. But it is possible to run linux container in windows host. In windows systems linux containers basically run in a linux Virtual Machine
  • Docker pulls image of a container from repository, known as ‘Registry’
  • There are two type of registry, public and private. The most popular public registry is Docker Hub. AWS, Azure, GCP and many other cloud providers have their own public and private registry.
  • Many organizations maintain their own private registry to modify images according to their own need. Insecure private registries have been compromised many a times in last few years..

Note: Docker is not meant for use in production. For production purpose, Kubernetes is used as an Orchestrator which in turn uses Docker as a container runtime.

Now a debate arises, which is better Docker Containers or Virtual Machines? let’s see a comparison between the both:

Container vs VM

It is clear that in terms of resource utilization, RAM consumption and Boot time, containers are way better than Virtual Machines, but when the question of isolation & security comes in picture, Virtual Machines win the battle. What is the solution then?? which one to use??

Hybrid Architecture:

When you want both, features of Containers and Security of VM, this hybrid solution is best suited.

Now, let’s talk about how Docker actually works…

  • Docker architecture has two parts, docker client and docker daemon (or server).
  • Docker client talks with docker daemon using a REST API. This communication uses Unix socket (named pipe in windows) or plain TCP socket or TLS socket.
  • Docker client takes command from user and sends it to the server. Server searches for images locally first, if not found it contacts registry for downloading the image.
Docker Architecture
  • Custom images can be created using Dockerfile. docker build command creates an image based on context of the Dockerfile
  • docker pull <name of image>command pulls specified image from registry.
  • docker imagescommand lists down all available images locally.
  • docker run <image name or image ID>command creates a container using the specified image.

Enough theories, let’s play with docker. To download and install docker in ubuntu, please visit this link.

After the setup is complete, run docker run hello-world command and see what happens.

There was no image named “hello-world” in my machine and hence, docker fetched it from Docker Hub registry. Now, run the command docker images

The listed images are present in my machine locally. Notice there are several fields named tag, IMAGE ID, CREATED and SIZE in the table. While pulling images from Docker Hub, if you don’t mention any version, the latest version of that image will get pulled and it will have a tag latest, otherwise the tag field will have the specified version. Every image will have their unique IMAGE ID and SIZE field indicates the size of the image.

Now, let’s create an ubuntu container and access it’s shell.

In the command, -it gives us an interactive console and parameter /bin/bash, actually tells docker to provide us a bash shell. You can see, most of the utility commands or binaries like ifconfig , ip addr is not installed, but apt is there, so you can basically install any binary you want. Now if you run docker ps -a you will see a list of currently running and exited containers.

You can see different fields in this table. The command field tells what command we used as parameter while running those containers. And the last column NAME actually randomly names each container based on some algorithm.

These containers are not stateful, means if we launch an ubuntu container and install python in it, python will be accessible as long as the container is running. As soon as you exit the container, and relaunch the container using exact same image, python will not be installed there. This is because, docker containers lack a persistent storage layer. We can add file or folders of host system as a volume, bind or a tmpfs mount with a container and add a persistent storage layer to the container.

Let’s see how a file from host system can be mounted as a volume in docker container.

Basically, we are using -v switch to add the volume.

We can use docker inspect <container ID or Image ID> to get every details about the container or image such as ip, volumes, port etc. Containers are assigned with a private ip using DHCP protocol, and due to this reason even if you expose a port while running the container, the application running in the container will not be accessible using the host ip. To enable accessing the containerized application using host ip, we have to publish the container port to a host port. Let’s see how this is done.

Here, at first we have run the nginx container in detached mode using -d switch, and by default nginx runs on port 80. Running command docker inspect , we get the ip of the nginx container and when we try to access nginx home page using this ip and port 80, we successfully fetch the homepage. But from localhost it fails, means it cannot be accessed using host ip. After this, we have published container’s port 80 to host’s port 3000 using -p switch. And now homepage is accessible through host ip.

Hope this is helpful, we will discuss about dockerfile and docker breakout in upcoming posts.

--

--