
很多人学Docker最大的误区就是还没搞明白底层原理就开始敲命令。比如看到别人跑:
docker run nginx 应用起来了,一片祥和,然后就继续往下走了。但你有没有停下来想过:你敲下回车那一瞬间,到底发生了什么?
Docker看起来像是在"魔法般"地运行你的应用,但实际上每次都走同一套流程。想象成这个样子:
你
│
▼
Docker Client(客户端)
│
▼
Docker Engine(引擎)
│
▼
Docker Hub(如果需要)
│
▼
Docker Image(镜像)
│
▼
Docker Container(容器)
│
▼
Running Application(运行中的应用)
来一个个拆开说。
Docker Client(客户端)
你的命令第一个打交道的就是这个组件。可以把它理解为你和Docker之间的传话人。
当你输入:docker run nginx
Docker Client本身不创建容器,也不下载镜像。它的职责只有一个:接收你的命令,然后转发给Docker Engine。就像你用美团点外卖——你通过App下单,但App本身不做菜,它把你的需求发给餐厅:Docker Client就是干这个的。
Docker Engine(引擎)
Docker Client收到命令后,会把它转发给Docker Engine。如果说Docker Client是传话的,那Docker Engine就是大脑,所有的活都在这儿干。
Docker Engine负责:
没有Docker Engine,Docker压根玩不转。Engine启动后第一个问自己的问题是:"我本地有这个镜像吗?"
如果有,就继续往下走。如果没有,就需要找个地方下载——这就是Docker Hub的用武之地。
Docker Registry(镜像仓库)和 Docker Hub
镜像仓库简单说就是存放Docker镜像的地方。最有名的就是Docker Hub。可以把它理解成代码托管平台,但存的不是源代码,而是Docker镜像。
如果Docker Engine本地找不到镜像,它会自动去Docker Hub下载,存到本地,然后继续后续流程。好消息是Docker只会下载一次镜像。下次再跑同样的镜像,Docker直接用本地那份,速度就快多了。搞清楚这个,你就明白为什么第一次跑Docker命令总比后面慢。
Docker镜像可不是什么蓝图这么简单
你可能听过一种说法:"Docker镜像就是蓝图。"这话没错,但只说了一半。Docker镜像是一个完整的、只读的包,里面装了你应用运行所需的全部东西。
包括:
可以把它想象成应用在某个特定时刻的快照。一旦镜像构建完成,Docker会把它当作不可变的对象——也就是说不会改动。如果你的应用变了,Docker不会去更新已有镜像,而是重新构建一个全新的镜像。
听起来可能有点浪费?实际上这恰恰是Docker最强大的地方。因为镜像永远不变,每个开发者的机器、测试环境、CI/CD流水线、生产服务器跑的都是同一个包。这就是Docker大火的核心原因:它消灭了"在我机器上能跑"这个经典问题。
另外要知道的重点是:镜像是不运行的。它就躺在那里,等着被使用。可以理解成打包好的应用,随时可以启动。
Docker容器:你的应用在这里活过来
很多新手不知道的一件事:Docker从来不直接运行镜像。它总是基于镜像创建一个容器再跑。容器就是Docker镜像的运行实例。和镜像不同,容器是"活的"——它占用CPU、使用内存、处理请求、响应用户。
容器才是真正在执行你应用的部分。Docker的一大优势是:一个镜像可以创建多个容器。
比如:

每个容器都从同一个镜像起步。这就是Docker保证一致性的原因——不是创建三个不同的应用,而是从同一个包创建三个运行实例。
容器还被设计成用完即弃。如果一个容器崩了、坏了、被删了,你不需要去修它,再从原始镜像起一个新的就行。因为镜像从来没变过,新容器的行为和之前那个完全一致。把容器当作一次性用品,是Docker带来的最大思维转变之一——不是去修复运行中的环境,而是重建它们。
更快、更干净、更可预测。
给开发者的建议:如果这段只能记住一件事,就记住这个:
为什么写命令之前必须搞懂这些概念
你可能注意到了,到目前为止我们一个Docker命令都没敲过——这是故意的。
学Docker不是背命令,而是搞懂每次敲命令时底层发生了什么。一旦你理解了Docker Client、Docker Engine、Docker Hub、镜像和容器是怎么配合的,Docker就不再复杂了。命令变得顺理成章,因为你清楚背后的原理。
这个系列的目的就在于此:不只是教你用Docker,而是让你理解它为什么这么设计。
基础打好了,该动手实践了。下一期我们构建第一个Docker镜像,看看Dockerfile是怎么把这些概念串起来的。