Understanding Docker: A Beginner’s Guide for Junior DevOps engineers
Andrey Byhalenko
I am a self-driven DevOps expert with 15 years of experience in the IT industry. I write articles aimed at Junior DevOps engineers and those aspiring to become DevOps engineers.
Understanding what Docker is, what problems it solves, and how it works is one of the basic requirements for a DevOps engineer.
By the end of this article, you will have a basic understanding of the Docker Engine and its components.
Imagine you’re a developer tasked with creating a web application for notifications.
Your design consists of three separate components: a User Interface (UI), a Backend, and a Notification Service. Each component lives in its own GitHub repository.
First, you will need to create three GitHub repos: one for the UI, one for the backend, and another for the notification service.
For your backend, you’ve chosen Redis as a caching service and MySQL as your primary database, so you need to install them on your operating system.
Once your code is ready, you have to ensure all services and dependencies are properly installed on the OS.
But what if you need the QA team to test it? If they use a different operating system, like MacOS when you’re on Windows, they’ll face a new set of challenges. Their setup might need different dependencies or configurations.
And what happens when there’s an OS upgrade and suddenly a dependency is no longer compatible?
It’s a complex, sometimes frustrating process. This was the norm before the advent of containerization.
Docker simplifies the deployment process, reduces issues related to “on my machine everything works” problems, and has become an integral tool for both developers and operations teams (DevOps) to streamline and optimize the software development life cycle.
What is Docker?
Docker is a popular platform designed to make it easier to create, deploy, and run applications using containers.
What are containers?
A container is a lightweight, stand-alone, and executable software package that contains everything needed (code, runtime, system tools, libraries, and settings) to run a piece of software. Containers are isolated from each other and from the host system, ensuring consistent operation across various computing environments.
Containers vs Virtual Machines
A virtual machine (VM) emulates an entire computer, complete with an OS and virtualized hardware.
Think of a VM as a self-contained house. If you have multiple houses (VMs) on a plot of land (a physical computer), each is separate and independent.
Containers are like tents set up on the same plot of land. All tents share the same ground: the host operating system. However, each tent (container) has its own unique space.
Unlike VMs, containers share the same OS kernel as the system they run on, but they operate in isolated user spaces. This means they are lightweight and fast since there’s no need to emulate hardware or run a separate OS for each container.
Key Benefits and Features of Containers:
Basic Docker Concepts:
Dockerfile
A Dockerfile is a text document containing instructions used by Docker to build an image. Think of it as a recipe, specifying how your app and its environment should be pieced together. This makes it simple to share and replicate.
Here is what basic Hello Medium Dockerfile looks like:
FROM alpine
CMD [“echo”, “Hello Medium!”]
This Dockerfile instructs Docker Engine to build an alpine-based image (FROM) and run specific command (CMD).
Let’s cover some key components and commands using the following Dockerfile:
FROM node:alpine
WORKDIR /app
COPY package.json .
RUN npm install -g typescript
ENV MY_VARIABLE=value
EXPOSE 3000
CMD ["npm", "run", "start:dev"]
FROM node:alpine
WORKDIR /app
COPY package.json .
RUN npm install -g typescript
CMD ["npm", "run", "start:dev"]
ENV MY_VARIABLE=value
EXPOSE 3000
To build an image from a Dockerfile and tag it (-t), use the docker build command, followed by a location of the Dockerfile:
docker build -t my_image_name:latest .
Docker Image:
Docker Image is a snapshot or template of a container. It bundles the application, its dependencies, configurations, scripts, variables, and more. You can think of it as the blueprint for a Docker container.
Key Aspects of Docker Images:
The order in which Dockerfile commands are placed is crucial. A Docker construction is made up of sequential build steps. Each instruction in a Dockerfile creates a new layer in the Docker Image. Docker Image Layers are immutable, meaning they can’t be changed.
领英推荐
This layered approach provides several benefits:
So in our Dockerfile each instruction creating a layer:
FROM node:alpine
WORKDIR /app
COPY package.json .
RUN npm install -g typescript
ENV MY_VARIABLE=value
EXPOSE 3000
CMD ["npm", "run", "start:dev"]
Let’s see how the layers and cache works in example. Let’s create Docker Image from the following Dockerfile:
FROM alpine
COPY . .
CMD ["echo", "This is the first version of Docker Image"]
To build the image run the command:
docker build -t my-docker-image:v1.0.0 .
Here is the build command output:
Let’s verify our image exist:
Now let’s inspect the layers of my-docker-image:v1.0.0 (image ID is 59a*** as you can see on the previous picture):
Now let’s change our Dockerfile to following:
FROM alpine
COPY . .
CMD ["echo", "This is the second version of Docker Image"]
Create new image with version v1.0.1:
docker build -t my-docker-image:v1.0.1 .
Now let’s compare the outputs of the docker build command between the versions.
As you see, the build of the second step is shorter because it took some Layers from the cache.
If you will run docker image inspect, you will discover that the Layer with digest sha256:cc2447***9438 is the same for both images.
Check out another example.
Download (docker pull) two different mysql images from Docker Hub (the world’s largest library for container images).
As you can see, mysql:8.0 pulled layer by layer.
Now let’s pull mysql:8.1 and see what happens.
As you see, the first layer already exist, so Docker don’t need to pull it.
Docker Container:
Let’s run my-docker-image:v1.0.0 using docker run command.
You see This is the first version of Docker Image output when you run the image because this is what you wrote in the Dockerfile, remember?
FROM alpine
COPY . .
CMD ["echo", "This is the first version of Docker Image"]
If you run docker container ls -a you will see your docker container. The status of container will be exited as it’s just printing the text and exits.ls = list, -a = all (default shows just running containers).
Now let’s pull and run redis:latest image. Type docker run redis:latest -d , image will be pulled if it’s not exist on the server. -d option runs the container on the background.
What is that means?
Let’s type docker run redis:latest and press enter, the container runs and you see the container log on the command line.
The problem is that if you will press Control + C, the container will stop. To avoid that, you should run it on the background using -d option.
This command also prints the container id.
Executing docker container ls command, will show all running containers (in our case redis:latest).
Verify that container is running properly by checking logs.
What is Docker Hub?
Earlier I mentioned that I pulled the Redis image from the Docker Hub. Docker Hub is a cloud-based registry where Docker users and partners can create, test, store, and distribute container images.
For example, I created a Docker image for my own application, and I want to share this image with the teams inside the organization. So I can create an account in Docker Hub, create my private repository, push my image to this repository, and share it with my team.
Here is the link to Docker Hub — https://hub.docker.com/
There is a lot of alternatives to Docker Hub.
The most popular is Amazon ECR, Google Artifact Registry, Azure Container Registry.
In the ever-evolving landscape of software development and deployment, Docker has emerged as a revolutionary tool that addresses age-old challenges.
By introducing the concept of containers, Docker has simplified the complexities associated with ensuring software runs consistently across varied environments.
Understanding containerization isn’t just a skill for the modern DevOps professional, it’s a must have.