富 Web 时代,应用变得越来越强大,与此同时也越来越复杂。集群部署、隔离环境、灰度发布以及动态扩容缺一不可,而容器化则成为中间的必要桥梁。
本节我们就来探索一下 Docker 的神秘世界,从零到一掌握 Docker 的基本原理与实践操作。别再守着前端那一亩三分地,是时候该开疆扩土了。
We will focus on the following points:
- tell a story
- Virtual machines and containers
- Meet Docker
- core concepts
- install Docker
- quick start
- normal operation
- best practices
1. Tell a story
为了更好的理解 Docker 是什么,我们先来讲个故事:
I needed to build a house, so I moved rocks, cut wood, drew drawings, and built a house. After a series of operations, the house was finally built.

As a result, after living there for a while, I wanted to move to the seaside on a whim. At this time, according to my previous method, I could only go to the seaside and move stones, cut wood, draw drawings, and build a house again.

When I was troubled, a magician came and taught me a kind of magic. This kind of magic can make a copy of the house I built, make it a "mirror image", and put it in my backpack.

When I got to the seaside, I used this "mirror image" to replicate a house and moved in with my bag.
是不是很神奇?对应到我们的项目中来,房子就是项目本身,镜像就是项目的复制,背包就是镜像仓库。如果要动态扩容,从仓库中取出项目镜像,随便复制就可以了。Build once,Run anywhere!
We no longer have to pay attention to issues such as version, compatibility, and deployment, and we completely solve the embarrassment of "collapsing immediately on the launch and endless construction."
2. Virtual machines and containers
Before starting, let's reserve some basic knowledge:
- Virtual machines: Virtualizing hardware
虚拟机 Virtual Machine 指通过软件模拟的具有完整硬件系统功能的、运行在一个完全隔离环境中的完整计算机系统。在实体计算机中能够完成的工作在虚拟机中都能够实现。
在计算机中创建虚拟机时,需要将实体机的部分硬盘和内存容量作为虚拟机的硬盘和内存容量。每个虚拟机都有独立的 CMOS、硬盘和操作系统,可以像使用实体机一样对虚拟机进行操作。在容器技术之前,业界的网红是虚拟机。
虚拟机技术的代表,是 VMWare 和 OpenStack。更多请参看百科虚拟机。
Container: Virtualizes the operating system layer and is a standard unit of software
- Run Everywhere: Containers can package code with configuration files and related dependent libraries to ensure consistent operation in any environment.
- High resource utilization: Containers provide process-level isolation, so CPU and memory utilization can be set more fine-grained, thereby making better use of server computing resources.
- Rapid expansion: Each container can run as a separate process and can share system resources from the underlying operating system, which can speed up container startup and shutdown efficiency.
differences and relations
- 虚拟机虽然可以隔离出很多「子电脑」,但占用空间更大,启动更慢。虚拟机软件可能还要花钱,例如
VMWare; - Container technology does not need to virtualize the entire operating system, only needs to virtualize a small-scale environment, similar to a "sandbox";
- Running space, virtual machines generally require a few gigabytes to tens of gigabytes of space, while containers only require MB or even KB levels;
- 虚拟机虽然可以隔离出很多「子电脑」,但占用空间更大,启动更慢。虚拟机软件可能还要花钱,例如
Let's look at the comparative data:
| characteristics | virtual machine | container |
|---|---|---|
| isolation level | operating system level | process |
| isolation strategy | Hypervisor (Virtual Machine Monitor) | Cgroups (control groups) |
| system resources | 5 ~ 15% | 0 ~ 5% |
| startup time | minute-level | second-level |
| mirrored storage | GB - TB | KB - MB |
| cluster scale | hundreds | tens of thousands |
| High availability strategies | Backup, disaster tolerance, migration | Elasticity, load, dynamics |
与虚拟机相比,容器更轻量且速度更快,因为它利用了 Linux 底层操作系统在隔离的环境中运行。虚拟机的 Hypervisor 创建了一个非常牢固的边界,以防止应用程序突破它,而容器的边界不那么强大。
Physical machine deployment cannot make full use of resources, resulting in waste of resources. When deployed using virtual machines, the virtual machines themselves will occupy a large amount of resources, resulting in waste of resources. In addition, the performance of the virtual machines is also very poor. Container-based deployment is more flexible, lightweight, and has better performance.
Virtual machines belong to virtualization technology, while container technologies such as Docker belong to lightweight virtualization.
3. Know Docker

- concept
Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口。
Docker 技术的三大核心概念,分别是:镜像 Image、容器 Container、仓库 Repository。
- Why Docker is lightweight?
相信你也会有这样的疑惑:为什么 Docker 启动快?如何做到和宿主机共享内核?
当我们请求 Docker 运行容器时,Docker 会在计算机上设置一个资源隔离的环境。然后将打包的应用程序和关联的文件复制到 Namespace 内的文件系统中,此时环境的配置就完成了。之后 Docker 会执行我们预先指定的命令,运行应用程序。
The mirror does not contain any dynamic data and its contents will not be changed after it is built.
4. Core concepts
Build, Ship and Run(搭建、运输、运行);Build once, Run anywhere(一次搭建,处处运行);Docker本身并不是容器,它是创建容器的工具,是应用容器引擎;Docker三大核心概念,分别是:镜像Image,容器Container、仓库Repository;Docker技术使用Linux内核和内核功能(例如Cgroups和namespaces)来分隔进程,以便各进程相互独立运行。- 由于
Namespace和Cgroups功能仅在Linux上可用,因此容器无法在其他操作系统上运行。那么Docker如何在macOS或Windows上运行?Docker实际上使用了一个技巧,并在非Linux操作系统上安装Linux虚拟机,然后在虚拟机内运行容器。 - 镜像是一个可执行包,其包含运行应用程序所需的代码、运行时、库、环境变量和配置文件,容器是镜像的
运行时实例。
更多关于 Docker 的原理,可以查看 Docker 工作原理及容器化简易指南,这里不再赘述。
5. Install Docker
- command line installation
Homebrew 的 Cask 已经支持 Docker for Mac,因此可以很方便的使用 Homebrew Cask 来进行安装,执行如下命令:
brew cask install docker
更多安装方式,请查看官方文档:安装 Docker
- view version
docker -v
- Configure mirror acceleration
设置 Docker Engine 写入配置:
{
"registry-mirrors": [
"http://hub-mirror.c.163.com/",
"https://registry.docker-cn.com"
],
"insecure-registries": [],
"experimental": false,
"debug": true
}
- Install desktop

桌面端操作非常简单,先去官网下载。通过 Docker 桌面端,我们可以方便的操作:
- clone: Clone a project
- build: Packaging images
- run: Run the example
- share: Shared image
Okay, the preparations are ready, and we can show our talents next!
6. Start quickly
After installing Docker, we first mirror the actual project and use it while learning.
- First, we need to have a general understanding of the 11 commands we will use
| command | described |
|---|---|
| FROM | Based on which image is implemented |
| MAINTAINER | Mirror creator |
| ENV | Declare environment variables |
| RUN | execution command |
| ADD | Add host files to the container, and files that need to be extracted will be automatically extracted |
| COPY | Add host files to the container |
| WORKDIR | working directory |
| EXPOSE | Ports available to applications in container |
| CMD | Programs executed after the container is started will be overwritten if docker run is followed by the start command |
| ENTRYPOINT | The same function as CMD, but requires docker run to not overwrite it. If you need to override it, you can add the parameter-entrypoint to override it. |
| VOLUME | Data volume, mapping the host's directory to the directory in the container |
- new project
为了快捷,我们直接使用 Vue 脚手架构建项目:
vue create docker-demo
Try activating it:
yarn serve
访问地址:http://localhost:8080/。项目就绪,我们接着为项目打包:
yarn build
这时候,项目目录下的 Dist 就是我们要部署的静态资源了,我们继续下一步。
需要注意:前端项目一般分两类,一类直接 Nginx 静态部署,一类需要启动 Node 服务。本节我们只考虑第一种。关于 Node 服务,下文我会详细说明。
- Create a new Dockerfile
cd docker-demo && touch Dockerfile
The project directory at this time is as follows:
.
├── Dockerfile
├── README.md
├── babel.config.js
├── dist
├── node_modules
├── package.json
├── public
├── src
└── yarn.lock
可以看到我们已经在 docker-demo 目录下成功创建了 Dockerfile 文件。
- Prepare Nginx images
运行你的 Docker 桌面端,就会默认启动实例,我们在控制台拉取 Nginx 镜像:
docker pull nginx
The following message appears on the console:
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
如果你出现这样的异常,请确认 Docker 实例是否正常运行。
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
镜像准备 OK,我们在根目录创建 Nginx 配置文件:
touch default.conf
Write:
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;
}
}
- configured with mirrors
Open Dockerfile and write the following:
FROM nginx
COPY dist/ /usr/share/nginx/html/
COPY default.conf /etc/nginx/conf.d/default.conf
Let's explain the code line by line:
FROM nginx指定该镜像是基于nginx:latest镜像而构建的;COPY dist/ /usr/share/nginx/html/命令的意思是将项目根目录下dist文件夹中的所有文件复制到镜像中/usr/share/nginx/html/目录下;COPY default.conf /etc/nginx/conf.d/default.conf将default.conf复制到etc/nginx/conf.d/default.conf,用本地的default.conf配置来替换Nginx镜像里的默认配置。
- build images
Docker 通过 build 命令来构建镜像:
docker build -t jartto-docker-demo .
As usual, let's explain the above code:
-t参数给镜像命名jartto-docker-demo.是基于当前目录的Dockerfile来构建镜像
After successful execution, the output will be:
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 mirror image production was successful! Let's take a look at the container:
docker image ls | grep jartto-docker-demo
As you can see, we printed a 133MB project image:
jartto-docker-demo latest 7df6efaf9592 About a minute ago 133MB
There are also good and bad images. We will introduce how to optimize them later, so we can ignore them for now.
- run containers
docker run -d -p 3000:80 --name docker-vue jartto-docker-demo
Explain the parameters here:
-d设置容器在后台运行-p表示端口映射,把本机的3000端口映射到container的80端口(这样外网就能通过本机的3000端口访问了--name设置容器名docker-vuejartto-docker-demo是我们上面构建的镜像名字
One additional point:
在控制台,我们可以通过 docker ps 查看刚运行的 Container 的 ID:
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
如果你使用桌面端,那么打开 Docker Dashboard 就可以看到容器列表了,如下图:

- access Project
因为我们映射了本机 3000 端口,所以执行:
curl -v -i localhost:3000
或者打开浏览器,访问:localhost:3000
- release image
If you want to contribute to the community, you need to publish the image for other developers to use it.
Publishing an image requires the following steps:
- 登录 dockerhub,注册账号;
- 命令行执行
docker login,之后输入我们的账号密码,进行登录; - 推送镜像之前,需要打一个 Tag,执行
docker tag <image> <username>/<repository>:<tag>
全流程结束,以后我们要使用,再也不需要「搬石头、砍木头、画图纸、盖房子」了,拎包入住。这也是 docker 独特魅力所在。
VII. Routine operations
Here, congratulations on completing the Docker entry project! If you still want to go deeper, you might as well keep looking.
- parameter uses
FROM
- 指定基础镜像,所有构建的镜像都必须有一个基础镜像,且
FROM命令必须是Dockerfile的第一个命令 FROM <image> [AS <name>]指定从一个镜像构建起一个新的镜像名字FROM <image>[:<tag>] [AS <name>]指定镜像的版本Tag- 示例:
FROM mysql:5.0 AS database
- 指定基础镜像,所有构建的镜像都必须有一个基础镜像,且
MAINTAINER
- Information about the mirror holder
MAINTAINER <name>- 示例:
MAINTAINER Jartto Jartto@qq.com
RUN
- Commands to execute when building an image
RUN <command>- 示例:
RUN ["executable", "param1", "param2"]
ADD
- Add and copy local files to the container, the compressed package will be decompressed, files on the network can be accessed, and will be downloaded automatically
ADD <src> <dest>- 示例:
ADD *.js /app添加js文件到容器中的app目录下
COPY
- 功能和
ADD一样,只是复制,不会解压或者下载文件
- 功能和
CMD
- 启动容器后执行的命令,和
RUN不一样,RUN是在构建镜像是要运行的命令 - 当使用
docker run运行容器的时候,这个可以在命令行被覆盖 - 示例:
CMD ["executable", "param1", "param2"]
- 启动容器后执行的命令,和
ENTRYPOINT
- 也是执行命令,和
CMD一样,只是这个命令不会被命令行覆盖 ENTRYPOINT ["executable", "param1", "param2"]- 示例:
ENTRYPOINT ["donnet", "myapp.dll"]
- 也是执行命令,和
LABEL: Add metadata to the mirror in the form of key-value
LABEL <key>=<value> <key>=<value> ...- 示例:
LABEL version="1.0" description="这是一个web应用"
ENV: Set environment variables. Some containers require certain environment variables when running
ENV <key> <value>一次设置一个环境变量ENV <key>=<value> <key>=<value> <key>=<value>设置多个环境变量- 示例:
ENV JAVA_HOME /usr/java1.8/
EXPOSE: Expose external ports (the port of the program inside the container will be the same as the host machine, but there are actually two ports)
EXPOSE <port>- 示例:
EXPOSE 80 - 容器运行时,需要用
-p映射外部端口才能访问到容器内的端口
VOLUME: Specifies the directory for data persistence. The official language is called mount
VOLUME /var/log指定容器中需要被挂载的目录,会把这个目录映射到宿主机的一个随机目录上,实现数据的持久化和同步。VOLUME ["/var/log","/var/test".....]指定容器中多个需要被挂载的目录,会把这些目录映射到宿主机的多个随机目录上,实现数据的持久化和同步VOLUME /var/data var/log指定容器中的var/log目录挂载到宿主机上的/var/data目录,这种形式可以手动指定宿主机上的目录
WORKDIR: Set the working directory. After setting, the working directories of RUN, CMD, COPY, and ADD will change synchronously
WORKDIR <path>- 示例:
WORKDIR /app/test
USER: Specifies the user to use when running the command. For security and permissions, select different users based on the command to be executed
USER <user>:[<group>]- 示例:
USER test
ARG: Set the parameters to be passed for building the image
ARG <name>[=<value>]ARG name=sss
更多操作,请移步官方使用文档。
8. Best practices
After mastering Docker's general operations, we can easily print the project image we want. However, the mirror images created by different operations are also very different.
We might as well continue to explore what causes the mirror image difference.
The following are the best practices to compile when applying Docker. Please try to follow the following guidelines:
- Require clarity: What mirrors are needed
- Streamlining steps: Steps with fewer changes are prioritized
- Version clear: mirror name clear
- Documentation: The entire image packaging step can be reproduced
The following two articles are recommended:
IX. Summary
Containerization technology will surely be one of the indispensable skills in the cloud era, and Docker is just a drop in the bucket. Along with it are cluster container management K8s, Service Mesh, Istio and other technologies. Open Docker's door, continue to pull silk and peel off cocoons, and go deep layer by layer, and you will feel the infinite charm of containerization.
Hurry up and open the skill boundaries and empower your front-end technology!
Copyright statement: 文章首发于 Jartto's Blog , 转载文章请务必以超链接形式标明文章出处、作者信息及本版权声明。