Introduction to Docker

Posted by moneytree on Sat, 26 Feb 2022 14:57:38 +0100

Introduction to Docker

1. Introduction

Docker is an open source application container engine, which allows developers to package their applications and dependency packages into a portable image, and then publish them to any popular Linux or Windows operating system, or realize virtualization. Containers are completely sandboxed, and there will be no interface between them.

In short, Docker can simplify the configuration of development environment; It is convenient for program deployment and migration of different systems (Windows/Mac/Linux) and different environments (production environment, pre release environment and development environment).

The difference between Docker and traditional Virtualization:

  • Traditional virtual machine technology is to run a complete operating system on a set of virtual hardware, and then run the required application process on the system;
  • The application process in the container runs directly in the host kernel. There is no own kernel in the container, and there is no hardware virtualization. Therefore, containers are lighter than traditional virtual machines.

2 basic concepts

2.1 Image

Docker image is a special file system. In addition to providing the program, library, resource, configuration and other files required by the container during operation, it also includes some configuration parameters prepared for operation (such as anonymous volume, environment variable, user, etc.). The image does not contain any dynamic data, and its content will not be changed after construction.

It can be understood as a software installation package, which can be easily spread and installed.

Container (2.2)

The relationship between image and Container is like a class and instance in object-oriented programming. Image is a static definition, and Container is the entity of image runtime. Containers can be created, started, stopped, deleted, suspended, etc.

The essence of a container is a process. The process in the container runs in an isolated environment and is used as if it were operating under a host independent system. This feature makes container encapsulated applications more secure than running directly on the host.

It can be understood as the state after software installation. Each software running environment is independent and isolated, which is called container.

2.3 Repository

After the image is built, it can be easily run on the current host. However, if we need to use this image on other servers, we need a centralized service for storing and distributing images, such as Docker Registry.

A Docker Registry can contain multiple repositories; Each warehouse can contain multiple tags; Each label corresponds to a mirror image.

Usually, a warehouse will contain images of different versions of the same software, and labels are often used to correspond to each version of the software. We can specify which version of the software is mirrored through the format of < warehouse name >: < label >. If no label is given, latest will be used as the defau lt label.

Warehouse names often appear in the form of two-stage paths, such as kint216 / flash. The former often means the user name in the Docker Registry multi-user environment, while the latter is often the corresponding software name. However, this is not absolute, depending on the specific Docker Registry software or service used.

3.Windows Docker installation

3.1 changing the default installation location

Because the default installation location of Docker is Disk C, and the capacity of my disk C is getting smaller and smaller, the following methods are adopted to change the installation location of Docker.

# Installation location of Docker:
# C:\Program Files\Docker
# C:\ProgramData\Docker
# C:\ProgramData\DockerDesktop
# C:\Users \ your user name \ AppData\Local\Docker
# C:\Users \ your user name \ AppData\Roaming\Docker

Execute the following command in cmd with administrator privileges:

mklink /j "C:\Program Files\Docker" "Custom location"

"Custom location" must be established manually before executing the command. After executing the above command, just install docker directly. This command will create a shortcut to "custom location" in the "default location" (different from the shortcut you added). If you want to withdraw this command, delete the shortcut in the "default location".

3.2 installation steps

Download address:

  • Double click the downloaded exe file and check the following two options to automatically install the corresponding configuration.

  • After the configuration download is completed, the computer needs to be restarted.

  • There is an error when starting Docker. You need to manually update the WSL 2 kernel.

  • According to the prompt connect Step 4 in downloads the Linux kernel Update package , manually update after downloading.

  • At this time, Docker can be opened normally, and the display page is as follows.

  • Set the image source to speed up the download.

Image acceleratorMirror accelerator address
Docker China official image
DaoCloud mirror station
Azure China image
HKUST mirror station
Alibaba cloudhttps://<your_code>
Seven cattle cloud
Netease cloud
Tencent cloud

# The added code is as follows
  "registry-mirrors": [

4. Use image

4.1 obtaining images

There are a large number of high-quality images available on the Docker Hub. The command to obtain images from the Docker image warehouse is docker pull. The command format is:

$ docker pull [option] [Docker Registry address[:Port number]/]Warehouse name[:label]

The specific options can be seen through the docker pull --help command. Here we will talk about the format of the image name.

  • Docker image warehouse address: the address format is generally < domain name / IP > [: port number]. The defau lt address is Docker Hub(
  • Warehouse Name: the warehouse name here is a two-stage name, that is < user name > / < software name >. For Docker Hub, if the user name is not given, it defau lt s to library, that is, the official image.
$ docker pull ubuntu:18.04
18.04: Pulling from library/ubuntu
284055322776: Pull complete
Digest: sha256:0fedbd5bd9fb72089c7bbca476949e10593cebed9b1fb9edf5b79dbbacddd7d6
Status: Downloaded newer image for ubuntu:18.04

The above command does not give the address of Docker image warehouse, so the image will be obtained from Docker Hub ( The image name is Ubuntu: 18.04, so the image labeled 18.04 in the official image library / Ubuntu warehouse will be obtained. The last line of the output result of the docker pull command gives the full name of the image, namely: Docker io/library/ubuntu:18.04.

4.2 list images

List the downloaded images. You can use the docker image ls command.

$ docker image ls
REPOSITORY                                                 TAG       IMAGE ID       CREATED        SIZE
docker/getting-started                                     latest    26d80cd96d69   2 months ago   28.5MB
ubuntu                                                     18.04     5a214d77f5d7   4 months ago   63.1MB
ubuntu                                                     bionic    5a214d77f5d7   4 months ago   63.1MB   latest    a54473bbb25a   7 months ago   47.3MB

The list contains the warehouse name, label, image ID, creation time and occupied space.

The image ID is the unique identification of the image. One image can correspond to multiple labels. Therefore, in the above example, we can see that ubuntu:18.04 and ubuntu:bionic have the same ID because they correspond to the same image.

Without any parameters, docker image ls will list all top-level images, but sometimes we only want to list some images. docker image ls has several parameters to help do this.

  • List the image according to the warehouse
$ docker image ls ubuntu
ubuntu       18.04     5a214d77f5d7   4 months ago   63.1MB
ubuntu       bionic    5a214d77f5d7   4 months ago   63.1MB
  • List a specific image, that is, specify the warehouse name and label
$ docker image ls ubuntu:18.04
ubuntu       18.04     5a214d77f5d7   4 months ago   63.1MB

$ docker image ls ubuntu:bionic
ubuntu       bionic    5a214d77f5d7   4 months ago   63.1MB

4.3 delete local image

To delete a local image, you can use the docker image rm command. The format is:

$ docker image rm [option] <Mirror 1> [<Mirror 2> ...]

Among them, < Image > can be image short ID, image long ID and image name.

For example, we have some images:

$ docker image ls
REPOSITORY                                                 TAG       IMAGE ID       CREATED        SIZE
docker/getting-started                                     latest    26d80cd96d69   2 months ago   28.5MB
ubuntu                                                     18.04     5a214d77f5d7   4 months ago   63.1MB
ubuntu                                                     bionic    5a214d77f5d7   4 months ago   63.1MB   latest    a54473bbb25a   7 months ago   47.3MB

We can use the full ID of the image, also known as the long ID, to delete the image, but more often we use the short ID to delete the image. docker image ls lists short IDS by default. Generally, it takes more than the first three characters, as long as it is enough to distinguish them from other images.

For example, here, if we want to delete the docker / getting started image, we can execute the following steps:

$ docker image rm 26d
Untagged: docker/getting-started:latest
Untagged: docker/getting-started@sha256:86093b75a06bf74e3d2125edb77689c8eecf8ed0cb3946573a24a6f71e88cf80
Deleted: sha256:26d80cd96d6905cdc4f95c8e4cac9e1dce43cc9d81054fff28371728435891a8
Deleted: sha256:417302e3ee3f952e11b2c25c5295ac437e9eceb97b5d50683ab9717688c2c47a
Deleted: sha256:8dfa110a9ba2693c02cc4311773b7a7ebdd02a8be91d089cd4cfc4a7ca51a75c
Deleted: sha256:57dba6dab88290f4e9b3125f9e6b3b088626af1fe3a93d47056c030ac7d51c1c
Deleted: sha256:67c225b96afdfdb9c2b8f6f7284d771fe20ff5ebabc65a088afeca1fbafadbee
Deleted: sha256:d8242f1082c90da0b3819a2737bc23215237e2440857a0c5ec0904abc81e81b0
Deleted: sha256:329df243003cb0259caf109da224f24391d0a4e3fe419fde5a6f092ee27424fe
Deleted: sha256:bdb2ce57de00bca016d44a1def44f2a281dfe027bbc4975d65c8ff4cf04d63fb
Deleted: sha256:1a058d5342cc722ad5439cacae4b2b4eedde51d8fe8800fcf28444302355c16d

We can also delete the image by using the image name, that is < warehouse name >: < label >.

$ docker image rm ubuntu:18.04
Untagged: ubuntu:18.04

If you observe the output information of the above commands, you will notice that the deletion behavior is divided into two types: Untagged and Deleted. As we mentioned earlier, the unique identification of an image is its ID and summary, and an image can have multiple labels.

Therefore, when we use the above command to Delete the image, we are actually asking to Delete the image of a label, which is the Untagged information. Because an image can correspond to multiple labels, when we Delete the specified label, there may be other labels pointing to the image. If this is the case, the Delete behavior will not occur. Therefore, when the docker image rm ubuntu:18.04 instruction is executed, only the tag name 18.04 is cancelled, because the ubuntu image has other tag names bionic

When all the labels of the image are cancelled, the image is likely to lose its meaning of existence, so the deletion behavior will be triggered. The image is a multi-layer storage structure, so it is also judged and deleted from the upper layer to the basic layer. The multi-layer structure of image makes image reuse very easy, so it is likely that some other image is dependent on a layer of the current image. In this case, the deletion of this layer will not be triggered. The current layer will not be deleted until no layer depends on the current layer.

In addition to the image dependency, you should also pay attention to the container's dependency on the image. If a container started with this image exists (even if the container is not running), the image cannot be deleted. If these containers are not needed, you should delete them first, and then delete the mirror.

5. Container

A container is an application or group of applications that run independently and their running environment.

5.1 start up container

There are two ways to start a container. One is to create a new container based on the image and start it, and the other is to restart the container in the terminated state.

5.1.1 create and start

With an image, we can start and run a container based on this image. The main command used is docker run.

For example, the following command starts a bash terminal to allow users to interact.

$ docker run -it --rm ubuntu:18.04 bash

root@10781f4737ca:/# cat /etc/os-release
VERSION="18.04.6 LTS (Bionic Beaver)"
PRETTY_NAME="Ubuntu 18.04.6 LTS"
root@10781f4737ca:/# exit
  • -it: These are two parameters, one is - i interactive operation, and the other is - t terminal, that is, interactive terminal.
  • --rm: this parameter means that the container will be deleted after exiting.
  • ubuntu:18.04: This refers to starting the container based on the ubuntu:18.04 image.
  • bash: after the image name is the command. Here we want an interactive Shell, so bash is used.

After entering the container, we can operate under the Shell and execute any required commands. Here, we execute cat / etc / OS release, which is a common command for Linux to view the current system version. From the returned results, we can see that the container is Ubuntu 18.04.1 LTS system. Finally, we exited the container through exit.

When using docker run to create containers, the standard operations of Docker running in the background include:

  • Check whether the specified image exists locally. If it does not exist, download it from the registry
  • Create and start a container using the image
  • Allocate a file system and mount a read-write layer outside the read-only image layer
  • Bridge a virtual interface from the bridge interface configured by the host to the container (- p parameter)
  • Configure an ip address from the address pool to the container
  • Execute user specified applications
  • The container is terminated after execution

5.1.2 start the terminated container

You can directly start an exited container by using the docker container start command.

5.2 background operation

More often, Docker needs to be run in the background rather than directly outputting the results of executing commands. At this point, you can add the - d parameter.

If you do not use the - d parameter, run the container.

$ docker run ubuntu:18.04 /bin/sh -c "while true; do echo hello world; sleep 1; done"
hello world
hello world
hello world
hello world

As you can see from the above example, the container will print the output.

If the - d parameter is used, run the container.

$ docker run -d ubuntu:18.04 /bin/sh -c "while true; do echo hello world; sleep 1; done"

At this time, the container will run in the background and will not print the output results (the output results can be viewed with docker logs).

After starting with the - d parameter, a unique id will be returned. You can also view the container information through the docker container ls command.

To obtain the output information of the container, you can use the docker container logs command.

$ docker container logs [container ID or NAMES]
hello world
hello world
hello world
. . .

You can also view the logs of containers in docker desktop.

5.3 termination of containers

You can use docker container stop to terminate a running container. In addition, when the application specified in the Docker container terminates, the container also terminates automatically.

$ docker container stop [container ID]

Containers in the terminated state can be restarted with the docker container start command.

In addition, the docker container restart command will terminate a running container and then restart it.

5.4 entering the container

When using the - d parameter, the container will enter the background after starting. Sometimes you need to enter the container for operations. You can use the docker attach command or docker exec command.

5.4.1 attach command

# Start container
$ docker run -dit ubuntu

# View container status
$ docker container ls
862613a2556e   ubuntu    "bash"    3 seconds ago   Up 2 seconds             infallible_cori

# Enter a container according to the container ID
$ docker attach 862
# sign out
root@862613a2556e:/# exit

# View the status of the container after the end of the attach instruction
$ docker container ls

If you exit, it will cause the container to stop.

5.4.2 exec command

# Start container
$ docker run -dit ubuntu

# View container status
$ docker container ls
6f242cd3ca38   ubuntu    "bash"    4 seconds ago   Up 3 seconds             naughty_williamson

# Enter a container according to the container ID
$ docker exec -it 6f24 bash
# View current directory
root@6f242cd3ca38:/# ls
bin  boot  dev  etc  home  lib  lib32  lib64  libx32  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
# sign out
root@6f242cd3ca38:/# exit

# View the status of the container after the end of the exec instruction
$ docker container ls
6f242cd3ca38   ubuntu    "bash"    5 minutes ago   Up 5 minutes             naughty_williamson

If you exit, it will not cause the container to stop.

The docker exec instruction is recommended.

5.5 delete container

You can use docker container rm to delete a container in a terminated state.

$ docker container rm [container ID]

If you want to delete a running container, you can add the - f parameter. Docker will send SIGKILL signal to the container.

Use the docker container ls -a command to view all containers that have been created, including those in terminated status. If there are too many containers, it may be troublesome to delete them one by one. Use the following command to clean up all containers in terminated status.

$ docker container prune

6. Customized image

The image is the basis of the container. Each time docker run is executed, which image will be specified as the basis for the container to run. In the previous examples, we used images from Docker Hub. Using these images directly can meet certain needs. When these images cannot meet the needs directly, we need to customize these images.

The following is a demo based on the flash framework.

File directory structure


The back-end code is as follows. Open the web page to display Hello, World!:

from flask import Flask

app = Flask(__name__)

def hello_world():
    return "Hello, World!"

if __name__ == '__main__':'')

requirements.txt reads as follows:


Dockerfile contents are as follows:

# FROM specifies the base image
FROM python:3.8-slim-buster
# Specify the working path of Docker command. If the path does not exist, Docker will be created automatically
# Copy all programs to Docker image
# Copy < Local Path > < target path >
# First '.' Represents all files in the root directory of the program; Second '.' Represents the path in the Docker image, that is, the current working path '/ app /'
COPY . .
# Create an image and install the environment. The RUN command is used when creating an image
RUN pip install -r requirements.txt
# CMD instruction is used to specify the command to be executed when Docker container is running
CMD ["python",""]

Enter the command in the Dockerfile file directory. The - t parameter specifies the image name Tell docker to find the Dockerfile file in this directory

$ docker build -t demo .

docker executes step by step according to the instructions we write, as shown in the figure below.

Then we start a container through the docker run instruction- p is to map a port on the container to the local host so that we can access the Web services in the container from the host. The front 8080 is the port on the local host and the back 5000 is the port on the container- d let the container run in the background, so that the output will not be directly displayed on the console-- The name parameter specifies the name of the container. If Docker is not set, a container name will be randomly generated.

$ docker run -p 8080:5000 -d --name web demo

At this point, open localhost:8080 in the browser, and you can see Hello World in the web page!

Note: the host number of the back-end code of Flask should be written as, otherwise an error will be reported when the container is opened on the machine after startup.

7. Directory mount

7.1 data Volumes

A data volume is a special directory that can be used by one or more containers. It has the following characteristics:

  • Can be shared and reused between containers
  • Changes to the data volume take effect immediately
  • Updating data volumes does not affect mirroring
  • Data volumes persist by default, even if the container is deleted
# Create a data volume
$ docker volume create Data volume name

# View all data volumes
$ docker volume ls

# Use the following command in the host to view the information of the specified data volume
$ docker volume inspect Data volume name

# Delete data volume
$ docker volume rm my-vol

# Delete unused data volumes
$ docker volume prune

The following demonstrates starting a container that mounts data volumes:

# Create data volume
$ docker volume create test

# View data volumes
$ docker volume ls
local     test

# Create a container named test with ubuntu image, and mount the newly created data volume to the / volume directory. If there is no directory, Docker will automatically create it
$ docker run -dit --name test -v test:/volume ubuntu

# Enter the container and create the test file
$ docker exec -it 57cc bash
root@57cc84da548f:/# cd volume
root@57cc84da548f:/volume# touch test.txt

At this point, you can see that the test file also appears in the data volume.

7.2 mount Host Directory

Create a mount directory locally. The directory I use here is D:\Volume.

Mount a local host directory as a data volume. The command is as follows:

# Use the ubuntu image to create a container named test, and mount the local directory to the / volume directory. If there is no such directory, Docker will automatically create it
$ docker run -dit --name test01 -v /d/Volume:/volume ubuntu

In order to modify files in the container, I install vim in the container, and the instructions are as follows:

# Update apt source
apt-get update 
# Install vim
apt-get install -y vim

To create a file in a container:

$ docker exec -it test01 bash
root@7c6623ff53d2:/# cd volume
# Create a test file with the content of "Container test"
root@7c6623ff53d2:/volume# vim test.txt

Updates are also synchronized in the local folder.

8.Docker Compose

In many cases, we need multiple containers to cooperate with each other to complete a task. For example, to implement a Web project, in addition to the Web service container itself, you often need to add the back-end database service container, and even include the load balancing container. Compose just meets this need. It allows users to use a separate docker - compose YML template file (YAML format) to define a set of associated application containers as a project.

Here I use a simple personal blog system as a demonstration, including flash back-end and MySQL database.
Warehouse address:

The file directory is as follows:


The dockerfile in the backend flash folder is as follows:

FROM python:3.8-slim-buster
COPY . .
RUN pip install -r requirements.txt -i
CMD ["python",""]

The dockerfile in the mysql folder of the database is as follows:

FROM mysql
COPY ./notebook.sql /docker-entrypoint-initdb.d

notebook.sql is the database initialization file, which will create the libraries and tables needed by flash application. In the official mysql image, the / docker entrypoint initdb.exe is automatically executed when the container is started D folder (including shell script and sql script). So we just copy the initialization file to / docker entrypoint initdb. When the image starts D folder is OK.

To assemble multiple services that the project depends on, we need to write a docker - compose YML file, which describes which services depend on.

# Version number
version: '3'

  # Define database container
  	# Execute the dockerfile under the database folder
    build: ./mysql
    # Set port mapping for hosts and containers
      - "3307:3306"
    # Set root user password
      - MYSQL_ROOT_PASSWORD=123456
  # Define backend container
  	# Execute dockerfile under backend folder
    build: ./flask
    # Set port mapping for hosts and containers
      - "5000:5000"

After completing the above steps, click docker-compose The directory where the YML file is located, execute the command:

$ docker-compose up -d

Problem 1: the flash container cannot access the MySQL container, and cannot be connected after changing the host number for many times.

# Back end error message
pymysql.err.OperationalError: (2003, "Can't connect to MySQL server on '' ([Errno 111] Connection refused)")

The error message of the web page is as follows:

**Solution: * * after querying similar problems on github and stack overflow, I found that my host and port were written incorrectly. Host should be written as the name of the database service, namely docker - compose mysql in YML; Because I mapped port 3306 of the container to port 3307 of the local host, I always wrote that port 3307 failed. The two containers are in the same network, so they can communicate with each other after changing to port 3306.

# Database connection code
class MysqlUtil():
    def __init__(self):
        host = 'mysql'  # host name
        port = 3306  # Port number
        user = 'root'  # Database user name
        password = '123456'  # Database password
        database = 'notebook'  # Database name
        self.db = pymysql.connect(host=host, port=port, user=user, password=password, db=database)  # Establish connection
        self.cursor = self.db.cursor(cursor=pymysql.cursors.DictCursor)  # Set cursor and set cursor to dictionary type

Question 2: RuntimeError: 'cryptography' package is required for sha256_password or caching_sha2_password auth methods

**Solution: * * install the cryptography package or set the encryption method (in docker-compose.yml or modify it manually).

9. Release and deployment

  1. stay Docker Hub Registered account number on

  2. Create a mirror Library

  1. Command line login account:
$ docker login -u username
  1. Register an account with the same name as tag
$ docker tag notebook_flask:latest username/notebook:v1

  1. Push to remote warehouse
$ docker push username/notebook:v1

  1. At this time, it can be pulled from the remote warehouse for deployment
$ docker run -dp 8080:5000 --name hub_notebook username/notebook:v1

Practice 1 Docker installation MySQL

# Pull image
$ docker pull mysql

# Run a MySQL container
# -p 3306:3306: map the 3306 port of the container service to the 3307 port of the host. The external host can directly access the MySQL service through the host ip:3307.
# MYSQL_ROOT_PASSWORD=123456: set the password of the root user of MySQL service.
$ docker run -itd --name mysql-test -p 3307:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql

Problem: sqlyog:2058 connection error

sqlyog:2058 error occurred when connecting to mysql on the local host. This means that the client does not support caching_sha2_password encryption method.

Solution steps:

  1. Enter container
$ docker exec -it mysql-test bash
  1. Sign in
mysql -uroot -p
  1. Check the encryption method of the current root user and find that the encryption method of the root user is caching_sha2_password
select user,host,plugin from mysql.user where user = 'root';

  1. Changing the encryption rules requires resetting the root password
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'root password'; 
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'root password';
  1. Refresh permission configuration
flush privileges;

Topics: MySQL Docker Container Flask