大家好,我是程序员柏风,AI 最全的 Vibecoding 学习地图 http://coderoadmap.cn 作者。
容器是什么
这一课你将能做到
- 用一张表说清物理机、虚拟机、容器在「内核、启动速度、体量、隔离粒度」上的差异
- 用 Java「类与对象」的类比,准确讲清镜像与容器的关系
- 说出你的 Spring Boot + MySQL + Redis 项目为什么值得容器化,以及容器化不解决什么
为什么要学
先看三个真实场景:
场景一:你本地 JDK 21、MySQL 8.0、Redis 7,代码跑得好好的;测试服务器是 JDK 17、MySQL 5.7、Redis 5,启动直接报 UnsupportedClassVersionError。场景二:新同事入职装环境,装了一下午,最后卡在一个 Redis 配置文件上。场景三:上线部署,运维在服务器上手动传 jar、改配置、敲启动脚本,每一步都靠人肉,改一处错一处。
三个问题的共同根源是:应用和它的运行环境是分开的。JDK 版本、系统库、时区、目录结构,全靠人记、靠文档、靠运气。
容器做的事,就是把「应用 + 它依赖的运行时」打成一个标准化的、可搬运的交付单元——镜像。开发、测试、生产跑的是同一份镜像,环境不一致从根源上消失。
对 Java 后端工程师来说,容器是部署上岗证:面试必问、生产在用、CI/CD 依赖它。这一课不装环境、不敲部署命令,只打概念地基——后面 11 课的所有操作都建立在「镜像、容器、隔离」这三个词的准确理解上。
先建立图像
物理机: [硬件] → [OS] → [你的进程们]
一切共享,互相干扰
虚拟机: [硬件] → [OS] → [Hypervisor] → [Guest OS + 你的进程]
每台 VM 自带一整套操作系统,重
容器: [硬件] → [OS] → [容器引擎] → [进程 A | 进程 B | 进程 C]
共享内核,进程级隔离,轻
本站技术栈容器化后的部署图(后面课程会亲手搭出来):
浏览器 / 客户端
│
▼
Spring Boot 容器 (:8080) ← jar + JRE 钉死在镜像里
│ │
▼ ▼
MySQL 容器 Redis 容器
(:3306) (:6379)
│ │
└─ 数据落在数据卷(volume),容器删了数据还在
用你已有的 Java 知识类比:
// 镜像 Image ≈ 类(Class):只读模板,定义"这个进程怎么跑"
// 容器 Container ≈ 对象(Object):由类创建的运行实例,可同时存在多个
Image springBootImage = ...; // docker pull / docker build 得到
Container app1 = springBootImage.newInstance(); // docker run → 容器 1
Container app2 = springBootImage.newInstance(); // 同一镜像再跑一个,互不干扰
| 维度 | 物理机 | 虚拟机 | 容器 |
|---|---|---|---|
| 内核 | 自有 | 每台 VM 自带 Guest OS 内核 | 共享宿主机内核 |
| 启动 | 分钟级 | 分钟级 | 秒级 |
| 体量 | — | 常见 GB 级 | 常见 MB~几百 MB |
| 隔离粒度 | 无 | 整机级(最强) | 进程级(够用,但不是绝对安全边界) |
人话:虚拟机是「每层楼独立装修水电再住人」;容器是「同一栋楼里每人一个房间,共用水电管道(内核),但门锁(namespace)各归各」。
跟着做
本课不要求已安装 Docker,重点是建立概念 + 亲手确认事实。
步骤 1:写下你当前的部署痛点
打开笔记回答三个问题:
- 你的 Spring Boot 项目本地怎么跑?(IDE 直跑?
mvn spring-boot:run?) - 测试/生产环境的 JDK、MySQL、Redis 版本和本地一致吗?谁保证的?
- 换一台全新服务器,几步能把项目跑起来?
应看到至少一条「靠人记」「靠文档」「路径写死」——这就是容器要消灭的摩擦点。
步骤 2:在 Docker Hub 亲手验证「镜像是一份现成配方」
浏览器打开 https://hub.docker.com/_/mysql,切到 Tags 页:8.0、8.0.40、8.0-debian、8.0-oracle……同一版 MySQL 有很多变体,每个 tag 就是一份固定配方。任何机器执行 docker pull mysql:8.0 拉到的内容完全一致——这就是「环境一致性」的实现方式。
步骤 3:核对镜像与容器的类比
在笔记写下两句,后面课程反复对照:
- 镜像 = 只读模板。一个镜像可以同时跑出 N 个容器,就像一个类可以 new 出 N 个对象。
- 容器 = 运行实例。对容器内文件的修改只发生在它自己的「可写层」,删容器即丢弃;镜像本身永远不变。
步骤 4:理解「共享内核」的三个推论
记下来,这是面试高频考点:
- 容器里没有第二个操作系统内核,所以启动秒级、体量小。
- 因为共享内核,Linux 容器只能跑在 Linux 内核之上——Windows 是通过 WSL2 提供一个 Linux 内核来跑 Linux 容器的(下一课就装)。
- 因为隔离是进程级的,容器不是绝对安全边界——root 权限、密钥管理等问题第 11 课专门处理。
步骤 5:画出你项目的容器化草图
在纸上画 Spring Boot → MySQL → Redis 三个框,每个框旁标注两件事:「镜像里钉死什么」「什么数据必须留下」。应看到:应用本身可以完全进镜像;MySQL 的数据、Redis 的持久化文件,必须放到容器外面(第 8 课的数据卷)。
讲清楚要点
- 容器不是迷你虚拟机:官方定义是「对进程加上隔离(namespaces)与资源限制(cgroups)后的运行方式」。它本质是一个被隔离的进程,不是一台机器。
- 交付单位从「jar」变成「镜像」:以前交付 jar + 一份部署文档 + 运维经验;现在交付镜像,依赖全部钉死。CI 构建一次,各环境 pull 同一个 tag,版本天然对齐。
- 镜像是分层只读的:多个 Spring Boot 镜像可共享同一个 JRE 基础层,磁盘和传输都省。细节在第 4 课展开。
- 容器是可丢弃的(ephemeral):正确用法是「容器随时删、随时重建;数据放卷,配置放环境变量」。把状态存在容器里是反模式。
- Docker ≠ Kubernetes:Docker 解决单机上「构建、分发、运行」;K8s 解决多机集群的「调度、扩缩容、自愈」。本课程走完 Docker,第 12 课给 K8s 方向地图。
- OCI 是开放标准:Docker 是最常用的工具链,但镜像格式与运行时接口由 OCI 标准化,同一份镜像 containerd、podman 也能跑,不会被厂商锁死。
你可能会懵的地方
-
容器里到底有没有一整套 Linux? 镜像里通常有一份精简的「用户态」文件(shell、libc、包管理器),比如 Debian 或 Alpine 的 rootfs;但内核就是宿主机那一个,没有第二个内核。Alpine 基础镜像只有 5MB 左右,小的是用户态文件,不是自带了新内核。
-
「把 jar 拷到服务器上跑」和容器差在哪? jar 的运行依赖服务器上的 JDK 版本、系统时区、字体、locale……镜像把这些全部打进交付物。人话:以前是「寄行李,到了对方城市借衣服穿」;现在是「连人带衣柜一起寄过去」。
-
同一镜像能同时跑多个容器吗?端口不冲突吗? 能,进程和文件系统完全隔离。端口是否冲突取决于
-p映射:-p 8081:8080和-p 8082:8080可以让同一镜像的两个容器同时对外服务。第 9 课细讲。 -
Docker 和虚拟机会互相取代吗? 不会,解决的问题不同:强隔离、多内核(跑不同操作系统)用虚拟机;快速交付、高密度部署用容器。云上常见架构是「虚拟机里面跑容器」。
-
为什么说容器不是绝对安全的? 共享内核意味着一旦内核级漏洞被利用(所谓「容器逃逸」),隔离可能被穿透。所以生产上要非 root 运行、最小镜像、最小暴露面、定期扫漏洞——第 11 课逐条落实。
错法对照
| 错法 | 问题 | 正解 |
|---|---|---|
| 把容器当虚拟机用,进去装一堆东西「养」起来 | 容器可丢弃,重建即丢 | 状态放数据卷,配置放环境变量 |
| 认为「改了容器里的文件 = 改了镜像」 | 容器有独立可写层 | 改 Dockerfile 重新 build |
| 数据库数据直接放容器可写层 | 删容器数据全没 | 挂 volume(第 8 课) |
| 一上来直接学 Kubernetes | 缺镜像/网络/卷的地基 | 先走完本课程 |
| 说「Docker 就是轻量级虚拟化」 | 面试官会追问到底 | 说清:共享内核 + 进程级隔离 |
| 期望容器解决所有环境问题 | 基础镜像版本、CPU 架构(amd64/arm64)也要管理 | 固定 tag + 明确架构 |
卡点急救
- 概念太多记不住:只记三句话——镜像保证「带什么依赖出发」,容器是「这一次怎么跑」,数据卷决定「数据放哪」。后面课程围绕这三句展开。
- 分不清镜像和容器:装好 Docker 后,
docker images看到的是「类」,docker ps -a看到的是「对象」(包括已停止的)。 - 担心 Windows 上学不了:Docker Desktop + WSL2 让 Windows 完整支持 Linux 容器,本课程所有命令在 PowerShell 下同样适用。
- 不知道学到什么程度算够:本课程的终点是——不查资料,手写 Dockerfile 和 compose 文件,把 Spring Boot + MySQL + Redis 一键拉起且数据可持久化。
面试常问
-
容器和虚拟机的区别?(出现率极高) 关键三点:内核(容器共享宿主机内核,VM 有独立 Guest OS);启动速度(容器秒级,VM 分钟级);体量与密度(容器 MB 级、单机可跑几十上百个,VM GB 级)。补充一句隔离强度:VM 更强,容器是进程级隔离——能主动说出这句是加分项。
-
镜像和容器的关系? 模板与实例。镜像是分层只读文件系统 + 启动参数模板;容器 = 镜像 + 一个可写层 + 运行中的进程。同一镜像可派生任意多个容器。
-
Docker 解决了什么问题? 环境一致性(依赖钉死进镜像)、交付标准化(一次构建到处运行)、资源利用率(共享内核、高密度部署)、秒级启停支撑弹性伸缩。
-
容器里能跑 Windows 程序吗? Linux 容器只能跑 Linux 进程。Windows 容器是另一条产品线(很少用)。Java/MySQL/Redis/Nginx 全部属于 Linux 容器生态。
自测三问
- 为什么容器启动是秒级而虚拟机是分钟级?
- 「同一镜像在多台机器跑出一致环境」是如何实现的?依赖什么机制?
- 你的 Spring Boot 项目容器化后,哪些东西必须在容器外持久化?
小结一句话
容器是共享宿主机内核的轻量隔离运行单元,镜像把应用与依赖钉死为标准交付物——它消灭的不是某个 bug,而是「环境不一致」这一整类问题。
延伸
- Docker 官方概览
- What is a container?
- 下一课预告:安装 Docker 并跑通
hello-world,配好国内镜像加速。