技术博客

Docker 核心概念详解:容器 vs 虚拟机,镜像、容器、仓库与守护进程

从零开始理解 Docker:深入讲解容器与虚拟机的本质区别(隔离层次、性能开销、启动时间对比),以及 Docker 四大核心概念——镜像(Image)、容器(Container)、仓库(Registry)、守护进程(Daemon)的关系与工作原理,帮助运维工程师建立正确的容器认知模型。

Docker容器虚拟机镜像容器化云原生入门

Docker 是当前最主流的容器技术,但很多初学者在“会用”之前缺少一个清晰的概念模型。本文不写命令,专门讲Docker 是什么、为什么、怎么运作,帮你在动手之前建立正确的认知。

容器 vs 虚拟机:本质区别

这是理解 Docker 的第一道门槛。两者都能隔离应用,但隔离的层次完全不同。

虚拟机(VM)架构:
┌────────────┐  ┌────────────┐  ┌────────────┐
│   App A    │  │   App B    │  │   App C    │
├────────────┤  ├────────────┤  ├────────────┤
│ Guest OS   │  │ Guest OS   │  │ Guest OS   │
│ (Linux)    │  │ (Windows)  │  │ (Linux)    │
├────────────┴──┴────────────┴──┴────────────┤
│              Hypervisor(虚拟化层)          │
├────────────────────────────────────────────┤
│              Host OS(宿主机操作系统)        │
├────────────────────────────────────────────┤
│              物理硬件                        │
└────────────────────────────────────────────┘

容器(Docker)架构:
┌────────────┐  ┌────────────┐  ┌────────────┐
│   App A    │  │   App B    │  │   App C    │
│ + 依赖库   │  │ + 依赖库   │  │ + 依赖库   │
├────────────┴──┴────────────┴──┴────────────┤
│              Docker Engine(容器引擎)        │
├────────────────────────────────────────────┤
│              Host OS(宿主机操作系统)        │
├────────────────────────────────────────────┤
│              物理硬件                        │
└────────────────────────────────────────────┘

关键区别:

维度 虚拟机 Docker 容器
隔离层次 硬件级(每个VM有自己的内核) 进程级(共享宿主机内核)
启动时间 分钟级 秒级甚至毫秒级
磁盘占用 GB 级(包含完整 OS) MB 级(只含应用和依赖)
内存开销 每个 VM 需要独立内存 共享内核,开销极低
安全隔离 强(内核完全隔离) 较弱(共享内核,依赖 namespace/cgroup)
适用场景 运行不同操作系统、强安全要求 同一 OS 下隔离应用、快速部署

Docker 的隔离原理

容器不是魔法,它依赖 Linux 内核的两个核心机制:

Linux Namespace(命名空间隔离)

Namespace 让每个容器“以为”自己有独立的系统资源:

Namespace 类型    隔离的内容
─────────────────────────────────────────
PID namespace    进程 ID(容器内的 PID 1 是容器的初始进程)
NET namespace    网络接口、IP、路由表、防火墙规则
MNT namespace    文件系统挂载点(容器看到自己的文件系统)
UTS namespace    主机名和域名
IPC namespace    进程间通信(信号量、消息队列)
USER namespace   用户 ID(容器内的 root ≠ 宿主机的 root)

Linux Cgroups(资源限制)

Namespace 解决“看到什么”,Cgroups 解决“能用多少”:

Cgroup 控制的资源:
  cpu        → 限制 CPU 使用时间(如最多使用 0.5 核)
  memory     → 限制内存用量(如最多 512MB,超出被 OOM Kill)
  blkio      → 限制磁盘 I/O 带宽
  net_cls    → 标记网络包,配合 tc 限速
  pids       → 限制容器内的进程数
# 实际效果演示(了解即可,不需要手动操作)
# 启动一个限制 CPU 和内存的容器:
docker run --cpus=0.5 --memory=256m nginx

# Docker 会在宿主机上创建对应的 cgroup:
# /sys/fs/cgroup/memory/docker/<container_id>/memory.limit_in_bytes
# → 值为 268435456(256 × 1024 × 1024 bytes)

Docker 四大核心概念

1. 镜像(Image)

镜像是只读的文件系统快照,包含运行应用所需的一切:代码、运行时、依赖库、配置文件。

镜像的分层结构:
┌──────────────────────────────┐  ← 层4:COPY 应用代码(可写层,构建时)
├──────────────────────────────┤  ← 层3:RUN pip install requirements
├──────────────────────────────┤  ← 层2:RUN apt-get install python3
├──────────────────────────────┤  ← 层1:ubuntu:22.04 基础镜像
└──────────────────────────────┘

每一层都是只读的,层与层之间用内容寻址(SHA256)标识
多个镜像可以共享相同的底层(节省磁盘空间)

类比: 镜像类似于虚拟机的“快照”或光盘镜像,但更轻量,且是分层可复用的。

# 镜像命名规则:
[registry/][namespace/]name[:tag]

docker.io/library/nginx:1.25       # Docker Hub 官方镜像
registry.cn-hangzhou.aliyuncs.com/library/nginx:1.25  # 阿里云镜像
harbor.company.com/backend/api:v1.2.3   # 私有仓库

2. 容器(Container)

容器是镜像的运行实例。Docker 在镜像顶部添加一个可写层,所有运行时的文件修改都写入这一层。

容器运行时结构:
┌──────────────────────────────┐  ← 可写层(Container Layer)
│   运行时写入的文件/日志       │    容器停止后这层默认消失
├──────────────────────────────┤
│   镜像层(只读)              │    多个容器共享同一镜像层
│   Image Layer 1-N            │    节省大量磁盘空间
└──────────────────────────────┘

类比:
  镜像 = 程序安装包(.exe 或 .dmg)
  容器 = 运行中的程序实例(可以同时运行多个)

同一个镜像可以启动多个容器,互不干扰:

# 3 个 nginx 容器,共享同一个镜像层
docker run -d -p 8081:80 --name web1 nginx
docker run -d -p 8082:80 --name web2 nginx
docker run -d -p 8083:80 --name web3 nginx

# 3 个容器运行中,但磁盘上镜像只存一份
docker images nginx  # 只有 1 行
docker ps            # 3 行

3. 仓库(Registry)

仓库是镜像的存储和分发中心,类似于 Git 的 GitHub。

常见仓库:

公共仓库:
  Docker Hub       → hub.docker.com(默认)
  Quay.io          → quay.io(Red Hat 维护)
  
国内加速镜像:
  阿里云 ACR       → registry.cn-hangzhou.aliyuncs.com
  腾讯云 TCR       → ccr.ccs.tencentyun.com

私有仓库(自建):
  Harbor           → 企业最常用
  GitLab Registry  → 与 GitLab CI 集成
  JFrog Artifactory

仓库结构:
  Registry(仓库服务器)
  └── Repository(镜像仓库,如 nginx)
      ├── Tag: 1.25
      ├── Tag: 1.24
      └── Tag: latest

4. Docker 守护进程(Daemon)

Docker Daemon(dockerd)是运行在宿主机上的后台服务,负责管理所有容器、镜像、网络和存储。

Docker 架构(C/S 模型):

用户(你)
    ↓ docker 命令(CLI)
    ↓ 通过 /var/run/docker.sock(Unix Socket)
Docker Daemon(dockerd)
    ├── 镜像管理(pull/build/push)
    ├── 容器管理(create/start/stop/rm)
    ├── 网络管理(bridge/overlay)
    └── 存储管理(volume/bind mount)

containerd(实际的容器运行时)

runc(底层容器创建工具)

Linux Namespace + Cgroups
# 查看 Docker Daemon 状态
systemctl status docker

# Docker 架构组件
docker version
# Client: Docker Engine 版本
# Server: dockerd 版本(运行在后台)

# 查看 daemon 的 socket 文件
ls -la /var/run/docker.sock
# srw-rw---- 1 root docker  → socket 文件,docker 组的用户可以访问

核心概念关系图

用户操作流程:

  docker pull nginx           # 从 Registry 拉取 Image
  docker build -t myapp .     # 用 Dockerfile 构建 Image

       Image(镜像)
  ┌─────────────────────┐
  │  layer4: 应用代码   │
  │  layer3: 依赖       │
  │  layer2: 运行时     │
  │  layer1: 基础 OS    │
  └─────────────────────┘
           ↓ docker run
    Container(容器)     Container(容器)
  ┌───────────────────┐  ┌───────────────────┐
  │  可写层(运行时)  │  │  可写层(运行时)  │
  ├───────────────────┤  ├───────────────────┤
  │   共享镜像层      │  │   共享镜像层      │
  └───────────────────┘  └───────────────────┘

  docker push myapp           # 把 Image 推送到 Registry

为什么要用 Docker

不是“Docker 是什么”,而是“Docker 解决了什么痛点”:

痛点1:"在我机器上能跑"
  问题:开发环境和生产环境依赖版本不一致
  解决:镜像将应用和依赖打包在一起,环境一致

痛点2:部署流程复杂
  问题:每次部署需要手动安装依赖、配置环境
  解决:docker run 一条命令完成部署

痛点3:多应用隔离
  问题:同一台机器上多个应用依赖冲突(Python2 vs Python3)
  解决:每个容器有独立的依赖环境

痛点4:资源利用率低
  问题:VM 独占资源,空闲时浪费
  解决:容器共享内核,资源按需使用

痛点5:扩缩容慢
  问题:VM 启动需要几分钟
  解决:容器秒级启动,快速水平扩展

小结

Docker 的核心认知模型:

镜像是模板,容器是实例。 镜像是静态的只读文件,容器是镜像的运行态,有自己的进程、网络和文件系统(可写层)。

容器不是虚拟机,但也不是裸进程。 它是通过 Linux Namespace 和 Cgroups 实现的“轻量级隔离进程”,与宿主机共享内核。

Docker Daemon 是管控中枢。 所有 docker 命令都是发给 Daemon 的请求,Daemon 再调用 containerd/runc 完成实际操作。

建立了这个认知模型后,后续所有 Docker 操作都会变得自然而然。下一篇我们将动手安装 Docker,并运行第一个容器。