Docker 入门:容器为什么比虚拟机轻这么多
新手第一次接触 Docker,最常见的困惑是:它和虚拟机到底有什么区别?表面上两者都在"隔离出一台小机器",可实际用起来,虚拟机启动要几分钟、吃掉几个 G 内存,Docker 容器却秒级启动、几十 MB 就能跑。这份差距不是魔法,而是两种完全不同的隔离思路。
一、虚拟机:每个房间配一套全套家电
虚拟机的思路很直白:在物理机上用 Hypervisor 模拟出完整的硬件(CPU、内存、磁盘、网卡),然后在每一台"虚拟硬件"上都安装一个完整的操作系统,包括内核、驱动、系统库。想跑 10 个应用?那就装 10 个完整的操作系统。
代价很明显:每个虚拟机都要背一个内核的重量。Windows Server 虚拟机动辄几 GB 磁盘、1–2 GB 内存起步,启动时内核要经历完整的引导流程,动不动两三分钟。开发机上跑四五个虚拟机,风扇就开始起飞。
二、容器:合租公寓,共用厨房
Docker 的思路恰好反过来:不模拟硬件,直接共享宿主机的操作系统内核,只隔离应用运行需要的部分。Linux 内核早就提供了隔离机制:
- Namespaces(命名空间):让每个容器有独立的进程树(PID)、网络栈(NET)、挂载点(MNT)、用户 ID(USER)。容器里的进程以为自己是 1 号进程,看不到宿主机的进程,但实际上大家跑在同一个内核上。
- Cgroups(控制组):限制每个容器能用的 CPU、内存、磁盘 IO 配额,防止一个容器把整台机器吃光。
因为没有"第二个内核"要启动,容器启动本质上只是 fork 出几个进程——所以是秒级;镜像也不打包内核和驱动,只有应用代码加它依赖的库——所以小得多。这就是"轻"的全部秘密。
三、用 Docker 跑你的第一个容器
装好 Docker 后,三步验证:
# 1. 拉一个最小的 Linux 发行版镜像(约 5MB)
docker pull alpine:3.20
# 2. 启动容器并在里面执行命令
docker run --rm alpine:3.20 echo "Hello from container"
# 3. 进入一个可交互的容器看看
docker run -it --rm alpine:3.20 sh
在容器里执行 ps,你会发现 1 号进程就是你自己的 shell——命名空间生效了。退出容器再执行 docker ps -a,--rm 参数让容器退出后自动删除,不留垃圾。
几个每天会用到的命令:
docker ps:看正在跑的容器;加-a看所有(含已退出的)docker images:看本地镜像docker logs <容器名>:看容器输出的日志docker exec -it <容器名> sh:进入正在运行的容器排查问题
四、写一个 Dockerfile:把应用变成可复制的交付物
容器真正的价值在可复制。把一个 Python Web 服务打包成镜像,别人一条命令就能在完全一致的环境里跑起来:
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["python", "app.py"]
每一行都是一个可缓存的镜像层:FROM 打底,RUN 装依赖,COPY 拷代码,CMD 定启动命令。依赖没变时重新构建,Docker 会直接复用缓存层,构建快到离谱。构建加运行就两句:
docker build -t myapp:1.0 .
docker run -d -p 8000:8000 myapp:1.0
-d 后台运行,-p 8000:8000 把容器端口映射到宿主机。打开浏览器访问本机 8000 端口,服务就起来了——和你本地装 Python、配环境跑出来的效果一模一样,但换一台机器照样行。
五、新手最容易踩的三个坑
- 容器退出就丢数据:容器默认是无状态的,
docker rm之后里面的文件全没了。数据库这类有状态服务必须挂 volume:-v mydata:/var/lib/postgresql/data。 - latest 标签的坑:
FROM python:latest今天和下个月可能指向不同版本,生产环境永远写死具体版本号,比如python:3.12-slim。 - root 用户运行:默认容器内是 root,长远看有安全风险。Dockerfile 末尾加
USER appuser是个好习惯(先RUN useradd -m appuser)。
小结
虚拟机隔离的是硬件,容器隔离的是进程的视野。共享内核让容器获得了接近裸机的性能和秒级启动,而命名空间加控制组保证了隔离性。理解了这一层,Docker 的镜像、容器、volume、网络这些概念就都顺理成章了。下一篇文章,我们聊聊 docker-compose 怎么把"一个应用加一个数据库"一键编排起来。
- 点赞
- 收藏
- 关注作者
评论(0)