0、前言

什么是docker:

        将应用程序自动部署到容器(container)的技术;Docker 是一个容器化工具,用来把应用 + 依赖环境打包成一个独立、可移植、能一键运行的 “盒子”。

什么是容器:

        一种虚拟化的方案,与虚拟机不同,虚拟机是通过中间层将一台或多台虚拟系统独立运行在硬件之上,而容器是运行在操作系统的内核之上的,可以称为操作系统虚拟化。只能运行相同或相似的内核操作系统;依赖于linux内核特性:Namespace和Cgroups,所以docker上只能运行linux操作系统

1、优点

1. 环境一致,从根本解决 “我本地能跑”

  • 开发、测试、生产完全一样
  • 一次构建,到处运行,告别依赖冲突、版本不一致

2. 比虚拟机轻得多、快得多

  • 共享宿主机内核,不需要装完整操作系统
  • 启动:秒级 / 毫秒级
  • 资源占用:远小于虚拟机
  • 一台机器能跑几十上百个容器

3. 隔离性好,应用互不干扰

  • 利用 Linux Namespace 实现:进程、网络、文件系统全隔离
  • 一个容器挂了不影响其他容器
  • 不同版本软件、不同依赖可共存

4. 标准化打包,可移植极强

  • 代码 + 环境 + 配置 + 依赖打成一个镜像
  • 放到任何装了 Docker 的机器都能直接跑
  • 迁移、扩容、回滚极其方便

5. 高效的分层存储,省空间、省时间

  • 镜像分层复用,相同层只存一份
  • 构建、传输、更新都极快
  • 只传改动的层,不用全量传

6. 部署简单、自动化友好

  • 一条命令启动服务
  • 完美适配 CI/CD、DevOps、微服务
  • 可轻松接入 Jenkins、GitLab、K8s

7. 资源可控,稳定安全

  • 通过 Cgroups 限制 CPU、内存、磁盘、带宽
  • 防止某个应用把服务器拖垮
  • 权限、网络可精细控制

8. 生态超级成熟

  • 海量官方 / 第三方镜像:Nginx、MySQL、Redis、Mongo、Elasticsearch…
  • 一条命令拉取即用,不用自己装环境

2、Docker 存在争论的地方

1、能否实现彻底隔离

在超复杂的业务系统中,Docker 基于单一操作系统内核的隔离机制,能否做到真正彻底的隔离,一直存在较大争议。单个容器如果出现程序崩溃、内存溢出、CPU 占用过高、磁盘 I/O 被打满等问题,是否会影响其他容器甚至整个宿主机,很多人对 Docker 在生产环境、尤其是关键任务系统中的稳定性仍持怀疑态度。这就像有人质疑 Node.js 单线程模型 “快而不稳”,难以在复杂场景下稳定支撑一样。Docker 依靠 Namespace + Cgroups 实现隔离,能保证应用级、资源级隔离,正常场景下足够安全稳定,但容器共享宿主机内核,不具备虚拟机那样的硬件级强隔离,极端情况下若出现内核漏洞,可能发生容器逃逸,内核资源耗尽也会影响整个节点。不过目前 Linux 内核已持续针对容器做大量优化,隔离能力在不断增强。

2、Go 语言尚未完全成熟

Docker 由 Go 语言开发,但早期 Go 语言对大多数开发者比较陌生,且语言本身还在不断迭代改进,距离成熟还有一段时间,同时 Go 半 git、半包管理的方式,也让一部分开发者感到不适。这一说法属于早期观点,如今 Go 语言已经非常成熟稳定,是云原生领域的主流开发语言,Docker、K8s、etcd、Istio 等核心基础设施均使用 Go 开发,经过海量生产环境验证。真正的问题不是语言不成熟,而是学习门槛较高,很多运维、开发者不熟悉 Go,导致排查底层问题难度更大。

3、被私有公司控制,存在商业化风险

Docker 最初由名为 DotCloud(后改名为 Docker Inc.)的私有商业公司设计,公司以营利为目的,早期用户无法自由通过源代码编译 Docker,只能使用官方提供的二进制发行包,因此有人担心未来 Docker 可能无法完全免费使用,目前 Docker 公司已经推出面向企业的收费服务,包括咨询、技术支持与培训等。Docker Inc. 确实主导产品并走商业化路线,Docker Desktop 等工具已对企业收费,但容器生态已经完全开放,Docker 将核心运行时 containerd 捐赠给 CNCF,推动建立了 OCI 开放容器标准,现在容器镜像、运行时都是行业通用标准,不再被单一公司绑架,即使不用 Docker,也可以使用其他容器工具,生态不会被垄断。

4、有状态服务不适合容器化

Docker 天生面向无状态应用设计,容器删除后数据默认丢失,像 MySQL、Redis、Kafka、ES 这类有状态服务,放到容器中会面临数据持久化复杂、磁盘性能损耗、网络与 IP 不稳定、故障排查难度高等问题。无状态服务如 Web 服务、接口、微服务非常适合容器化,而高可靠、高 IO 的有状态服务,建议优先使用物理机、虚拟机或云托管服务,不建议盲目容器化。

5、性能损耗问题

Docker 并非零性能损耗,其联合文件系统 Overlay2 会影响写入性能,容器网络经过 NAT、网桥,比直接宿主机进程略慢,在高并发、高 IO、低延迟场景下会有明显感知。普通后端、接口、微服务等常规业务,性能损耗可以忽略,但数据库、大数据等高 IO 组件,在使用时需要谨慎评估。

3、Docker的目标

1.提供简单轻量的建模方式(同一台宿主机可以运行多个容器)

2.职责的逻辑分离

加强开发人员的开发环境与生产部署的环境的一致性

3.快速高效的开发的生命周期

缩短从开发到生产的周期,使开发,测试,生产环境相一致,并且都以容器的方式进行交付,避免了额外调试部署的时间开销

4.鼓励使用面向服务的架构

鼓励单个容器只运行单一服务,这就形成了一种分布式模型,避免服务之间的互相应影响,在定位出现的问题时,也变得简单直接

4、Docker的使用场景

1.使用docker容器开发,测试,部署服务.

2.创建隔离的运行环境.

3.搭建测试环境

4.构建多用户的平台即服务(PaaS)基础设施 Iaas Paas Saas daas

5.提供软件即服务(SaaS)应用程序

6.高性能,超大规模的宿主机部署

5、Docker容器技术的实现

1、namespace 命名空间(隔离资源)

作用:为容器创建独立的「运行环境」,让容器看起来像一个独立的操作系统,实现 PID、网络、挂载点等资源的隔离。简单比喻:把容器装进一个「隔音房」,里面的进程看不到外面的进程,外面也看不到里面的,彼此互不干扰。

Docker 中用到的主要 Namespace 类型

类型 作用 举例
PID Namespace 隔离进程 ID 容器内的 PID 1 是容器主进程,和宿主机 PID 1(init/systemd)完全隔离
Network Namespace 隔离网络栈 容器有独立的网卡、IP、端口、路由表,通过网桥与宿主机通信
Mount Namespace 隔离文件系统挂载点 容器的 / 根目录和宿主机的 / 根目录完全分离
UTS Namespace 隔离主机名和域名 容器可以设置自己的 hostname,和宿主机不同
User Namespace 隔离用户和组 ID 容器内的 root 用户(UID 0)映射到宿主机的普通用户,提升安全性
IPC Namespace 隔离进程间通信(如共享内存) 容器间无法通过 IPC 直接通信,需通过网络等方式

2、cgroup 资源控制(限制资源)

Docker 底层依托 Linux 的 cgroup(Control Groups) 实现对容器的资源限制(CPU、内存、磁盘 IO、网络等),核心是为容器划定资源使用的 “边界”,避免单个容器占用过多宿主机资源导致服务不稳定。

cgroup 是 Linux 内核提供的资源管理机制,能对一组进程(Docker 容器本质是一组进程)进行资源限制、优先级调整、资源使用统计。Docker 会为每个容器创建独立的 cgroup 层级,通过配置 cgroup 参数实现资源控制。

1. CPU 资源限制

CPU 限制主要分为 “核心数限制” 和 “CPU 使用率权重” 两类:

(1)限制 CPU 核心数

通过 --cpus 参数指定容器最多使用的 CPU 核心数(支持小数,如 0.5 表示半核)。

限制容器最多使用 2 个 CPU 核心

[root@Anolist ~]# docker run -d --name nginx-cpu --cpus=2 nginx

(2)限制 CPU 使用率权重(多容器竞争时生效)

通过 --cpu-shares 指定 CPU 权重(默认值 1024),仅当宿主机 CPU 资源不足时生效,权重越高,容器分配到的 CPU 时间片越多。

容器1:权重2048

[root@Anolist ~]# docker run -d --name app1 --cpu-shares=2048 busybox sh -c "while true; do :; done"

容器2:权重1024(默认)

[root@Anolist ~]# docker run -d --name app2 --cpu-shares=1024 busybox sh -c "while true; do :; done"

(3)绑定 CPU 核心(独占指定核心)

通过 --cpuset-cpus 指定容器只能使用某几个 CPU 核心(适合对性能敏感的场景)。

限制容器仅使用第 0、1 号 CPU 核心(核心编号从 0 开始)

[root@Anolist ~]# docker run -d --name app-cpuset --cpuset-cpus=0,1 nginx

2. 内存资源限制

内存限制是避免容器 “吃满” 宿主机内存的关键,核心参数是 --memory(简写 -m

限制容器最大使用 512MB 内存

[root@Anolist ~]# docker run -d --name nginx-mem -m 512m nginx

默认情况下,-m 仅限制物理内存,可通过 --memory-swap 指定 “物理内存 + 交换分区” 的总上限:

  • 格式:--memory-swap=物理内存+swap(如 -m 512m --memory-swap=1g 表示物理内存 512M,swap 512M);
  • 若设为 --memory-swap=-1,则 swap 无限制(不推荐)。

物理内存 512M,swap 512M,总上限 1G

[root@Anolist ~]# docker run -d --name app-swap -m 512m --memory-swap=1g nginx

3. 磁盘 IO 限制

通过 --blkio-weight(权重)或 --blkio-weight-device(指定设备的 IO 限制)控制容器磁盘读写速度,权重范围 10-1000(默认 500)。

限制容器对 /dev/sda 磁盘的 IO 权重为 800(高于默认)

[root@Anolist ~]# docker run -d --name app-io --blkio-weight-device="/dev/sda:800" nginx

4.docker-compose 中配置资源限制

若用 docker-compose.yml 管理容器,可在 deploy.resources 中配置资源限制(需注意:deploy 字段在 docker-compose v3+ 生效)

version: '3.8' services: nginx: image: nginx deploy: resources: limits: # 硬限制(容器绝对不能超过) cpus: '2' memory: 512M reservations: # 软限制(容器至少分配的资源) cpus: '0.5' memory: 256M

5.验证资源限制是否生效

查看指定容器的资源使用

[root@Anolist ~]# docker stats nginx-mem

查看所有容器的资源使用

[root@Anolist ~]# docker stats

3、overlay2fs 联合文件系统

Overlay2 是 Docker 默认的存储驱动(Docker 17.06+ 推荐),属于 Union File System(联合文件系统) 的一种,核心是将多个目录(层)“叠加” 成一个统一的文件视图,实现容器镜像的分层存储、高效复用和写时复制(Copy-on-Write)。

一、核心概念:Union FS 与 Overlay2 基础

  1. 联合文件系统(Union FS):本质是将多个独立的文件系统(目录)以 “只读 + 可写” 的方式叠加,对外呈现为一个完整的文件系统,底层目录的修改不会相互影响。
  2. Overlay2 的核心分层
    • Lowerdir(只读层):对应 Docker 镜像的各层(如基础镜像层、应用安装层),所有镜像层都是只读的,可被多个容器共享。
    • Upperdir(可写层):对应容器的独有层,容器运行时的所有修改(新建 / 删除 / 修改文件)都只发生在这一层,不影响底层镜像。
    • Merged(统一视图):对外展示的 “合并后” 的文件系统,用户 / 进程看到的是 Lowerdir + Upperdir 的组合结果。
    • Workdir(工作层):Overlay2 内部使用的临时目录,用于辅助实现文件修改,无需用户关注。

二、Overlay2 工作原理(通俗举例)

假设我们基于 nginx:alpine 镜像启动一个容器,Overlay2 的工作流程如下:

  1. 镜像层(Lowerdir)nginx:alpine 镜像由多个只读层组成(如 alpine 系统层、nginx 安装层),这些层被所有基于该镜像的容器共享。
  2. 容器启动:Docker 为容器创建 Upperdir(可写层)、Workdir(工作层),并将 Lowerdir + Upperdir 合并为 Merged 视图,容器进程操作的是 Merged 目录。
  3. 文件修改场景
    • 读取文件:如果文件在 Upperdir 存在,直接读取;否则读取 Lowerdir 中的只读文件。
    • 修改文件:先将 Lowerdir 中的只读文件复制到 Upperdir(写时复制,Copy-on-Write),再修改 Upperdir 中的副本,原镜像层文件不变。
    • 删除文件:不会删除 Lowerdir 中的文件(只读),而是在 Upperdir 中创建一个 “删除标记”(whiteout 文件),合并视图中该文件就会显示为已删除。
    • 新建文件:直接在 Upperdir 中创建,仅属于当前容器。
  4. 容器删除:仅删除 Upperdir 和 Workdir,底层镜像层(Lowerdir)保留,不影响其他容器。

三、Overlay2 关键特性(优势 + 适用场景)

1. 核心优势
  • 高效复用:镜像层只读且可共享,多个容器共用同一镜像时,仅需一份镜像层数据,大幅节省磁盘空间。例:10 个基于 nginx:alpine 的容器,仅占用 1 份镜像层空间 + 10 个极小的可写层空间。
  • 写时复制(CoW):容器修改文件时才复制副本,避免镜像层被污染,且初始启动速度极快(无需拷贝整个镜像)。
  • 性能优秀:相比旧版的 overlay/aufs 驱动,Overlay2 减少了文件查找的层数,读写性能更优,是 Docker 官方推荐的生产环境驱动。
2. 限制 / 注意事项
  • 仅支持 Linux 内核 4.0+:Overlay2 依赖较新的内核特性,CentOS 7.4+、Ubuntu 16.04+ 已默认支持。
  • 不支持嵌套叠加:Overlay2 本身不支持 “多层叠加的叠加”,但 Docker 已通过分层设计规避了这个问题。
  • 磁盘分区要求:Overlay2 要求镜像和容器的存储目录在同一个磁盘分区(默认 /var/lib/docker/overlay2),跨分区会失效。

四、实操:查看 Docker 存储驱动与 Overlay2 分层

  1. 查看当前 Docker 存储驱动

bash

docker info | grep "Storage Driver"
# 输出示例:Storage Driver: overlay2
  1. 查看容器的 Overlay2 分层详情

bash

# 1. 启动一个测试容器
docker run -d --name test-nginx nginx:alpine

# 2. 查看容器的存储信息(找到 Merged/Lowerdir/Upperdir 路径)
docker inspect test-nginx | grep -E "MergedDir|LowerDir|UpperDir"

输出示例(路径为宿主机 /var/lib/docker/overlay2/ 下的目录):

plaintext

"LowerDir": "/var/lib/docker/overlay2/xxx/diff:/var/lib/docker/overlay2/yyy/diff",  # 镜像只读层
"MergedDir": "/var/lib/docker/overlay2/zzz/merged",                              # 合并视图
"UpperDir": "/var/lib/docker/overlay2/zzz/diff",                                  # 容器可写层
"WorkDir": "/var/lib/docker/overlay2/zzz/work"                                    # 工作层

五、Overlay2 vs 其他存储驱动(简单对比)

存储驱动 核心特点 适用场景
overlay2 性能优、磁盘占用少、官方推荐 绝大多数生产环境(Linux 内核 4.0+)
devicemapper 基于块设备,支持瘦置备 老旧内核系统(CentOS 7.0-7.3)
aufs 早期 Docker 默认驱动,分层多性能差 仅兼容老旧 Ubuntu 系统
zfs 支持快照、数据压缩 对数据可靠性要求极高的场景(如存储集群)

6.Docker容器的三大组件

仓库、镜像、容器

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐