WHY DOCKER

Softwares are typically built using different programming languages, frameworks & dependencies. During development, we generally set up our environment by installing our desired programming language, frameworks & dependencies in our Pc or Mac and start development. When we want to run our application in other machines for development or deployment we need to recreate our environment each time. This will become even more complicated when we work with microservice architectures.

What if we could package our application along with its environment and ship?

This is the exact problem DOCKER solves.It helps us packaging our application with its environment, dependencies and makes it easy to move across different machines irrespective of the operating system. Let’s see how it works.

DOCKER

Docker has a client-server architecture with three main components.

  • DOCKER DAEMON (server)
    A docker Daemon (dockerd) is a persistent process that runs in the background & executes docker commands it receives from the Docker CLI.The Docker Daemon does all the heavy lifting managing images, containers, volumes, networks etc.

  • DOCKER CLI (client)
    As a end user we typically interact with the Docker CLI and run our desired docker commands and the Docker CLI interacts with the Docker Daemon to execute our commands.

  • REST API
    The Docker Daemon exposes a REST API & the Docker Client communicates with the Docker Daemon via Rest API.

Docker Components

The Docker Daemon runs on a docker host & exposes a REST API.
The Docker Daemon can listen for requests via three different types of sockets unix tcp & fd.

By default unix domain socket is created and it listens on /var/run/docker.sock. The Docker CLI can communicate with the Docker Daemon running on the same Host via unix socket.

Docker Daemon can be accessed remotely when the tcp socket is enabled.By this way the Docker CLI can communicate with a Docker Daemon running on a remote machine.

On systemd based systems Docker Daemon can be accessed via fd sockets.

THE BASICS

The core function of Docker is to run containers.On a high level it looks something like this.

Docker Components

As we can see from the above image to run our container we need our Docker Image and a Docker Image is built from a Dockerfile.

Sounds Gibberish ? Lets understand the following components one by one.

  • Dockerfile
  • Docker Image
  • Docker Container
  • Docker Volume
  • Docker Network
  • Docker Registry

DOCKERFILE

A dockerfile is the blueprint to create our Docker Image. We will define our environment, dependencies to install, commands to run our application in a Dockerfile. The Dockerfile typically lives in our application repository.

A dockerfile typically starts by defining a base image followed by instructions to install our dependencies, copying our source files & commands to build & run our application.

A dockerfile to create a NODEJS application would look like this.

#Base Image
FROM node:13-stretch-slim

# Create app directory
WORKDIR /app

# Install app dependencies
# A wildcard is used to ensure both package.json AND package-lock.json are copied
COPY package*.json ./
RUN npm install

# Copy app source
COPY . .

EXPOSE 8080
CMD [ "npm", "start" ]

A dockerfile can have a base image or we can build everything from scratch & we can even have multiple stages to build our Docker Image.

Now we have our Dockerfile to build our docker image we can use docker build command.
usage
docker build [OPTIONS] PATH | URL | -

For example to build our Docker Image from the above Dockerfile we would run the following command.
docker build -t myNodeJsApp build .
The trailing . is important - It tells the docker daemon to use our Dockerfile to build our image

DOCKER IMAGE

Docker Image is built from a dockerfile and its an immutable snapshot of our application. Once a Docker Image is built it can be found in our local machine & we can push it to a docker registry if we want to share our Image.Now a user or a server which has access to our registry can pull our docker Image and run it.

To list our Docker Images we can use docker images command.
usage
docker images [OPTIONS] [REPOSITORY[:TAG]]

To build our Docker Image we can use docker image build command.
usage
docker image build [OPTIONS] PATH | URL | -

To display the history of an image we can use docker image history command.
usage
docker image history [OPTIONS] IMAGE

To inspect our Docker Image we can use docker image inspect command.
usage
docker image inspect [OPTIONS] IMAGE [IMAGE...]

To build our Docker Image we can use docker image rm command.
usage
docker image rm [OPTIONS] IMAGE [IMAGE...]

DOCKER CONTAINER

A Docker Container is the running process of our Docker Image. We can run as many containers as we want in our machine as long as we have enough hardware resources to feed our containers. Each Docker container is completely sandboxed & isolated from each other.\

To run a docker container we would use the docker run command. usage
docker run [OPTIONS] IMAGE[:TAG|@DIGEST] [COMMAND] [ARG...]

We can actually run containers from the Images in our local machine or a remote registry.
For example to run our previously built NODEJS Image we can run docker run myNodeJsApp -p 8080:8080.Now if we go to http://localhost:8080 we can see our application running.(The -p is used to bind our container port to our host port)

To list our running containers we can use docker ps command.
usage
docker ps [OPTIONS]

To stop a running container we can use docker stop command.
usage
docker stop [OPTIONS] CONTAINER [CONTAINER...]

To restart a running container we can use docker restart command.
usage
docker restart [OPTIONS] CONTAINER [CONTAINER...]

To kill a running container we can use docker kill command.
usage
docker kill [OPTIONS] CONTAINER [CONTAINER...]

DOCKER VOLUME

A Docker Volume is a persistent storage unit that can be attached to a Docker Container to persist data.A docker container dies when it is killed/destroyed. If we have any data it will be gone forever when the container is destroyed. So when we want to persist the data we must attach a Docker Volume to our containers. This would be mostly used for database containers. We can share our Volume with multiple containers as well.

To create a volume we can use volume create command
usage
docker volume create [OPTIONS] [VOLUME]

To list all volumes we can use volume ls command
usage
docker volume ls [OPTIONS]

To inspect a volume we can use volume inspect command
usage
docker volume inspect [OPTIONS] VOLUME [VOLUME...]

To remove a volume we can use volume rm command
usage
docker volume rm [OPTIONS] VOLUME [VOLUME...]

To remove all unused volumes we can use volume prune command
usage
docker volume prune [OPTIONS]

To attach a volume to a container we can use -v with the docker run command.
For example
docker run -v <path to host directory>:<path to container working directory> <image id>

DOCKER NETWORK

Docker Network can be used to make two or more docker containers to communicate with each other. Let’s say we have our React container & NodeJS/Express container and if we want our containers to communicate with each other we can use a Docker Network.

Docker Engine natively supports the following network types

  • Brigde Network
    A bridge network is limited to a single host where the Docker Engine runs.
  • Overlay Network
    An overlay network can have multiple hosts and its more advanced.

To create a docker network we can use docker network create command
usage
docker network create [OPTIONS] NETWORK

To inspect a docker network we can use docker network inspect command
usage
docker network inspect [OPTIONS] NETWORK [NETWORK...]

To connect a docker container to a docker network we can use docker network connect command
usage
docker network connect [OPTIONS] NETWORK CONTAINER

To disconnect a docker container to a docker network we can use docker network disconnect command
usage
docker network disconnect [OPTIONS] NETWORK CONTAINER

To list all docker networks we can use docker network ls command
usage
docker network ls [OPTIONS]

To remove one or more docker network we can use docker network remove command
usage
docker network rm NETWORK [NETWORK...]

To remove all unused docker networks we can use docker network prune command
usage
docker network prune [OPTIONS]

DOCKER REGISTRY

A Docker Registry helps us to store & distribute our docker images. We can use the docker registry to manage our image distribution pipeline. We can either use Docker HUb (hub.docker.com) a free solution from docker or we can have our own private registry to distribute our Docker Images.A docker registry can be pulled using docker pull registry from the Docker Hub if we want to self host it.

We can push or pull from the docker registry using the following commands.Before we do that we must login to our registry using docker login.

To push a docker Image we can use docker push command
usage
docker image push [OPTIONS] NAME[:TAG]

To pull a docker Image we can use docker push command
usage
docker image pull [OPTIONS] NAME[:TAG|@DIGEST]

PUT TOGETHER

Now we have understood what is docker and what it does. If we visualize whatever we have discussed in this post it would look something like this.

Docker

To summarize

A docker Image is built from a Dockerfile.
A docker container is a running instance of a docker Image.
A docker volume is attached to a docker container to persist data.
A docker Network is used to help multiple containers to communicate with each other.
A docker registry is used to store & distribute our docker Images.

Share