Getting Started with Docker: A Beginner's Guide

What is Containerization?

Containerization is the process of packaging your application code into container along with its dependencies so, it can run quickly and reliably from one computing engine to another. The docker image is light weight, standalone and an executable package of software with all the required libraries, code, runtime system and settings to run the application.

Now, Containers and Virtual Machines serve similar purposes but there are few differences, let's understand those key distinctions.

Container Vs Virtualization

Isolation

Virtual Machines: Provides complete isolation from the host OS and other VMs

Containers: These offer light weight isolation from the host and other containers but don't provide strong security boundaries as VMs. For security, we can use Hyper-V isolation method to isolate each container in a VM.

Operating System

Virtual Machines: Run a complete OS including its Kernel, which requires more system resources.

Containers: Run only user mode portion of the OS. We can also modify that as per our requirement and include only which services are required.

Deployment

Virtual Machines: Deploys single VMs with the help of tools like Windows Admin Center, Hyper-V Manager, or PowerShell.

Containers: Deploys containers using Docker via command line or multiple containers using orchestrator like AWS ECS, EKS and so on.


Till now, we grasped the concept of Containerization and how it differs from VM.
Let's deep dive into Docker and its use in Containerization.

What is Docker?

Docker is an open-source platform used to automate the deployment, scaling and managing of the applications. It does this process through containerization, as discussed above, containerization helps to package your application with all required services, dependencies in a portable container and is light weight.

Docker Architecture

Docker uses a Client-Server architecture. First, the client talks to the docker daemon, which helps in building, running and distributing the docker containers. Docker client runs with docker daemon on the same system or can connect remotely as well. The interaction of docker client and docker daemon is done with the help of REST API over a UNIX socket or a Network.

Docker Client

Docker client is the most primary way a user can interact with docker. Using of commands on CLI such as docker run, docker build, and so on. Then the client sends these commands to dockerd (Docker Daemon) which carries them out. These docker commands uses the docker API and the client can communicate with more than one daemon.

Docker Daemon

The Docker daemon (dockerd), processes Docker API requests from docker client and handles Docker objects like images, containers, networks, and volumes. Additionally, the daemon can interact with other daemons to manage Docker services.

Docker Registry

A Docker registry is a storage system for Docker images. Docker Hub, a popular registry platform, allows you to push (upload) your own images and pull (download) publicly available images. We can have private and public registries.

Docker Desktop

Docker Desktop, an application - can be installed for any OS environment (MAC, Windows, Linux), which enables to build and share containerized applications and microservices. Docker Desktop includes - docker daemon, docker client, docker compose, docker content trust, Kubernetes, and Credential helper. For more detailed information on this, refer Docker Desktop.

Docker Image

A Docker Image is a read-only template that contains instructions to create a Docker Container. We can either build your own image by writing a Dockerfile or can also use the available images from docker registry. We can also publish our own created images on docker registry publicly for others to use.

Dockerfile

Dockerfile is a file in which you provide instructions to build your Docker Image. To build image, we can create a Dockerfile with its given syntax to define the steps required to build an image and run it. Each instruction in Dockerfile creates a layer in image, hence, when we make any new changes and rebuild the docker image, it will rebuild only new changes layers. Therefore, docker images are light weight and fast comparatively.

Docker Process

As discussed above in the docker architecture, the process of Docker involves three major stages: Client -> Daemon -> Registry.

  • docker build: This helps to build a docker image from a Dockerfile.

  • docker run: This helps to run the container from docker images.

  • docker push: This helps to push the container image to the docker registry.


So, till now we have understood all the pre-requisites and terminology of Docker.
It's time to get hands-on Docker!

Install Docker

  1. Download Docker Desktop Installer from official docker site.

  2. After downloading, click on the Docker Application and unpack the files and let it get installed. For more detailed steps ref docker doc (for windows).

  3. To verify if docker is installed on your system, you can run docker -v in your command prompt.

C:\Users\krunali>docker -v
Docker version 27.0.3, build 7d4bcd8

Note: Before you start with any docker commands, make sure your Docker Engine is running on your system.

For Instance, when you try to execute any docker command WITHOUT running Docker Engine, you will get to see this error. Denied permission, as Docker Daemon is not running.

C:\Users\kjain53>docker run hello-world
docker: error during connect: in the default daemon configuration on Windows, the docker client must be run with elevated privileges to connect: Head "http://%2F%2F.%2Fpipe%2Fdocker_engine/_ping": open //./pipe/docker_engine: The system cannot find the file specified.
See 'docker run --help'.

To overcome this, make sure Docker Engine and Daemon is running on your system.
To do so, just start your downloaded Docker Desktop Application and you should be good to run "hello-world" container.

After running Docker Daemon, we can expect this as our output:

C:\Users\krunali>docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
c1ec31eb5944: Pull complete
Digest: sha256:1408fec50309afee38f3535383f5b09419e6dc0925bc69891e79d84cc4cdcec6
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

Now, you are all set to play with Docker!


How to write a Dockerfile?

Here is a basic Dockerfile where, we are using Python runtime as our base image.

# Use an official Python runtime as a parent image
FROM python:2.7-slim
# Set the working directory in the container
WORKDIR /app
# Copy the current directory contents into the container at /app
COPY . /app
# Install any needed packages specified in requirements.txt
RUN pip install --trusted-host pypi.python.org -r requirements.txt
# Make port 80 available to the world outside this container
EXPOSE 80
# Define environment variable
ENV NAME World
# Run app.py when the container launches
CMD ["python", "app.py"]

In Dockerfile, we use CMD ["python", "app.py"] to run the app.py file or to run any command, CMD ["<your_commands>"] this is the syntax. But there's another way to set the default commands to be run by default after you instantiate your container. This is called ENTRYPOINT.

ENTRYPOINT in a dockerfile is used to set the container’s primary purpose, like running a web server, database or application. It also allows you to pass arguments at runtime to customize the container’s behavior. Once this command is set and the image is pushed on docker registry, anyone using this image cannot modify ENTRYPOINT command. To personalize the dockerfile they can use the CMD syntax to modify commands as per their requirements.

To know more about Dockerfile syntax in detail, please refer official documentation.


Docker Commands

After learning how to write a dockerfile, we shall proceed with docker commands used to build, run, push/pull docker image. Here are few common commands used to perform basic docker functionality. To know more about docker commands, refer this.

  • Docker Build: After writing a dockerfile, you can build image by using the following command. Replace image_name with the name you want to give to docker image and put a tag to that image as a best practice. The period. at the end represents the current directory.

      $ docker build -t image_name:tag .
    
  • Docker Push: Once you build your own customized image by using Dockerfile you need to store the image in the remote registry which is DockerHub for that you need to push your image by using the following command.

      $ docker push <Image name/Image ID>
    
  • Docker Run: This command is used to create and start a container from a specified image. It combines the functionality of docker create (which creates a container) and docker start (which starts the container). When you run this command, Docker uses the image as a base filesystem and applies any specified configurations, such as environment variables, ports, and volumes.

      $ docker run <image_name>
    
      To give name of container
      $ docker run --name <container_name> <image_name>
    
  • Docker Pull: This command is used to pull any image which is present in the official docker registry. By default, it pulls the latest image, but you can specify the version you require to pull. The syntax of docker pull is as below.

      $ docker pull <image_name>