github编辑

2.2 容器

容器是 Docker 技术的核心,是应用实际运行的载体。本节将从容器的本质、与虚拟机的区别、存储层机制以及生命周期管理等方面,全面解析 Docker 容器。

2.2.1 一句话理解容器

容器是镜像的运行实例。如果把镜像比作程序,那么容器就是进程。 用面向对象编程的术语来说:镜像是类 (Class),容器是对象 (Instance)

  • 一个镜像可以创建多个容器

  • 每个容器相互独立,互不影响

  • 容器可以被创建、启动、停止、删除、暂停

2.2.2 容器的本质

💡 笔者认为,理解这一点是理解 Docker 的关键****容器的本质是一个特殊的进程。

spinner

这种隔离是通过 Linux 内核的 Namespace 技术实现的。

2.2.3 容器 vs 虚拟机:核心区别

很多初学者会混淆容器和虚拟机。笔者用一张图来说明:

spinner
特性
容器
虚拟机

隔离级别

进程级 (Namespace)

硬件级 (Hypervisor)

启动时间

秒级 (甚至毫秒)

分钟级

资源占用

MB 级别

GB 级别

性能损耗

几乎为零

5-20%

内核

共享宿主机内核

各自独立内核

2.2.4 容器的存储层

理解容器的存储层机制对于数据的持久化和镜像的优化至关重要。本节将介绍容器的可写层以及 Copy-on-Write 机制。

镜像层 + 容器层

当容器运行时,Docker 会在镜像的只读层之上创建一个 可写层 (容器存储层):

spinner

Copy-on-Write (写时复制)

当容器需要修改镜像层中的文件时:

  1. Docker 将该文件 复制 到容器存储层

  2. 在容器层中进行修改

  3. 原始镜像层保持不变

⚠️ 容器存储层的生命周期

笔者特别强调:这是新手最容易踩的坑!容器存储层与容器生命周期绑定。容器删除,数据就没了!

正确的数据持久化方式

按照 Docker 最佳实践,容器存储层应该保持 无状态。需要持久化的数据应该使用:

方式
说明
适用场景

Docker 管理的存储

数据库、应用数据

挂载宿主机目录

开发时共享代码

这些位置的读写 会跳过容器存储层,直接写入宿主机,性能更好,也不会随容器删除而丢失。

2.2.5 容器的生命周期

掌握容器的生命周期对于管理和调试 Docker 应用非常重要。如图 2-1 所示,容器会经历从创建到删除的完整状态流转。

spinner

图 2-1 容器生命周期状态流转图

概述

总体概述了以下内容。

常用生命周期命令

运行以下命令:

2.2.6 容器与进程的关系

核心概念:容器的生命周期 = 主进程 (PID 1) 的生命周期

这就是为什么:

详细解释请参考后台运行章节。

2.2.7 容器的隔离性

Docker 容器通过以下 Namespace 实现隔离:

Namespace
隔离内容
效果

PID

进程 ID

容器内 PID 1 是应用进程,看不到宿主机其他进程

NET

网络

独立的网络栈、IP 地址、端口

MNT

文件系统

独立的根目录和挂载点

UTS

主机名

独立的主机名和域名

IPC

进程间通信

独立的信号量、消息队列

USER

用户

独立的用户和组 ID

想深入了解?请阅读底层实现 - 命名空间

最后更新于