Time for a cup of tea


Time for a cup of tea

Working hard and then falling asleep, there seems to be no correlation between “working” and “dreaming”; writing code and deploying applications seem to be on each side of the sky. But is it true? This article will open docker in the way of inception, so that you can realize the substantial transformation from “dream” to “dream building”. In the original “dream” stage (manual configuration and deployment), everything is full of randomness and uncontrollability, and sometimes you can’t even recall every step. In the dream building stage (with docker), you can easily implement any configuration and deployment tasks in an automated, highly repeatable and traceable way. Hope that after reading this article, you can also become an excellent “dream builder”!

If you think we write well, rememberLike + follow + commentSanlian, encourage us to write better tutorials


The words written in the front

Many friends have told us that “a cup of tea” is just to deceive people. How can it be finished in a cup of tea for such a long time? In fact, the way of “drinking tea” varies from person to person, and different readers have different rhythm. You can choose to read all the lines at a glance, even browse the illustrations, and you can read them in a few minutes. You can also choose to follow us step by step and even stop to think about it in some places. Although it takes more time, we believe that the time invested must be worthwhile.

Secondly, we want to confirm whether you are the audience of this article:

  1. If you’re already a Devops boss who operates thousands of containers every day, I’m sorry to disturb you. This article may be too simple for you;
  2. If you are already familiar with docker and want more practical operation experience, this article can better help you review and consolidate the key knowledge points;
  3. If you’ve only heard of docker, but you can’t use it, then this article is for you! Just a friendly reminder:Docker is a little difficult to master. If you want to really master it, you need to invest enough time. After reading this article carefully, you will make great progress

Finally, the structure of each section isPractical training + recollection and sublimation。 The part of memory and sublimation is that the author spent a lot of time collecting and integrating high-quality resources, and combined with his own experience in using containers. I believe it can further deepen your understanding. If you are in a hurry, you can also skip it.

PS: This article doesn’t talk about the background, concept and advantages of docker seriously like the regular docker tutorial (most likely you’ve heard the ear cocoon HHH), but understands docker intuitively through practice. In the end, we will post the classic docker architecture diagram. Combined with the previous operation experience, I believe you will have a clear feeling.


Before reading this article, we hope you have the following qualifications:

  • Basic command line experience
  • Have a certain understanding of computer network, especially in the application layerportThis concept
  • It’s better to experience the painful struggle of environment and project deployment

What will we achieve

Now suppose you have a dream list project written by react, as shown in the following diagram:

Time for a cup of tea

In this article, we will teach you to use docker to container the application step by step, and use nginx server to provide built static pages.

You will learn

Time for a cup of tea

This article will not deal with

Of course, as an introductory tutorial, this article will not cover the following advanced contents:

  • Docker network mechanism
  • Data sharing between data volume and bind mount
  • Docker Compose
  • Multi stage build
  • Docker machine tool
  • Container choreography technologies such as kubernetes and docker swarm

Above advanced knowledge, we will soon launch the relevant tutorial, please look forward to.

Install docker

We recommend that each platform install docker in the following way (after repeated testing).


The novice tutorial introduces the different recommended installation methods of win7 / 8 and win10 in detail. Note that win10 recommends enabling Hyper-V virtualization.


You can download and install the DMG file by clicking the official download link (if the speed is slow, you can copy the link into Xunlei). After installation, click the docker application icon to open it.


For major Linux distributions (Ubuntu, CentOS, etc.), we recommend using official scripts for installation

curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh

Then recommend that thedockerThe permissions of are handed over to the non root user to usedockerYou don’t have to do it every timesudoWe have:

sudo usermod -aG docker $USER

It will take effect after the user is logged off or restarted. And then through thesystemdService configuration docker startup:

sudo systemctl enable docker

Configure image warehouse

The default image warehouse docker hub is abroad, and the pull speed in China is quite moving. It is recommended to refer to this article to configure image acceleration.

Mirror image and container: Dream architect’s drawings and dreams

image(image) andcontainerContainer is the most basic and key concept in dockerDream builder’s drawingsAccording to the content of this drawing, it can be generatedCompletely predictable dreams(i.e. the latter).


If you find this metaphor hard to understand, you can compare the two concepts of “class” and “instance” in object-oriented programming, “class” is equivalent to “mirror image” and “instance” is equivalent to “container”.

The place where dreams begin

After touching on the two basic concepts of mirror and container, we intend to pause the theoretical explanation and let you have a quick experience with a wave of small experiments.

Experiment one: Hello world!

According to historical conventions, we run Hello world from docker. The command is as follows:

docker run hello-world

The output is as follows:

Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
1b930d010525: Pull complete
Digest: sha256:fb158b7ad66f4d58aa66c4455858230cd2eab4cdf29b13e5c3628a6bfc2e9f05
Status: Downloaded newer image for hello-world:latest

Hello from Docker!

Don’t you just print a string and exit? Is that amazing? In fact, docker has done the following things for us in silence:

  1. Check if there is a specified localhello-world:latestMirror image(latestIf not, go to step 2; otherwise, go to step 3
  2. Unable to find XXX locally is not specified. Download it from docker hub
  3. According to the localhello-world:latestImage creates a new container and runs the program in it
  4. After running, the container exits and control is returned to the user

Experiment 2: run an nginx server

Too simple? Let’s try an advanced one: run an nginx server. Run the following command

docker run -p 8080:80 nginx

After running, you will find that it has been stuck, and there is no output, but rest assured that your computer did not crash. Let’s open the browserlocalhost:8080

Time for a cup of tea

At this time, friends familiar with nginx may not be able to sit still: a simple onedocker runCommand to complete the installation and deployment of the nginx server?? Yes, you can continue to access routes that do not exist, such aslocalhost:8080/what404. At this time, if we look at the output of the docker container, we will see the content (server log)

Time for a cup of tea

To summarize what docker did just now:

  1. Check if there is a specified localnginx:latestMirror (aboutlatestIf not, go to step 2; otherwise, go to step 3
  2. Unable to find XXX locally is not specified. Download it from docker hub
  3. According to the localnginx:latestImage creates a new container,And passed-p--publish)Parameter to establish the mapping between port 8080 of the local machine and port 80 of the container, and then run the program
  4. The nginx server program remains running and the container does not exit


The format of the port mapping rule is< native port >: < container port >。 The nginx container opens port 80 by default. We set the8080:80The port mapping rules can be accessed locally (outside the container) through thelocalhost:8080Access, even in the same LAN through the intranet IP access, this article will demonstrate at the end of oh.

Experiment 3: running nginx in the background

It looks cool, but for processes like nginx servers, we prefer to leave it in the background and run all the time. Press Ctrl + C to exit the current container, and then run the following command again:

docker run -p 8080:80 --name my-nginx -d nginx

Note that unlike before, we:

  • A parameter is added--nameTo specify that the container name ismy-nginx
  • An option has been added-d--detach), which means “run in the background”


The name of the container must be unique, and if a container with the same name already exists (even if it is no longer running), the creation fails. If this happens, you can delete containers that you didn’t need (I’ll explain how to delete them later).

Docker will output a long 64 bit container ID, and then return the control of the terminal to us. We tried to visitlocalhost:8080You can also see a string of familiar welcome to nginx! To show that the server is really running in the background.

How do we manage this server? It’s like the familiar UNIXpsThe order is the same,docker psThe command allows us to view the status of the current container:

docker ps

The output is as follows:

Time for a cup of tea


becausedocker psIf you think the result is not intuitive, you can lengthen the terminal (command line), as shown in the following figure:

Time for a cup of tea

From this table, we can clearly see some information about the nginx server container we are running in the background:

  • The container ID is0bddac16b8d8(it may be different on your machine)
  • The image used isnginx
  • Run the command / program asnginx -g 'daemon of...This is the running command of the nginx image. Don’t worry about it for the time being
  • Created 45 seconds ago
  • The current status is up 44 seconds
  • Ports are0.0.0.0:8080->80/tcp, which means to access the local0.0.0.0:8080All requests for are forwarded to the container’s TCP 80 port
  • The names are just specifiedmy-nginx

If we’re going to stop the container, go throughdocker stopThe command specifies the container name or ID to operate. The command is as follows:

docker stop my-nginx
# docker stop 0bddac16b8d8

be careful

If you specify the container ID, remember to change it to the real ID on your machine. In addition, ID can only write the first few characters, such as write0bdIt can be.

Experiment 4: interactive operation

After an addiction to the nginx server, let’s experience another way to open the docker containerInteractive operation。 Run the following command to enter an Ubuntu image:

docker run -it --name dreamland ubuntu

You can see that we added it-itOption, which is equal to specifying at the same time-i--interactive, interactive mode) and-t--ttyAssign an analog terminal) two options. The output of the above command is as follows:

Unable to find image 'ubuntu:latest' locally
latest: Pulling from library/ubuntu
2746a4a261c9: Pull complete
4c1d20cdee96: Pull complete
0d3160e1d0de: Pull complete
c8e37668deea: Pull complete
Digest: sha256:9207fc49baba2e62841d610598cb2d3107ada610acd4f47252faf73ed4026480
Status: Downloaded newer image for ubuntu:latest
[email protected]:/#

Wait a minute. How are we left on a new command line? Yes, you are now in the “dream” built by the Ubuntu image. You can “swim” at will and run some commands:

[email protected]:/# whoami
[email protected]:/# ls
bin   dev  home  lib64  mnt  proc  run   srv  tmp  var
boot  etc  lib   media  opt  root  sbin  sys  usr

For example, we run on itwhoamiandlsCommand, you’re basically sure you’re in the “dream” (container) now. At this time, open a new terminal (command line) and run itdocker psCommand, you can see the running Ubuntu image:

Time for a cup of tea

Back in the previous container, press Ctrl + D (or enterexitCommand) to exit. You can check beforedocker psThe terminal of the container is checked again to see if the container has been closed.

Destroy the container: listen to the sound of dream breaking

It is inevitable that dream builders will have failed works. The docker container we just created is only for preliminary exploration and will not be used in the future. Since the docker container is directly stored on our local hard disk, cleaning the container in time can also reduce the pressure on our hard disk. We can view all containers (including those that have been stopped) with the following command:

docker ps -a

-a--all)It is used to display all containers. If it is not added, it will only be displayedIn operationContainer. You can see that the output is as follows (here I widen the terminal, so you can see it conveniently)

Time for a cup of tea


You may have observed that in previous experiments 1 and 2, we did not specify the container name, but docker gave us a rather interesting default container name (for examplehardcore_nash), the format is a random adjective plus the last name of a famous scientist / Programmer (with luck, you may see the father of LinuxtorvaldsOh).

Similar to shellrmOrders, we can go throughdocker rmCommand to destroy the container, such as deleting thedreamlandContainer:

docker rm dreamland
#Or specify the container ID and remember to replace it with one on your own machine
# docker rm 94279dbf5d93

But what if we want to destroy all the containers? Input again and againdocker rmIt is obviously inconvenient to delete, which can be easily deleted by the following commandAll containers

docker rm $(docker ps -aq)

docker ps -aqThe ID of all containers is output and passed as a parameter todocker rmCommand, you can delete all containers by ID.


Be sure to check whether there are any before implementationof valueBecause once the container is deleted, it cannot be retrieved again (this black technology of hard disk recovery is not discussed here)!

Recollection and sublimation

About port mapping

Maybe some students still don’t fully understand the concept of “port mapping”8080:80For example, we can use the metaphor of “portal” to understand this mapping rule (the following figure is the cover of “Portal 2”):

Time for a cup of tea

Or compare the container to “dream” and the local environment to “reality” to access the local computer by establishing port mapping8080The request from the port will be “delivered” to the container80Port, isn’t it amazing.

Container life cycle: Dream map

After finishing the above four small experiments, you may have a very intuitive feeling and understanding of the docker container. It’s time to present the docker container life cycle diagram of Sang Xin Jing Kuang https://docker-saigon.github…. ):

Time for a cup of tea

At first glance, this picture has a visual impact and even makes you feel overwhelmed. It’s OK. We can roughly interpret the four types of elements in this picture

  1. Container status(colored circles): including created, running, suspended, stopped, and deleted
  2. Docker command(arrow withdockerOpening text): includesdocker rundocker createdocker stopwait
  3. event(rectangular box): includescreatestartdiestopalsoOOM(out of memory) and so on
  4. There is also a condition to judge whether the container needs to be restarted according to the restart policy

OK, it’s hard to understand this picture at once, but do you remember the four small experiments we did just now? In fact, we have taken a total of two paths (which are also the most frequently used in daily use), and we will analyze them one by one.

The first path (natural end)

Time for a cup of tea

As shown in the figure above:

  • Let’s go firstdocker runTo create and start a container, enter therunning state (Running)
  • Then the program runs out (e.g. after outputting Hello world, or by using Ctrl + C to terminate the program), the container dies (die)
  • Since we have not set a restart policy, we directly enter theStop state(Stopped)
  • Finally, it was approveddocker rmCommand to destroy the container, enter theDeleted status(Deleted)

The second path (compulsory end)

Time for a cup of tea

  • We still go throughdocker runTo create and start a container, enter therunning state (Running)
  • And then through thedocker stopCommand to kill the program in the container (die) and stop (stop) the container, and finally enter theStop state(Stopped)
  • Finally, it was approveddocker rmCommand to destroy the container, enter theDeleted status(Deleted)


Some sharp eyed readers may find thatdocker killanddocker stopTheir functions are very similar, with subtle differences before them:killThe command sends sigkill signal (or other specified signal) directly to the program running in the container, andstopSIGTERM is sent first and then sigkill signal is sentElegant closing(Graceful Shutdown)。

A shortcut: delete running containers

In fact, there is a shortcut not drawn in the life cycle diagram: directly from theIn operation(orIn pause)ToDeletedBy givingdocker rmCommand plus options-f--forceIn order to achieve the following:

#Suppose dreamland is still running
docker rm -f dreamland

Similarly, we can delete all containers, regardless of their state:

docker rm -f $(docker ps -aq)

Free exploration

You are free to explore other routes that we haven’t taken, such as trying to restart containers that were stopped before(docker start), or pause the running container(docker pause)。 Fortunately,docker helpCommands can provide us with a compass to explore, for example, we want to understandstartHow to use the command:

$ docker help start

Usage:    docker start [OPTIONS] CONTAINER [CONTAINER...]

Start one or more stopped containers

  -a, --attach                  Attach STDOUT/STDERR and forward signals
      --checkpoint string       Restore from this checkpoint
      --checkpoint-dir string   Use a custom checkpoint storage directory
      --detach-keys string      Override the key sequence for
                                detaching a container
  -i, --interactive             Attach container's STDIN

After reading this, I believe you have learned how to create containers and manage them with existing images. Next, we will take you to create your own docker image and start to become a standard “dream builder”!

The first application of containerization: the journey of dream building

In the previous steps, we experienced images that others had prepared for us in advance (e.ghello-worldnginxandubuntu)These images can be found in the docker hub image repository. In this step, we will start the dream building journey: learn how toContainerization(containerization) your app.

As we said at the beginning, we will container a full stack “dream list” application, run the following command to get the code, and then enter the project:

git clone -b start-point https://github.com/tuture-dev/docker-dream.git
cd docker-dream

In this step, we will container the front-end application written in react, and use nginx to provide access to front-end pages.

What is containerization

Containerization consists of three stages

  • Write codeWe have provided the written code
  • Building a mirror imageThis is the core content of this section, which will be expanded in detail below
  • Create and run containers: running our application as a container

Building a mirror image

There are two ways to build docker image

  1. Manual: create and run a container based on the existing image, enter it to modify it, and then rundocker commitCommand creates a new image based on the modified container
  2. automatic: create a dockerfile file, specify the command to build the image, and then use thedocker buildThe command creates the image directly

Due to the limited space, this article will only explainMost widely usedThe second way to create a mirror.

Some preparatory work

Let’s put the front-end project firstclientBuild a static page. Make sure node and NPM are installed on your machine (click here to download or usenvm), and then enter theclientDirectory, install all dependencies, and build the project:

cd client
npm install
npm run build

After a while, you should be able to seeclient/buildDirectory, which stores the front-end static page we want to show.

Create nginx configuration fileclient/config/nginx.confThe code is as follows:

server {
    listen 80;
    root /www;
    index index.html;
    sendfile on;
    sendfile_max_chunk 1M;
    tcp_nopush on;
    gzip_static on;

    location / {
        try_files $uri $uri/ /index.html;

Students who are not familiar with nginx configuration need not worry, just copy and paste. The above configuration roughly means: listen to port 80, the root directory of the web page is in the/www, the front page file isindex.html, if you visit/Documents will be providedindex.html

Create dockerfile

Then there is the most important code in this step: dockerfile! establishclient/DockerfileFile, code as follows:

FROM nginx:1.13

#Remove default configuration for nginx
RUN rm /etc/nginx/conf.d/default.conf

#Add custom nginx configuration
COPY config/nginx.conf /etc/nginx/conf.d/

#Copy the front-end static files to the / www directory of the container
COPY build /www

You can see that we used three instructions in the dockerfile:

  • FROMUsed to specify the base image, here we base onnginx:1.13Image as the starting point of construction
  • RUNThe command is used to run any command within the container (provided, of course, that the command must exist)
  • COPYThe command is used to copy the file from the directory where dockerfile is located to the path specified by the container

It’s time to build our image. Run the following command:

#If you are already in the client directory
#(note that there is a dot at the end of the list, which represents the current directory)
docker build -t dream-client .

#If you go back to the project root directory
docker build -t dream-client client

As you can see, we have designated-t--tag, container label) isdream-clientFinally, the context directory (that is, the current directory) of the build container is specified.orclient)。

After running the above command, you will find that:

Sending build context to Docker daemon:66.6MB

And the number is still growing, just like the scenes in hacker science fiction movies, which should stop at about 290mb in the end. Then a series of steps (4) were run, and the image was successfully constructed.

Why is the build context so large? Because we put nodes that are heavier than black holes_ Modules have been added! (I can’t help but think of the picture below)

Time for a cup of tea

Use. Dockeignore to ignore unnecessary files

Docker provides a mechanism similar to. Gitignore, which allows us to ignore specific files or directories when building images. establishclient/.dockerignoreFile (note that there is a dot in front of dockeignore)


Very simply, we just want to ignore the terrible node_ modules。 Run the build command again:

docker build -t dream-client .

Time for a cup of tea

Excellent! This time it’s only 1.386mb, and the speed is obviously much faster!

Run container

Finally, the last step of containerization is to create and run our container! Run thedream-clientImage:

docker run -p 8080:80 --name client -d dream-client

Similarly, we set the port mapping rule to8080:80, container name isclientAnd through-dSet to run in the background. Then visitlocalhost:8080

Time for a cup of tea

succeed! At the beginning of the set three dreams have been completed!


Even, we have access to the “dream list” through the intranet. Linux or MacOS students can input at the terminalifconfigCommand to query the local intranet IP, windows students are in the CMD inputipconfigTo query the local intranet IP address, the10172.16~172.31or192.168start. For example, my intranet IP address is192.168.0.2, then in the same LAN (generally WiFi), you can use other devices (such as your mobile phone) to access192.168.0.2:8080

Recollection and sublimation

About mirror labels

In the actual combat just now, you may have noticed that docker always adds one for us when pulling and building images:latestTag, this one:latest“Up to date” means “up to date”. Like the software version mechanism, images can also be “versioned” through tags.

be careful

latestIt literally means “up-to-date”, but it’s just a common label, which can’t ensure that it’s really “up-to-date”It will not be updated automatically。 Please refer to this article for more discussion.

In fact, it is quite possible to specify labels when pulling or building images (which is generally considered a good practice)

docker pull nginx:1.13
docker build -t dream-client:1.0.0

You can also label existing images:

#Label the default latest image with a newest label
docker tag dream-client dream-client:newest
#You can even change the name and label of the image at the same time
docker tag dream-client:1.0.0 dream-client2:latest

As you can see, the label may not necessarily be a version, it can also be any string (of course, it’s better to make sense, otherwise after a while, you won’t remember the function of the container with this label).

About dockerfile

Dockerfile is actually the default name. Of course, we can take an individual name, such asmyDockerfile, and then specify when you build the mirror-f--file)Parameters are as follows:

docker build -f myDockerfile -t dream-client .

Here are two classic scenarios:

  1. For example, in web development, createDockerfile.devUsed to build development image, createDockerfile.prodBuild the mirror image in the production environment;
  2. When training AI models, createDockerfile.cpuUsed to build images trained with CPU, createDockerfile.gpuConstruct the image of GPU training.

Rethinking the relationship between image and container

After the container combat just now, I believe you have a new understanding of the relationship between image and container. Take a look at the following picture:

Time for a cup of tea

In the previous “small trial ox knife” link (marked with the green arrow), we:

  1. adoptdocker pullPull the image from the docker image warehouse to the local
  2. adoptdocker runCommand to create and run a container based on the image
  3. adoptdocker stopAnd so on command operation container, causes it to have each kind of state transition

In this section of containerization (marked with a red arrow), we:

  1. adoptdocker buildCommand to build an image based on a dockerfile file
  2. adoptdocker tagCommand, label the image to get a new image
  3. It was passed (because of the limited space)docker commitCommand to convert an existing container to a mirror image

Panoramic view: docker architecture

It’s time to present the classic docker architecture diagram:

Time for a cup of tea

As you can see, docker follows the classic client server architecture, and its core components include:

  • Server (also known as docker daemons), in Linux system, isdockerdcommand
  • The rest API exposed by the server provides an interface for communication and operation with the daemons
  • The client (that is, the command-line program we’ve been using all the timedocker

At this point, this quick introduction to docker is over. I hope you have a preliminary understanding of the concept and use of docker. In the future, we will publish advanced docker content (such as network network, volume data volume, docker compose, etc.), and we will take you to deploy a full stack application (front and rear end and database) to the virtual machine (or any machine you can log in to). Please look forward to it~

Want to learn more wonderful practical skills course? Come and visit Tuque community.

Time for a cup of tea