第2章:容器技术基础——Docker核心概念与虚拟机对比

各位同学,咱们今天聊聊Docker的核心概念。说实话,我刚接触容器时也被一堆术语搞晕过——镜像、容器、仓库,这三个东西到底是什么关系?别急,我一个个给你拆开讲。

2.1 镜像(Image)——容器的“模板”

镜像,说白了就是一个只读的模板。它包含了运行某个应用所需的一切:代码、运行时、系统工具、库文件、环境变量……嗯,你可以把它想象成一个压缩包,里面装着完整的运行环境。

我个人习惯把镜像比作“类”的概念——就像面向对象编程里的Class。你定义好这个类,它本身不干活,但能用来创建实例。镜像也一样,它本身不能直接运行,但能用来启动容器。

关键点:镜像是分层构建的。每一层都是只读的,修改时只会新增一层,不会改动底层。这带来了两个好处:

  • 节省空间——多个镜像可以共享相同的基础层
  • 加速构建——修改只影响新增层,缓存层可以直接复用

我在项目中遇到过一个问题:团队里有人每次构建镜像都从头开始,结果一个200MB的镜像要等10分钟。后来我建议用多阶段构建,把编译环境和运行环境分开,镜像体积直接降到50MB,构建时间也缩短到2分钟。这就是分层的好处。

2.2 容器(Container)——镜像的“运行实例”

容器,就是镜像跑起来之后的样子。它有一个可写层,所有运行时产生的数据都写在这里。你可以启动、停止、删除容器,但镜像始终不变。

你想想看,这跟虚拟机有什么区别?虚拟机里你装了个操作系统,然后装应用,每次修改都会影响整个系统。但容器不一样——它只关心应用本身,底层操作系统是共享的。

我的经验:刚开始用Docker时,我总喜欢在容器里装一堆调试工具,比如vim、curl、netstat。后来发现这完全没必要——容器应该保持最小化,调试工具应该通过宿主机或专门的调试容器来提供。我曾经因为一个容器里装了Python、Node.js、GCC三个运行时,结果镜像体积飙到1.2GB……嗯,从那以后我再也不这么干了。

2.3 仓库(Registry)——镜像的“存储中心”

仓库就是存放镜像的地方。你可以把它想象成GitHub,只不过存的是镜像而不是代码。Docker Hub是最常用的公共仓库,但企业里一般会用私有仓库,比如Harbor或Nexus。

为什么需要仓库?因为镜像需要分发。你在一台机器上构建好镜像,其他机器怎么拿到?总不能每次都重新构建吧。仓库就是干这个的——你push上去,别人pull下来。

避坑指南:我曾经遇到过团队里有人把镜像直接传到FTP服务器上,结果版本管理一塌糊涂。后来我们统一用Harbor做私有仓库,配合标签策略(比如v1.0.0latestdev),再也没出过问题。记住:仓库不只是存东西的地方,更是版本管理的基石。

2.4 Docker与虚拟机的区别

这个问题面试经常问,但很多人答不到点子上。我直接给你画个对比表:

对比维度 Docker容器 虚拟机
启动速度 秒级(毫秒级启动) 分钟级(需要引导操作系统)
资源占用 轻量(共享宿主机内核) 重量(每个VM有完整OS)
隔离级别 进程级(命名空间+控制组) 硬件级(Hypervisor虚拟化)
镜像大小 通常几十MB到几百MB 通常几GB到几十GB
可移植性 强(依赖宿主机内核版本) 强(完全独立)
适用场景 微服务、CI/CD、开发测试 需要完整OS、遗留系统、安全隔离

说白了,容器和虚拟机最大的区别在于:容器共享宿主机内核,虚拟机有独立内核。这意味着容器不能运行与宿主机不同内核版本的应用——比如你在Linux上跑Windows容器?不行。但虚拟机可以,因为每个VM都有自己的内核。

我刚开始做嵌入式DevOps时,也纠结过到底用容器还是虚拟机。后来发现一个简单的判断标准:如果你的应用需要完整的操作系统支持(比如需要特定内核模块、需要硬件直通),那就用虚拟机;如果只是跑应用本身,容器更合适

实战建议:在嵌入式开发中,我通常这样搭配使用:

  • 开发环境:用Docker容器,保证团队环境一致
  • 测试环境:用虚拟机模拟不同硬件平台(比如ARM、x86)
  • 生产环境:用容器部署微服务,用虚拟机跑边缘节点

2.5 一个简单的Docker命令示例

光说不练假把式。咱们来跑个最简单的例子:

# 拉取一个镜像
docker pull alpine:latest

# 查看本地镜像
docker images

# 启动一个容器并进入交互模式
docker run -it alpine:latest /bin/sh

# 在容器里执行命令
# 输入: echo "Hello, Docker!"
# 输出: Hello, Docker!

# 退出容器
exit

# 查看所有容器(包括已停止的)
docker ps -a

你看,就这么几行命令,一个完整的运行环境就起来了。Alpine镜像只有5MB左右,启动时间不到1秒。换成虚拟机?光装个最小化的Linux就要几百MB,启动还得等半分钟。

我的习惯:开发时我常用docker run --rm参数,这样容器退出后自动删除,不会留下一堆僵尸容器。生产环境则用docker-compose管理多容器应用,配合健康检查和重启策略,基本不用手动干预。

2.6 小结

今天咱们把Docker的三个核心概念捋了一遍:

  • 镜像——只读模板,分层构建,不可变
  • 容器——镜像的运行实例,有可写层,轻量快速
  • 仓库——镜像的存储和分发中心,版本管理的关键

至于和虚拟机的区别,记住一句话:容器是进程级隔离,虚拟机是硬件级隔离。选哪个,看你的应用需要什么级别的隔离和资源控制。

下一章咱们聊聊Dockerfile怎么写,以及如何构建一个高效的嵌入式开发镜像。到时候我会分享一些我在ARM交叉编译环境里踩过的坑——嗯,那又是另一个故事了。


公众号:蓝海资料掘金营,微信deep3321