Ultimate Docker Beginner's Guide (Detailed Edition)! Never Say You Can't Use Docker Again!

Ultimate Docker Beginner's Guide (Detailed Edition)! Never Say You Can't Use Docker Again!

In the rich Web era, applications are becoming more powerful but also more complex. Cluster deployment, isolated environments, gray release, and dynamic scaling are all indispensable, and containerization has become the necessary bridge in between.

Last updated 8/15/2023 8:39 PM
Jartto's blog
18 min read
Category
Docker
Tags
Docker

In the rich Web era, applications are becoming more powerful and, at the same time, more complex. Cluster deployment, isolated environments, canary releases, and dynamic scaling are all essential, with containerization serving as the necessary bridge.

In this section, we'll explore the mysterious world of Docker, mastering its fundamental principles and practical operations from scratch. It's time to stop guarding your small corner of frontend development and start expanding your horizons.

We'll cover the following points:

  1. A Story
  2. Virtual Machines vs. Containers
  3. Understanding Docker
  4. Core Concepts
  5. Installing Docker
  6. Quick Start
  7. Common Operations
  8. Best Practices

1. A Story

To better understand what Docker is, let's start with a story:

I need to build a house. So I haul stones, cut wood, draw blueprints, and build the house. After all that work, the house is finally done.

Building a house

Then, after living in it for a while, I get a whim to move to the seaside. Using the old method, I'd have to go to the seaside, and again haul stones, cut wood, draw blueprints, and build a house.

Repeating house building

Frustrated, a wizard comes along and teaches me a magic trick. This magic lets me copy the house I built, turn it into an "image," and put it in my backpack.

Black magic

When I get to the seaside, I use this "image" to replicate a house and just move in.

Isn't that amazing? In our projects, the house is the project itself, the image is the project's copy, and the backpack is the image registry. If you need to scale dynamically, you just take the project image from the registry and copy it as needed. Build once, Run anywhere!

No more worrying about versions, compatibility, deployment issues, completely solving the awkwardness of "deploy and crash, endless builds."

2. Virtual Machines vs. Containers

Before we begin, let's build some foundational knowledge:

  1. Virtual Machine: Virtualizes Hardware

A Virtual Machine refers to a complete computer system with full hardware system functionality, running in a completely isolated environment, simulated by software. Anything that can be done on a physical computer can be done within a virtual machine.

When creating a virtual machine on a physical computer, part of the physical machine's hard drive and memory capacity are allocated as the virtual machine's hard drive and memory capacity. Each virtual machine has its own CMOS, hard drive, and operating system, and can be operated just like a physical machine. Before container technology, virtual machines were the industry darling.

Representatives of virtual machine technology include VMWare and OpenStack. For more, please refer to Virtual Machine on Baidu Baike.

  1. Container: Virtualizes the Operating System Layer, providing a standard software unit.

    • Run Anywhere: Containers package code with configuration files and related dependencies, ensuring consistent operation in any environment.
    • High Resource Utilization: Containers provide process-level isolation, allowing more granular control over CPU and memory usage, thus better utilizing server compute resources.
    • Fast Scaling: Each container runs as a separate process and can share the underlying operating system's system resources, speeding up container startup and shutdown.
  2. Differences and Connections

    • Although virtual machines can isolate many "sub-computers," they take up more space and start slower. Virtual machine software can also be costly (e.g., VMWare).
    • Container technology doesn't need to virtualize an entire operating system, only a small-scale environment, similar to a "sandbox."
    • In terms of space, virtual machines typically need from a few GB to tens of GB, while containers only require MB or even KB.

Let's look at a comparison:

Feature Virtual Machine Container
Isolation Level Operating System-level Process-level
Isolation Policy Hypervisor Cgroups (Control Groups)
System Overhead 5-15% 0-5%
Startup Time Minutes Seconds
Image Storage GB - TB KB - MB
Cluster Scale Hundreds Tens of thousands
HA Strategy Backup, Disaster Recovery, Migration Elasticity, Load Balancing, Dynamic Scaling

Compared to virtual machines, containers are lighter and faster because they leverage the underlying Linux operating system to run in isolated environments. A virtual machine's Hypervisor creates a very strong boundary to prevent applications from breaking out, while a container's boundary is less powerful.

Physical server deployment cannot fully utilize resources, leading to waste. Virtual machine deployment consumes significant resources for the VMs themselves, also causing waste, and virtual machine performance can be poor. Containerized deployment is flexible, lightweight, and offers better performance.

Virtual machines represent virtualization technology, while container technologies like Docker represent lightweight virtualization.

3. Understanding Docker

Docker

  1. Concept

Docker is an open-source application container engine that allows developers to package their applications and dependencies into a portable container, which can then be published to any popular Linux machine, also enabling virtualization. Containers use a sandbox mechanism entirely, with no interfaces between them.

The three core concepts of Docker technology are: Image, Container, and Repository.

  1. Why is Docker lightweight?

You might be wondering: Why does Docker start so fast? How does it share the kernel with the host machine?

When we ask Docker to run a container, Docker sets up a resource-isolated environment on the computer. It then copies the packaged application and associated files into the filesystem within the Namespace, completing the environment setup. After that, Docker executes the pre-specified command to run the application.

An image contains no dynamic data; its content is not changed after being built.

4. Core Concepts

  1. Build, Ship and Run;
  2. Build once, Run anywhere;
  3. Docker itself is not a container; it is a tool for creating containers, an application container engine;
  4. The three core concepts of Docker are: Image, Container, and Repository;
  5. Docker technology uses the Linux kernel and kernel features (like Cgroups and namespaces) to separate processes so they run independently of each other.
  6. Because Namespace and Cgroups features are only available on Linux, containers cannot run natively on other operating systems. So how does Docker run on macOS or Windows? Docker actually uses a technique: installing a Linux virtual machine on non-Linux operating systems and running containers inside that VM.
  7. An image is an executable package containing the code, runtime, libraries, environment variables, and configuration files needed to run an application. A container is a runtime instance of an image.

For more on Docker's principles, refer to Docker Working Principles and Containerization Simplified Guide. We won't elaborate further here.

5. Installing Docker

  1. Command Line Installation

Homebrew's Cask already supports Docker for Mac, so you can easily install it using Homebrew Cask by running:

brew cask install docker

For more installation methods, see the official documentation: Get Started Docker

  1. Check Version
docker -v
  1. Configure Image Acceleration

Configure Docker Engine by adding the configuration:

{
  "registry-mirrors": [
    "http://hub-mirror.c.163.com/",
    "https://registry.docker-cn.com"
  ],
  "insecure-registries": [],
  "experimental": false,
  "debug": true
}
  1. Install Desktop Client

Docker Desktop

The desktop client is very simple to use. First, download it from the official site. Through the Docker desktop client, you can easily:

  1. clone: Clone a project
  2. build: Build an image
  3. run: Run an instance
  4. share: Share an image

Alright, preparations are done. Now we can get down to business!

6. Quick Start

After installing Docker, let's create an image for a practical project, learning by doing.

  1. First, get a basic understanding of the 11 commands we'll likely use.
Command Description
FROM Base image to build from
MAINTAINER Image creator
ENV Declare environment variables
RUN Execute commands during build
ADD Add files from the host to the container; archives are automatically extracted
COPY Add files from the host to the container
WORKDIR Working directory
EXPOSE Ports available for the application inside the container
CMD Program to execute when the container starts; overridden if docker run includes a startup command
ENTRYPOINT Same function as CMD, but not overridden by docker run; can be overridden with --entrypoint if needed
VOLUME Data volume, mapping a host directory to a directory in the container
  1. Create a New Project

For speed, let's directly use the Vue CLI to build a project:

vue create docker-demo

Try starting it:

yarn serve

Access it at: http://localhost:8080/. The project is ready. Now let's build it for production:

yarn build

Now, the dist directory in the project folder contains the static assets we need to deploy. Let's move on.

Note: Frontend projects generally fall into two categories: those deployed statically with Nginx, and those requiring a Node service. This section covers the first type. I'll explain Node services in a later section.

  1. Create a Dockerfile
cd docker-demo && touch Dockerfile

Now the project directory looks like this:

.
├── Dockerfile
├── README.md
├── babel.config.js
├── dist
├── node_modules
├── package.json
├── public
├── src
└── yarn.lock

We can see we've successfully created the Dockerfile inside the docker-demo directory.

  1. Prepare the Nginx Image

Run your Docker desktop client (it will start a daemon by default). Pull the Nginx image from the console:

docker pull nginx

The console will output something like:

Using default tag: latest
latest: Pulling from library/nginx
8559a31e96f4: Pull complete
8d69e59170f7: Pull complete
3f9f1ec1d262: Pull complete
d1f5ff4f210d: Pull complete
1e22bfa8652e: Pull complete
Digest: sha256:21f32f6c08406306d822a0e6e8b7dc81f53f336570e852e25fbe1e3e3d0d0133
Status: Downloaded newer image for nginx:latest
docker.io/library/nginx:latest

If you get an error like this, make sure the Docker instance is running properly.

Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?

The image is ready. Let's create an Nginx configuration file in the project root:

touch default.conf

Write the following content:

server {
    listen       80;
    server_name  localhost;

    #charset koi8-r;
    access_log  /var/log/nginx/host.access.log  main;
    error_log  /var/log/nginx/error.log  error;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}
  1. Configure the Image

Open the Dockerfile and write the following:

FROM nginx
COPY dist/ /usr/share/nginx/html/
COPY default.conf /etc/nginx/conf.d/default.conf

Let's break down the code line by line:

  • FROM nginx: Specifies that the image is based on the nginx:latest image.
  • COPY dist/ /usr/share/nginx/html/: Copies all files from the dist folder in the project root to the /usr/share/nginx/html/ directory inside the image.
  • COPY default.conf /etc/nginx/conf.d/default.conf: Copies the local default.conf to /etc/nginx/conf.d/default.conf, replacing the default configuration in the Nginx image.
  1. Build the Image

Docker uses the build command to build images:

docker build -t jartto-docker-demo .

Let's explain the command:

  • -t tags the image with the name jartto-docker-demo.
  • . indicates building the image based on the Dockerfile in the current directory.

Upon successful execution, you'll see:

Sending build context to Docker daemon  115.4MB
Step 1/3 : FROM nginx
 ---> 2622e6cca7eb
Step 2/3 : COPY dist/ /usr/share/nginx/html/
 ---> Using cache
 ---> 82b31f98dce6
Step 3/3 : COPY default.conf /etc/nginx/conf.d/default.conf
 ---> 7df6efaf9592
Successfully built 7df6efaf9592
Successfully tagged jartto-docker-demo:latest

The image is successfully created! Let's check it:

docker image ls | grep jartto-docker-demo

We can see we've built a 133MB project image:

jartto-docker-demo latest 7df6efaf9592 About a minute ago 133MB

Images can be good or bad. We'll discuss optimization later. For now, we can ignore it.

  1. Run the Container
docker run -d -p 3000:80 --name docker-vue jartto-docker-demo

Let's explain the parameters:

  • -d: Run the container in the background (detached mode).
  • -p: Map ports. Maps port 3000 on the host to port 80 in the container (so external access via port 3000 on the host reaches the app).
  • --name: Assign a name docker-vue to the container.
  • jartto-docker-demo: The name of the image we built above.

As a bonus:

In the console, you can see the ID of the just-started Container using docker ps:

docker ps -a

The console will output:

CONTAINER ID IMAGE              COMMAND                  CREATED       STATUS PORTS  NAMES
ab1375befb0b jartto-docker-demo "/docker-entrypoint.…"   8 minutes ago Up 7 minutes  0.0.0.0:3000->80/tcp  docker-vue

If you are using the desktop client, open Docker Dashboard to see the container list, as shown below:

Docker Dashboard

  1. Access the Project

Since we mapped host port 3000, run:

curl -v -i localhost:3000

Or just open your browser and go to localhost:3000.

  1. Publish the Image

If you want to contribute to the community, you'll need to publish the image so other developers can use it.

Publishing an image requires these steps:

  1. Sign up for an account on Docker Hub.
  2. Log in via the command line: docker login, then enter your credentials.
  3. Before pushing the image, tag it properly: docker tag <image> <username>/<repository>:<tag>.

The whole process is complete. From now on, when we need this project, we don't have to "haul stones, cut wood, draw blueprints, build a house" again. We just move in. This is the unique charm of Docker.

7. Common Operations

Congratulations on completing your Docker introduction project! If you want to go deeper, feel free to explore further.

  1. Parameter Usage
  • FROM

    • Specifies the base image. Every built image must have a base image, and FROM must be the first command in the Dockerfile.
    • FROM <image> [AS <name>]: Build from an image and give the new image a name.
    • FROM <image>[:<tag>] [AS <name>]: Specify the image version Tag.
    • Example: FROM mysql:5.0 AS database
  • MAINTAINER

    • Image maintainer information.
    • MAINTAINER <name>
    • Example: MAINTAINER Jartto Jartto@qq.com (Note: Deprecated in favor of LABEL)
  • RUN

    • Commands to execute during the image build.
    • RUN <command>
    • Example: RUN ["executable", "param1", "param2"]
  • ADD

    • Add local files to the container. Archives are automatically extracted. Can access files over the network (downloads them).
    • ADD <src> <dest>
    • Example: ADD *.js /app adds all js files to the /app directory in the container.
  • COPY

    • Same function as ADD, but only copies; does not unpack archives or download files.
  • CMD

    • Command to execute when the container starts. Different from RUN, which executes during build.
    • Can be overridden by the command provided in docker run.
    • Example: CMD ["executable", "param1", "param2"]
  • ENTRYPOINT

    • Also executes a command, similar to CMD, but this command is not overridden by the command line.
    • ENTRYPOINT ["executable", "param1", "param2"]
    • Example: ENTRYPOINT ["donnet", "myapp.dll"] (Note: Original likely meant ["dotnet", "myapp.dll"])
  • LABEL: Adds metadata to the image in key-value format.

    • LABEL <key>=<value> <key>=<value> ...
    • Example: LABEL version="1.0" description="This is a web application"
  • ENV: Sets environment variables. Some containers require specific environment variables at runtime.

    • ENV <key> <value>: Set one environment variable.
    • ENV <key>=<value> <key>=<value> <key>=<value>: Set multiple environment variables.
    • Example: ENV JAVA_HOME /usr/java1.8/
  • EXPOSE: Exposes a port (the port exposed inside the container, which is different from the host port even if they are the same number).

    • EXPOSE <port>
    • Example: EXPOSE 80
    • When running the container, you need to use -p to map an external port to this container port for access.
  • VOLUME: Specifies a directory for data persistence; officially called a mount.

    • VOLUME /var/log: Specifies a directory in the container to be mounted. Docker maps this to a random directory on the host for data persistence and syncing.
    • VOLUME ["/var/log","/var/test".....]: Specifies multiple directories in the container to be mounted to multiple random host directories.
    • VOLUME /var/data /var/log: Mounts /var/log in the container to /var/data on the host. This syntax allows specifying the host path manually.
  • WORKDIR: Sets the working directory. After setting, the working directory for RUN, CMD, COPY, ADD commands is this path.

    • WORKDIR <path>
    • Example: WORKDIR /app/test
  • USER: Specifies the user to run subsequent commands. For security and permissions, choose appropriate users based on the commands.

    • USER <user>:[<group>]
    • Example: USER test
  • ARG: Defines parameters to pass during the image build.

    • ARG <name>[=<value>]
    • Example: ARG name=sss

For more operations, please refer to the official Docker documentation.

8. Best Practices

After mastering common Docker operations, it's easy to build project images you want. However, different operations can lead to vastly different images.

Why are images so different? Let's explore further.

Here are some best practices compiled from experience using Docker. Please try to follow these guidelines:

  1. Require Clarity: Know exactly what image you need.
  2. Streamline Steps: Prioritize steps that change less frequently.
  3. Clear Versioning: Name images clearly and explicitly.
  4. Documentation: The entire image building process should be reproducible.

Recommended reading:

9. Conclusion

Containerization technology is undoubtedly one of the indispensable skills for the cloud era, and Docker is just the tip of the iceberg. Following it are technologies like cluster container management (K8s), Service Mesh, Istio, and more. Open the door to Docker, keep peeling back the layers, delve deeper, and you will feel the infinite charm of containerization.

Hurry up and expand your skillset to empower your frontend technology!

Copyright Notice: This article was first published on Jartto's Blog. For reprinting, please be sure to include the article's source URL, author information, and this copyright notice in a hyperlink form.

Keep Exploring

Related Reading

More Articles
Same tag 2/25/2025

.NET 10 Preview 1 Released

Today .NET 10 Preview 1 was released. I downloaded it immediately, upgraded the Avalonia UI project and blog website. The former passed functional testing and AOT publishing successfully, the latter debugging went fine, but Docker has not been successful yet.

Continue Reading