Docker 是什么?一张图看懂容器化的三件套

0 阅读5分钟

零、这篇文章讲什么

我最早知道 Docker,是听到一句扎心的话:"我的电脑能跑,你的电脑怎么跑?" 代码在自己机器上好好的,换台机器、换个环境就各种报错。后来在练习里跑通了一次 docker run nginx,才真正明白 Docker 在解决什么问题。

这一篇是我对 Docker 的第一版理解,读完你会得到三样东西:

  1. 一个痛点场景——为什么需要容器化
  2. 一张知识架构图——image / container / registry 三件套的关系
  3. 一个 Git 类比——用你熟悉的东西钉死这三个概念

前置知识:不需要任何容器经验。如果你知道 npm、Git、Node 大概是什么,就够了。

一、为什么需要 Docker

先看痛点。你到公司接手一个 n 年前的 Vue 2 项目,要求用 Node 16 + npm 8 跑起来。而你的电脑装的是 Node 22——大概率直接跑不起来。

这种问题不只在找工作会遇到。代码只是应用的一半,另一半是它依赖的一整套运行环境

  • 语言版本(Node 16 / 22)
  • 依赖库(npm 包、pip 包)
  • 中间件(MySQL、Redis、Nginx)
  • 配置文件(端口、密钥、路径)

这些东西在每台机器上都可能不一样。"跑不起来"通常不是代码的错,是环境的错。 Docker 的答案是把"应用 + 运行环境"打包成一个整体,随处运行:

Agent  = LLM  + Harness(工具/MCP/技能…)
Docker = 应用 + 运行环境

类比:你点的不是"一盘菜",而是"菜谱 + 食材 + 做好的菜"整包带走。到哪台厨房都能直接端上桌,不用重新配食材。

二、一张图看懂

Docker 有三个核心对象:image(镜像)、container(容器)、registry(仓库)。它们的关系长这样:

        Dockerfile                    build                 push
   (造光盘的配方) ------------>  image(光盘) --------->  registry(光盘库)
                                   |                         ↑
                                 run│                         │ pull
                                   ▼                         │
                            container(播放器里        从光盘库拿光盘
                            正在运行的实例)          到本地(docker images)

一句话串起来:build(造)→ push(上传)→ pull(下载)→ run(跑)。下面一节一节拆开讲。

三、核心概念巡礼

1. image:只读的"光盘"

image 是应用的模板——包含了应用程序 + 它需要的运行环境,全部固化在一个只读的单元里。我 readme.md 里的第一版理解就是把它比作"光盘":

  • 只读:镜像构建出来就定型了,你改不动它
  • 分层:一条 Dockerfile 指令生成一层,多层叠加成一个镜像(第 04 篇展开)
  • 可复用:一个镜像可以跑出无数个容器
docker images        # 看本地有哪些"光盘"
docker pull nginx    # 从仓库拿"光盘"到本地

2. container:正在播放的"播放器"

container 是镜像的运行实例——光盘放进播放器开始跑,就是容器。它俩的关系最容易混,记住一句话:

image 是"类",container 是"实例";一个 image 可以 run 出无数个互不干扰的 container。

容器是"临时的、可写的":你在容器里装东西、改文件,都是在这层"薄薄的可写层"上操作;删掉容器,改动随之消失,镜像毫发无损。这也是为什么容器随便删、镜像要珍惜。

docker run -d --name my-nginx -p 80:80 nginx   # 用镜像开一个容器
docker ps                                      # 看正在跑的容器

3. registry:镜头的"光盘库"

registry 是存放和分发镜像的地方。最大的公共仓库是 Docker Hub——nginx、node、mysql、redis 的官方镜像都在那。

镜像的完整名字 = 仓库/命名空间/镜像名:标签

nginx:1.25                                   → Docker Hub 官方,tag 1.25
myname/myapp:v2                              → 私人推送的镜像
registry.cn-xxx.com/company/orders:latest    → 公司私有仓库

你执行 docker run nginx 时,Docker 发现本地没有,就自动去 registry pulllatest 只是约定俗成的标签,不是特殊值。

4. 用 Git 类比钉死

GitDocker
commit(不可变快照)image
checkout 出来的工作区 + 运行中的进程container
GitHub / 远程仓库registry
源文件 + 构建脚本Dockerfile
git push / git pulldocker push / docker pull
分支、标签tag(标签)

你拉代码用 git clone,Docker 拉环境用 docker pull——一个装代码,一个装"代码 + 环境"。

四、串起来:一次完整的容器之旅

跟着 nginx 走一遍,三件套全部上场:

1. 拉取:docker run nginx
     └─ Docker 发现本地没有 nginx 镜像 → 自动去 Docker Hub pull
     └─ 光盘(image)落地到本地

2. 运行:docker run 创建容器
     └─ 用 nginx 镜像开出一个容器(my-nginx)
     └─ -p 80:80:宿主机的 80 端口 → 容器内的 80 端口
     └─ 浏览器访问 localhost:80,看到 nginx 欢迎页

3. 观察:docker ps / docker logs
     └─ 容器在跑,日志在滚,一切可控

4. 清理:docker rm -f my-nginx
     └─ 删容器(可写层消失),nginx 镜像还在本地
     └─ 想再开一个,一条 run 命令即可

四步下来:registry 提供镜像,image 是模板,container 是实例。 这就是 Docker 的日常——不是玄学,是"拿光盘、放播放器、看演出、抽出来"。

五、Docker 到底解决了什么

回到开头的痛点,容器化带来的四个红利:

痛点容器化后的答案
环境不一致,换了机器跑不起来应用 + 环境一起打包,处处一致
装环境又慢又容易出错docker run 一条命令,秒级起服务
一堆服务版本互相打架各自隔离在自己的容器里
部署到服务器要重新配一遍同一个镜像,在哪都是同一个结果

一句话总结价值:Docker 把"运行环境"也变成了代码,可以构建、分发、版本管理——和代码本身一样。

小结

三件套一句话记忆:

概念一句话代码证据
image只读模板,应用 + 环境打包好的"光盘"docker pull nginx
containerimage 的运行实例,可写可删,随时重开docker run -d --name my-nginx nginx
registry存放分发镜像的"光盘库"docker push / pull