Understand Docker || Easy-Review || Beginner friendly

 

This article is my personal organized learning note for docker. 

Who can read?

No matter who you want to review docker or if you are new to docker.


Docker – What is Docker? 

Docker is an open platform for developing, shipping, and running applications. Docker enables you to separate your applications from your infrastructure so you can deliver software quickly. (Dockerdocs: https://docs.docker.com/get-started/docker-overview/ )

If this is your 1st time reaching Docker, you probably still don’t know what you can do with Docker by this definition.

Let me explain it. Have you had an experience when you shared your applications with your colleagues, teammates, or others, and they told you the application could not run on their laptops? It’s common problem – “I can run it on my computer.” The reasons behind this could be different operating systems, dependencies, etc.

Docker is an existence solving the problem mentioned above. It helps you to package and run your application in an isolated environment named “container”. Simply put, you can think of a container containing everything you need to run the application.


If you never try docker and want to experience what I said, please try the following example from the official docker website:

https://docs.docker.com/get-started/introduction/develop-with-containers/

If you didn’t install MySQL, or Node.js or anything else needed for this project in your computer, that is totally fine to run this project just by docker. 

You have already known what kind of problems Docker wants to solve. Now, let's dive into the docker deeply.

Basic concept of Docker

Container – What is a container?

Containers are isolated processes for each of your app's components. (dockerdocs-What is a container : https://docs.docker.com/get-started/docker-concepts/the-basics/what-is-a-container/ )

After you read this definition, if you are still confused, let me explain.

First question we need to know: What is process? A process is an instance of a running program. It consists of the program's code, memory, system resources, and execution state. Thus, you can think in this way: Each container runs an application or a specific part of an application. What does a specific part mean? It can mean your app frontend part, or API backend or database or any component you need for your applications.

It has 4 features:

  • Self-contained. Each container has everything it needs to function with no reliance on any pre-installed dependencies on the host machine.
  • Isolated. Since containers are run in isolation, they have minimal influence on the host and other containers, increasing the security of your applications.
  • Independent. Each container is independently managed. Deleting one container won't affect any others.
  • Portable. Containers can run anywhere! The container that runs on your development machine will work the same way in a data center or anywhere in the cloud!

(dockerdocs-What is a container : https://docs.docker.com/get-started/docker-concepts/the-basics/what-is-a-container/ )

 Based on the above-info of the docker official site, simply put, each container is built isolated with other containers on the same application, and they can work independently, and you can use them anywhere (your Windows computer, Mac laptop, or AWS cloud) and don’t have to manage its dependencies, because it manages by itself in docker.

 Image – What is an image?

A container image is a standardized package that includes all the files, binaries, libraries, and configurations to run a container.

 (What is an image ? : https://docs.docker.com/get-started/docker-concepts/the-basics/what-is-an-image/ )

Personally, I think the definition of the image from the docker official website is very clear. But, let me summarize what we read so far: In docker, an image has everything needed to run a container, and a container has everything needed to run an application or a specific part of the application.

Two important principles of images:

  1. Images are immutable. Once an image is created, it can't be modified. You can only make a new image or add changes on top of it.
  2. Container images are composed of layers. Each layer represents a set of file system changes that add, remove, or modify files.

(What is an image ? : https://docs.docker.com/get-started/docker-concepts/the-basics/what-is-an-image/ )

In my words, a Docker image is composed of layers. Each layer in the image is created by an instruction in the Dockerfile, which tells Docker how to add or modify files for the container. Once an image is built, its existing layers cannot be changed; you can only add new layers on top. If you need to modify past instructions (past layers), you must rebuild the image from scratch.

Dockerfile

A Dockerfile is a text-based document that's used to create a container image. It provides instructions to the image builder on the commands to run, files to copy, startup command, and more. ( writing a dockerfile  https://docs.docker.com/get-started/docker-concepts/building-images/writing-a-dockerfile

 So now the concept for docker container is clear, and can be depicted as follows:

(source: http://geeksforgeeks.org/what-is-dockerfile/  )

So, what does the docker file do in the above workflow? Of course, we can build a docker image by inputting the command lines (instructions) one by one to build each layer for an image, but it is easier to put those instructions into a script to tell docker how to do it once, and the instructions are also easier to be edited in a script file. This script file is the docker file. The example looks like as follows: 

# Use a smaller base image for better efficiency
FROM node:18-alpine AS build

# Set environment variables
ENV NODE_ENV=production
ENV PORT=3000

# Set a secure working directory
WORKDIR /usr/src/app

# Copy package files first to leverage Docker cache
COPY package*.json ./

# Install only production dependencies
RUN npm ci --only=production

# Copy the rest of the application code
COPY . .

# Add additional file
ADD public/index.html /usr/src/app/public/index.html

# Use a non-root user for security
RUN chown -R node:node /usr/src/app
USER node

# Expose the application port
EXPOSE $PORT

# Default command to run the application
CMD ["node", "app.js"]

# Labeling for better image metadata
LABEL version="1.1"
LABEL description="Optimized Node.js Docker image"
LABEL maintainer="Your Name"

# Healthcheck using exec for better performance
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
  CMD exec curl -fs http://localhost:$PORT || exit 1

# Define a volume to persist data if needed
VOLUME ["/usr/src/app/data"]

From the example, we can writing a Dockerfile follows the steps:

  1. Determine your base image
  2. Set Environment variables and the working directory
  3. Install application dependencies or Copy any package files, relevant source code or binaries
  4. Expose the application port ( inform Docker that the container listens on the specified port)
  5. Specify the default command (to run when the container starts using the CMD instruction. Here, it runs node app.js.)
  6. Label the image (optional, add metadata to the image)
  7. Add a Healthcheck (optional, check the container is running correctly)

You can also consider the following from docker official website:

( writing a dockerfile: https://docs.docker.com/get-started/docker-concepts/building-images/writing-a-dockerfile/)  

Docker Compose

With Docker Compose, you can define all your containers and their configurations in a single YAML file. (What is Docker Compose? : https://docs.docker.com/get-started/docker-concepts/the-basics/what-is-docker-compose/ )

Before talking about the above definition of docker compose, let us talk more about what we have studied so far about containers and images to help us understand why we used docker compose. Let us look a figure from Microsoft:

Diagram of VM and container stacks

Source: https://opensource.microsoft.com/blog/2019/07/15/how-to-get-started-containers-docker-kubernetes/

This figure is quite common when we study docker, even in docker official website share (https://www.docker.com/resources/what-container/ ). It’s not wrong, but it may not be clear enough for you to understand the docker concept thoroughly. But, let us talk about the figure first to help you understand the comparison between VM and docker and its advantages. In the figure, hardware can be regarded as infrastructure, and the container engine can be docker. So, from the above figure, you can know why docker containers are usually said to be light processes, because, compared with the virtual machine structure, you don’t have to install another OS on your computer, which decreases the resource occupation. (Of course, docker not only does this but also gives you convenience for managing everything you need to run your application.)

Let us come back to explain docker compose. Why I say the figure is not clear enough. As mentioned, a container can run an application or “a specific part” of an application. So imagine you have done your website application, and you have a frontend part for user interactive interface, an API server to call your service or data from database, a database to store log, data or whatever. You pack everything into one container to share with your colleagues. Yeah, it can be executed on their laptop, but it’s really a bad idea in development and hard to maintain in the future, especially for an agile-working style in teamwork. Why? If this application wants to integrate or change other programs, you probably have to make a new container every time, and part of the components in the design do not need to be changed. Also, in real teamwork, a whole application will be separated into several parts and distributed to front-end, data, and backend engineers.  

Okay, too much story…. How to improve the above-mentioned problem, you need to separate the components in your application properly, and every component can work independently as isolated containers for your application. (That’s the aforementioned feature in this article's container and image part if you remember it.) Why it work better? If you just want to change the frontend part, then you just have to update one container of the frontend part, and no need to touch other containers. That brings you easier update and maintenance, good for scalability, better fault isolation, and faster development and deployment in CI/CD pipelines.

The idea can be re-depicted as follows:

A diagram of a software application

AI-generated content may be incorrect.

(Source: myself)

To do this, of course, you can pack each component one by one, but the networks among them would be managed in a hard and complicated way in this case. So you can use Docker compose to help you solve this problem. You just need one YAML file as following example:

version: '3.8'

services:
  frontend:
    image: nginx:latest
    container_name:
frontend
    ports:
      - "80:80"
    volumes:
      - ./frontend/nginx.conf:/etc/nginx/nginx.conf:ro
      - ./frontend/build:/usr/share/nginx/html
    depends_on:
      - backend
    networks:
      - app_network

  backend:
    build:
./backend
    container_name:
backend
    environment:
      - DATABASE_URL=postgresql://user:password@database:5432/mydb
    ports:
      - "5000:5000"
    depends_on:
      - database
    networks:
      - app_network

  database:
    image: postgres:latest
    container_name:
database
    environment:
      POSTGRES_USER:
user
      POSTGRES_PASSWORD:
password
      POSTGRES_DB:
mydb
    volumes:
      - db_data:
/var/lib/postgresql/data
    networks:
      - app_network

networks:
  app_network:

volumes:
  db_data:

 You can see the structure of the yml file as follows:

·         Frontend: Runs a React app (served by Nginx).

·         Backend: Runs a Flask (Python) API.

·         Database: Uses PostgreSQL.

·         Networking: Containers communicate using an internal network.

 In the end, let we just go through the docker architecture.

Docker architecture

Docker uses a client-server architecture. The Docker client talks to the Docker daemon, which does the heavy lifting of building, running, and distributing your Docker containers. The Docker client and daemon can run on the same system, or you can connect a Docker client to a remote Docker daemon (What is Docker: https://docs.docker.com/get-started/docker-overview/ )


Docker Client

Clients are users (us), we send commands such as docker build, run, push or pull and so on to Docker daemon to communicate docker platform.

Docker daemon

Docker daemon is the server listening to Docker API requests and mange docker objects, such as images, and containers.

Registry – What is registry?

An image registry is a centralized location for storing and sharing your container images. It can be either public or private. Docker Hub is a public registry that anyone can use and is the default registry. (What is registry? : https://docs.docker.com/get-started/docker-concepts/the-basics/what-is-a-registry/ )

Simply put, users can push their image to share it on their Docker Hub registry. If someone is interested in any public image, then they can pull those images to run on their computer. That’s all. It works just like you share your program on GitHub.


Okay cool, Thank you for reading, if you like or have any questions, please leave your comments.

Welcome to criticize or correct me. Happy learning ~ See you~

No comments:

Post a Comment

Mini-Project: Emotion-Detector--Analyzing Customer Sentiment

Hey guys, I made an  Emotion-Detector project that analyzes customer feedback in text format to detect emotions using a pre-trained Hugging...