跳到主要内容

Docker 教程

欢迎学习 Docker!本教程将带你从零基础开始,逐步掌握 Docker 容器技术的核心知识和技能。

容器技术发展历史

理解容器技术的历史有助于更好地把握 Docker 的设计理念和演进方向。

早期隔离技术

容器化思想可以追溯到 1979 年 Unix V7 系统引入的 chroot 系统调用。chroot 能够改变进程看到的根目录,实现基本的文件系统隔离。这被称为"改变根目录"(change root),是最早的隔离机制之一,至今仍被用于创建隔离的测试环境。

Linux 容器雏形

2000 年,FreeBSD 推出了 jail 机制,将系统分割成多个独立的环境。2005 年,Sun 公司在 Solaris 10 中引入了 Solaris Zones(也称 Solaris Containers),提供更完整的隔离能力,包括文件系统、网络、进程等。

真正奠定现代容器基础的是 Linux 内核的技术进步:

  • Namespaces(2002 年):内核 2.4.19 引入,提供进程、网络、文件系统等资源的隔离
  • Cgroups(2007 年):Google 贡献,提供资源限制和审计能力
  • LXC(2008 年):LinuX Containers 项目,首次将 namespaces 和 cgroups 整合为易用的容器工具

Docker 的诞生

2013 年 3 月,DotCloud 公司(后更名为 Docker Inc.)在 PyCon 大会上首次发布 Docker。创始人 Solomon Hykes 的目标是解决软件交付的"最后一公里"问题——代码在开发环境能运行,到了生产环境却出问题。

Docker 的创新在于:

  1. 镜像概念:将应用及其依赖打包为不可变的镜像
  2. 分层存储:镜像由多个只读层组成,实现高效的存储和传输
  3. 简洁的 CLI:大幅降低容器技术的使用门槛
  4. Docker Hub:提供公共镜像仓库,促进生态发展

容器生态的演进

Docker 的成功推动了整个容器生态的发展:

  • 2014 年:Kubernetes 项目启动,解决容器编排问题
  • 2015 年:OCI(Open Container Initiative)成立,制定容器镜像和运行时标准
  • 2016 年:Docker 将核心运行时捐赠给 CNCF,成为 containerd 项目
  • 2017 年:Kubernetes 成为容器编排的事实标准

为什么 Docker 能够成功?

回顾历史,Docker 的成功并非偶然:

因素说明
时机云计算兴起,DevOps 理念普及
简洁性相比 LXC,Docker 的用户体验大幅提升
标准化镜像格式成为行业标准(OCI 镜像规范)
生态Docker Hub 聚合了大量官方和社区镜像
可移植性"一次构建,到处运行" 解决了长期痛点

理解这段历史,能帮助你更好地理解为什么 Docker 采用分层镜像设计、为什么强调不可变基础设施,以及容器编排工具存在的意义。

什么是 Docker?

Docker 是一个开源的应用容器引擎,基于 Go 语言开发,遵从 Apache2.0 协议开源。它可以让开发者将应用程序及其依赖打包到一个可移植的容器中,然后发布到任何流行的 Linux、Windows 或 macOS 机器上,也可以实现虚拟化。

Docker 的核心概念

容器(Container):容器是一个轻量级、独立的可执行软件包,包含运行应用程序所需的所有内容:代码、运行时、系统工具、系统库和设置。容器之间相互隔离,确保应用程序在不同环境中以相同方式运行。

镜像(Image):镜像是容器的蓝图,是一个只读模板,包含创建容器所需的指令。镜像由多个层组成,每层代表 Dockerfile 中的一条指令。

仓库(Registry):仓库是存储和分发镜像的地方。Docker Hub 是最大的公共仓库,包含超过 100,000 个镜像。你也可以搭建私有仓库来存储自己的镜像。

Docker 与虚拟机的区别

特性Docker 容器虚拟机
启动速度秒级分钟级
资源占用MB 级别GB 级别
性能接近原生有损耗
隔离性进程级别操作系统级别
操作系统共享宿主机内核独立内核

架构对比:

解释

  • 虚拟机需要为每个应用运行完整的操作系统,资源开销大
  • Docker 容器共享宿主机内核,只打包应用和依赖,更加轻量

容器底层原理

理解 Docker 的底层原理,有助于更好地排查问题和优化应用。容器本质上是利用 Linux 内核的隔离特性来限制进程的资源访问。

Namespaces:资源隔离

Namespaces 是 Linux 内核提供的一种资源隔离机制,可以让一组进程看到独立的系统资源。Docker 使用多种 namespace 来实现容器的隔离:

Namespace 类型隔离内容实际效果
PID进程 ID容器内进程从 PID 1 开始编号
NET网络栈容器拥有独立的网卡、路由表、防火墙规则
MNT挂载点容器有独立的文件系统视图
IPC进程间通信容器间信号量、消息队列互不影响
UTS主机名容器可以有自己的主机名
USER用户和组容器内的 root 可以映射到主机的普通用户

PID Namespace 示例

当你在容器内执行 ps aux 时,只能看到容器内的进程。这是因为容器进程属于一个独立的 PID namespace。在容器内,init 进程(PID 1)是容器的入口进程,而不是系统的 systemd。

# 在容器内查看进程
docker run -it alpine ps aux
# 只显示容器内的进程,PID 从 1 开始

# 在主机上查看同一进程
ps aux | grep <容器名>
# 显示主机视角的 PID(如 12345)

Cgroups:资源限制

Cgroups(Control Groups)用于限制、记录和隔离进程组使用的物理资源。没有 cgroups,一个容器可能耗尽整个主机的内存或 CPU。

主要功能

  • 资源限制:设置进程组使用资源的上限
  • 优先级分配:控制进程组分配资源的权重
  • 资源统计:统计进程组的资源使用量
  • 进程控制:可以冻结进程组或重启进程组

资源限制示例

# 限制容器使用 512MB 内存
docker run -d --memory="512m" nginx

# 限制容器使用 1.5 个 CPU 核心
docker run -d --cpus="1.5" nginx

这些限制通过 cgroups 实现。在主机上可以查看对应的 cgroup 配置:

# 查看内存限制(cgroup v2)
cat /sys/fs/cgroup/docker/<容器ID>/memory.max

# 查看 CPU 限制
cat /sys/fs/cgroup/docker/<容器ID>/cpu.max

Union File System:分层镜像

UnionFS(联合文件系统)是 Docker 镜像分层存储的基础。它允许多个文件系统"叠加"在一起,呈现为一个统一的文件系统。

分层原理

Docker 镜像由多个只读层组成,每层对应 Dockerfile 中的一条指令。运行容器时,Docker 在最上层添加一个可写层(容器层)。

┌─────────────────────────┐
│ 容器层(可写) │ ← 运行时修改写到这里
├─────────────────────────┤
│ 镜像层 N(只读) │ ← RUN npm install
├─────────────────────────┤
│ 镜像层 N-1(只读) │ ← COPY package.json
├─────────────────────────┤
│ 镜像层 2(只读) │ ← RUN apk add
├─────────────────────────┤
│ 镜像层 1(只读) │ ← FROM alpine
└─────────────────────────┘

Copy-on-Write(写时复制)

当容器需要修改文件时:

  1. 从只读层复制文件到容器层
  2. 在容器层进行修改
  3. 原始镜像层保持不变

这种设计带来几个好处:

  • 镜像共享:多个容器可以共享相同的只读层
  • 快速启动:新容器只需创建一个可写层
  • 存储效率:只存储差异部分

容器网络原理

Docker 创建容器时,会自动创建一对虚拟网络接口(veth pair):一端在容器内(eth0),一端在主机的网桥上(docker0)。

容器通过 NAT(网络地址转换)访问外部网络,外部网络通过端口映射访问容器。

容器 vs 进程

从内核视角看,容器就是一组被"特殊对待"的进程:

  • 它们有独立的 namespace(看起来像独立系统)
  • 它们被 cgroup 限制资源(不会失控)
  • 它们共享宿主机内核(不是完整的虚拟机)

这也是为什么容器启动快、资源占用少——本质上就是在运行普通进程,只是加了隔离和限制。

为什么学习 Docker?

  1. 一致性环境:开发、测试、生产环境完全一致,消除"在我机器上能运行"的问题
  2. 快速部署:容器启动只需几秒,大大加快部署速度
  3. 资源高效:相比虚拟机,容器占用资源更少,可以在同一硬件上运行更多服务
  4. 微服务架构:容器是微服务架构的理想载体,每个服务独立部署和扩展
  5. DevOps 实践:Docker 是 CI/CD 流程的核心组件,实现自动化构建和部署
  6. 云原生基础:Kubernetes 等容器编排工具都基于 Docker 容器

Docker 的应用场景

应用部署

  • 标准化应用交付流程
  • 一键部署复杂应用栈
  • 版本回滚和灰度发布

开发环境

  • 统一团队开发环境
  • 快速搭建本地开发栈
  • 隔离不同项目的依赖

持续集成/持续部署

  • 构建可重复的 CI 环境
  • 自动化测试环境
  • 流水线标准化

微服务架构

  • 服务独立部署和扩展
  • 服务隔离和资源限制
  • 服务网格基础

云原生应用

  • Kubernetes 基础设施
  • 云平台部署标准
  • 混合云和多云部署

Docker 核心组件

Docker Engine(Docker 引擎)

Docker 引擎是一个客户端-服务器应用程序,包含以下组件:

  • Docker Daemon(dockerd):守护进程,负责构建、运行和分发容器
  • REST API:用于程序与守护进程通信的接口
  • Docker CLI(docker):命令行界面,用于管理容器和镜像
┌─────────────────────────────────────────┐
│ Docker Engine │
├─────────────────────────────────────────┤
│ Docker CLI │
│ (docker 命令) │
├─────────────────────────────────────────┤
│ REST API │
├─────────────────────────────────────────┤
│ Docker Daemon │
│ (dockerd) │
├─────────────────────────────────────────┤
│ containerd │
│ runc │
└─────────────────────────────────────────┘

底层运行时

Docker 引擎的底层由两个关键组件组成:

  • containerd:一个工业级容器运行时,负责管理容器的完整生命周期(镜像传输、容器执行、监控等)。它是 CNCF 毕业项目,被 Kubernetes 等平台广泛使用。
  • runc:轻量级容器运行时,负责实际创建和运行容器。它实现了 OCI(开放容器倡议)运行时规范,是容器技术的基础。

Docker Desktop

Docker Desktop 是 Docker 官方提供的桌面应用程序,包含:

  • Docker Engine
  • Docker CLI
  • Docker Compose
  • Kubernetes(可选)
  • 图形化管理界面

Docker 生态系统

Docker Hub

Docker Hub 是 Docker 官方提供的公共镜像仓库:

  • 官方镜像(如 nginx、redis、mysql)经过安全审查
  • 自动构建功能,代码提交后自动构建镜像
  • 镜像扫描检测安全漏洞
  • 支持私有仓库(免费账户 1 个)

Docker Compose

Docker Compose 是用于定义和运行多容器应用的工具:

  • 使用 YAML 文件定义服务
  • 一键启动多个容器
  • 管理容器之间的依赖关系

容器编排

在生产环境中,通常需要容器编排工具来管理大规模容器部署:

  • Kubernetes:业界标准的容器编排平台,功能强大,生态丰富
  • Docker Swarm:Docker 原生的集群管理工具,简单易用

开放容器倡议(OCI)

OCI 制定了容器镜像格式和运行时规范,确保不同容器工具之间的互操作性。Docker 镜像格式已成为 OCI 镜像规范的基础。

Docker 版本说明

Docker Edition

Docker 提供两个主要版本:

版本说明适用场景
Docker Community Edition (CE)社区版,免费使用开发者、小型团队、学习
Docker Enterprise Edition (EE)企业版,付费订阅大型企业、需要技术支持

Docker CE 是大多数开发者的选择,功能完整且免费。Docker EE 在 CE 基础上增加了企业级功能,如镜像安全扫描、容器编排管理、统一管理平台等。

版本号命名规则

从 2017 年开始,Docker 采用基于时间的版本命名方案:

Docker 27.x.y
│ │
│ └── 补丁版本(bug修复)
└── 主版本(年度更新)

版本发布节奏

  • Stable 版本:每季度发布一个稳定版本,适合生产环境
  • Edge 版本:每月发布,包含最新功能,适合测试环境

长期支持(LTS)

Docker Engine 遵循长期支持策略:

  • 每个稳定版本支持约 1 年
  • 安全更新和 bug 修复在支持期内持续提供
  • 建议生产环境使用 Stable 版本

查看当前版本

docker version
# 输出包含客户端和服务端的版本信息

docker info | grep "Server Version"
# 只查看服务端版本

版本兼容性

  • Docker 客户端和服务端版本不需要完全一致
  • 客户端版本可以比服务端新
  • 建议客户端和服务端版本差距不超过一个主版本

教程目录

基础入门

进阶内容

高级主题

知识速查

学习建议

  1. 动手实践:每学一个概念,都要动手操作验证
  2. 理解原理:不只是记住命令,要理解底层原理
  3. 循序渐进:从基础命令开始,逐步掌握高级功能
  4. 阅读官方文档:Docker 官方文档是最权威的参考
  5. 项目练习:将实际项目容器化是最好的学习方式

参考资源

准备好开始学习了吗?点击下一章开始你的 Docker 学习之旅!