Docker 的底层原理基于 Linux 内核的核心技术,通过资源隔离、资源限制和分层文件系统实现轻量级虚拟化。
Docker 采用 客户端-服务器(C/S)架构,包含以下核心组件
1.Docker 客户端:用户通过命令行(CLI)或 API 发送指令(如 docker run)。
2.Docker 守护进程(Daemon):在宿主机后台运行,负责管理镜像、容器、网络等资源,并调用内核功能实现隔离。
3.Docker 镜像:只读模板,包含应用代码、依赖和环境配置,基于分层文件系统(UnionFS)构建。
4.Docker 容器:镜像的运行实例,包含独立的进程、网络和文件系统视图,通过写时复制(Copy-on-Write)实现数据隔离。
5.Docker 注册表:镜像存储中心(如 Docker Hub、私有仓库harbor),支持镜像的拉取和推送。
Docker 依赖 Linux 内核的三大机制实现容器化
命名空间为容器提供资源隔离,确保每个容器拥有独立的系统视图。
Namespace是 Linux 内核的一项功能,该功能对内核资源进行隔离,使得容器中的进程都可以在单独的命名空间中运行,并且只可以访问当前容器命名空间的资源。
Namespace 可以隔离进程 ID、主机名、用户 ID、文件名、网络访问和进程间通信等相关资源。
Namespace是Linux系统提供的一种资源隔离机制,可实现系统资源隔离的列表如下:
IPC :用于隔离进程间通信
Network :隔离网络栈,容器拥有独立 IP 和端口。
Mount :隔离文件系统挂载点,容器文件操作不影响宿主机。
PID :用于隔离进程ID,容器内进程仅可见自身进程
User :隔离用户和组 ID,提升安全性
UTS :隔离主机名(HostName)和域名(DomianName)
#01 创建一个名称为"liux-test"的网络名称空间
[root@docker01 harbor]# ip netns add liux-test
[root@docker01 harbor]# ll /var/run/netns/liux-test
-r--r--r-- 1 root root 0 May 19 16:26 /var/run/netns/liux-test
[root@docker01 harbor]# ip netns exec liux-test ip a
1: lo: mtu 65536 qdisc noop state DOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
#02 启动"liux-test"的网络名称空间的网卡
#未启动时显示网络不可用
[root@docker01 harbor]# ip netns exec liux-test ping 127.0.0.1
connect: Network is unreachable
#启动
[root@docker01 harbor]# ip netns exec liux-test ifconfig lo up
#启动之后发现可以ping通自己
[root@docker01 harbor]# ip netns exec liux-test ping 127.0.0.1
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.046 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.042 ms
#03 宿主机创建网络设备对
[root@docker01 harbor]# ip link add veth100 type veth peer name veth200
[root@docker01 harbor]# ip a
37: veth200@veth100: mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether e6:84:3c:bb:3a:55 brd ff:ff:ff:ff:ff:ff
38: veth100@veth200: mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 42:59:ac:18:0b:fb brd ff:ff:ff:ff:ff:ff
#04 将"veth200"设备关联到咱们自定义的"liux-test"网络名称空间
[root@docker01 harbor]# ip link set veth200 netns liux-test
# 你会发现宿主机的veth200不见啦!
[root@docker01 harbor]# ip a
#05 将"veth200"设备配置IP地址
[root@docker01 harbor]# ip netns exec liux-test ip a
...
37: veth200@if38: mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether e6:84:3c:bb:3a:55 brd ff:ff:ff:ff:ff:ff link-netnsid 0
[root@docker01 harbor]# ip netns exec liux-test ifconfig veth200 172.31.100.200/24 up
[root@docker01 harbor]# ip netns exec liux-test ip a
...
37: veth200@if38: mtu 1500 qdisc noqueue state LOWERLAYERDOWN group default qlen 1000
link/ether e6:84:3c:bb:3a:55 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.31.100.200/24 brd 172.31.100.255 scope global veth200
valid_lft forever preferred_lft forever
#对比发现已经有ip地址啦
#06 宿主机veth100也配置IP地址
[root@docker01 harbor]# ifconfig veth100 172.31.100.100/24 up
[root@docker01 harbor]# ifconfig veth100
veth100: flags=4163 mtu 1500
inet 172.31.100.100 netmask 255.255.255.0 broadcast 172.31.100.255
inet6 fe80::4059:acff:fe18:bfb prefixlen 64 scopeid 0x20
ether 42:59:ac:18:0b:fb txqueuelen 1000 (Ethernet)
RX packets 8 bytes 648 (648.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 8 bytes 648 (648.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
#此时发现veth100可以ping通veth200啦
[root@docker01 harbor]# ping 172.31.100.200
PING 172.31.100.200 (172.31.100.200) 56(84) bytes of data.
64 bytes from 172.31.100.200: icmp_seq=1 ttl=64 time=0.089 ms
64 bytes from 172.31.100.200: icmp_seq=2 ttl=64 time=0.059 ms
#07 liux-test的网络名称空间ping宿主机的IP地址
[root@docker01 harbor]# ip netns exec liux-test ping 172.31.100.100
PING 172.31.100.100 (172.31.100.100) 56(84) bytes of data.
64 bytes from 172.31.100.100: icmp_seq=1 ttl=64 time=0.135 ms
64 bytes from 172.31.100.100: icmp_seq=2 ttl=64 time=0.065 ms
# 未添加网关,无法跨网段ping通
[root@docker01 harbor]# ip netns exec liux-test ping 192.168.91.52
connect: Network is unreachable
# 配置默认网关
[root@docker01 harbor]# ip netns exec liux-test route add default gw 172.31.100.100
# Duang~可以ping通啦!
[root@docker01 harbor]# ip netns exec liux-test ping 192.168.91.52
PING 192.168.91.52 (192.168.91.52) 56(84) bytes of data.
64 bytes from 192.168.91.52: icmp_seq=1 ttl=64 time=0.124 ms
64 bytes from 192.168.91.52: icmp_seq=2 ttl=64 time=0.077 ms
# 无法访问外网,这是正常的!此处建议pingIP地址,域名解析需要DNS。
[root@docker01 harbor]# ip netns exec liux-test ping www.baidu.com
# 宿主机可以抓取到数据报文。
[root@docker01 harbor]# tcpdump -i veth100 -nn icmp
# 如果想要连接外网,可以尝试手动配置NAT
[root@docker01 harbor]# ip netns exec liux-test iptables -vnL -t nat
#测试完成后,删除名称空间
#查看挂载点文件是否存在
[root@docker01 harbor]# ll /var/run/netns/
total 0
-r--r--r-- 1 root root 0 May 19 16:26 liux-test
# 删除名称空间
[root@docker01 harbor]# ip netns del liux-test
[root@docker01 harbor]# ll /var/run/netns/
total 0
#删除宿主机的虚拟网卡
[root@docker01 harbor]# ip link del veth100
Cgroups 用于限制和监控容器的资源使用,防止资源争抢。
cpu限制:主要限制进程的cpu使用率
内存限制:防止容器耗尽宿主机内存
磁盘 I/O 和网络带宽:分配优先级和配额
通过 /sys/fs/cgroup 目录配置资源限制(如 cpu.cfs_quota_us 设置 CPU 配额)
#01 查看Cgroup类型
[root@docker01 harbor]# mount -t cgroup
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd)
cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
#02 进入到CPU的挂载路径,并创建自定义的资源限制组
[root@docker01 harbor]# cd /sys/fs/cgroup/cpu
[root@docker01 cpu]# mkdir liux-test
[root@docker01 cpu]# ll liux-test/
total 0
-rw-r--r-- 1 root root 0 May 19 17:05 cgroup.clone_children
--w--w--w- 1 root root 0 May 19 17:05 cgroup.event_control
-rw-r--r-- 1 root root 0 May 19 17:05 cgroup.procs
-r--r--r-- 1 root root 0 May 19 17:05 cpuacct.stat
-rw-r--r-- 1 root root 0 May 19 17:05 cpuacct.usage
-r--r--r-- 1 root root 0 May 19 17:05 cpuacct.usage_percpu
-rw-r--r-- 1 root root 0 May 19 17:05 cpu.cfs_period_us
-rw-r--r-- 1 root root 0 May 19 17:05 cpu.cfs_quota_us
-rw-r--r-- 1 root root 0 May 19 17:05 cpu.rt_period_us
-rw-r--r-- 1 root root 0 May 19 17:05 cpu.rt_runtime_us
-rw-r--r-- 1 root root 0 May 19 17:05 cpu.shares
-r--r--r-- 1 root root 0 May 19 17:05 cpu.stat
-rw-r--r-- 1 root root 0 May 19 17:05 notify_on_release
-rw-r--r-- 1 root root 0 May 19 17:05 tasks
#03 使用stress压力测试
[root@docker01 cpu]# yum -y install epel-release
[root@docker01 cpu]# yum -y install stress
# # 压力测试20分钟,启动4个worker进程的CPU压测。如下图所示,4个cpu瞬间打满100%
[root@docker01 cpu]# stress -c 4 -v -t 20m
#04 限制CPU的使用率在30%
[root@docker01 cpu]# cd /sys/fs/cgroup/cpu/liux-test && echo 30000 > cpu.cfs_quota_us
#05 将压测任务ID加入自定义限制组
[root@docker01 liux-test]# ps -ef | grep stress | grep -v grep
root 47838 1122 0 17:09 pts/0 00:00:00 stress -c 4 -v -t 20m
root 47839 47838 31 17:09 pts/0 00:01:24 stress -c 4 -v -t 20m
root 47840 47838 35 17:09 pts/0 00:01:35 stress -c 4 -v -t 20m
root 47841 47838 41 17:09 pts/0 00:01:52 stress -c 4 -v -t 20m
root 47842 47838 47 17:09 pts/0 00:02:08 stress -c 4 -v -t 20m
# 进入到咱们自定义的限制组,分别加入限制的进程ID
[root@docker01 liux-test]# cd /sys/fs/cgroup/cpu/liux-test
# 建议加入后,立刻查看top的信息,最好执行一个看一个效果。
[root@docker01 liux-test]# echo 47838 >> tasks
[root@docker01 liux-test]# echo 47839 >> tasks
[root@docker01 liux-test]# echo 47840 >> tasks
[root@docker01 liux-test]# echo 47841 >> tasks
[root@docker01 liux-test]# echo 47842 >> tasks
# 启动容器
[root@docker01 ~] # docker run --name stress-cpu -d harbor.liux.com/liux/stress stress -c 4 -v -t 20m
#查看容器的状态
[root@docker01 ~]# docker stats stress-cpu
#更新CPU限制案例,修改CPU的内存限制为30%
[root@docker01 ~]# docker container update --cpu-quota=30000 stress-cpu
#1.启动容器
[root@docker01 ~]# docker run --name stress-memory -d harbor.liux.com/liux/stress tail -f /etc/hosts
#2.查看容器的状态
[root@docker01 ~]# docker stats stress-memory
#3.更新memeory限制案例,限制内存使用量为200M。
[root@docker01 ~]# docker container update -m 209715200 --memory-swap 209715200 stress-memory
#4.压测是否能够超过200M内存
[root@docker01 ~]# docker exec stress-memory stress --vm-bytes 60M -m 3 --vm-keep
OverlayFS是一种堆叠文件系统,它依赖并建立在其它的文件系统之上(例如ext4fs和xfs等),并不直接参与磁盘空间结构的划分,仅仅将原来系统文件中的文件或者目录进行"合并一起",最后向用户展示"合并"的文件是在同一级的目录, 这就是联合挂载技术, 相对于AUFS (<1.12 早期使用的存储技术), OverlayFS速度更快,实现更简单。
Linux内核为Docker提供的OverlayFS驱动有两种:Overlay和Overlay2。而Overlay2是相对于Overlay的一种改进,在Inode利用率方面比Overlay更有效。
OverlayFS实现方式:
OverlayFS通过三个目录:lower目录、upper目录、以及work目录实现。
lower:
一般对应的是只读数据。
upper:
可以进行读写操作的目录。
work:
目录为工作基础目录,挂载后会自动创建一个work子目录(实际测试手动卸载后该目录并不会被删除)
该目录主要是存储一些临时存放的结果或中间数据的工作目录。
值得注意的是,在使用过程中其内容用户不可见,最后联合挂载完成给用户呈现的统一视图称为merged目录。
OverlayFS结构分为三个层: LowerDir、Upperdir、MergedDir
LowerDir (只读)
只读的image layer,其实就是rootfs。
在使用Dockfile构建镜像的时候, Image Layer可以分很多层,所以对应的lowerdir会很多(源镜像)。
Lower 包括两个层:
(1)系统的init
1)容器在启动以后, 默认情况下lower层是不能够修改内容的, 但是用户有需求需要修改主机名与域名地址, 那么就需要添加init层中的文件(hostname, resolv.conf,hosts,mtab等文件), 用于解决此类问题;
2)修改的内容只对当前的容器生效, 而在docker commit提交为镜像时候,并不会将init层提交。
3)init文件存放的目录为/var/lib/docker/overlay2//diff
(2)容器的镜像层
不可修改的数据。Upperdir (读写)
upperdir则是在lowerdir之上的一层, 为读写层。容器在启动的时候会创建, 所有对容器的修改, 都是在这层。比如容器启动写入的日志文件,或者是应用程序写入的临时文件。MergedDir (展示)
merged目录是容器的挂载点,在用户视角能够看到的所有文件,都是从这层展示的。
#01 创建工作目录
[root@docker01 ~]# mkdir -pv /liux2025/lower{0..2} /liux2025/{uppper,work,merged}
#02 挂载文件系统
[root@docker01 ~]# mount -t overlay overlay -o lowerdir=/liux2025/lower0:/liux2025/lower1:/liux2025/lower2,upperdir=/liux2025/uppper,workdir=/liux2025/work /liux2025/merged/
#03 查看挂载信息
[root@docker01 ~]# mount | grep merged
overlay on /liux2025/merged type overlay (rw,relatime,lowerdir=/liux2025/lower0:/liux2025/lower1:/liux2025/lower2,upperdir=/liux2025/uppper,workdir=/liux2025/work)
#04 尝试在lower层写入准备初始数据
[root@docker01 ~]# cp /etc/hosts /liux2025/lower0/
[root@docker01 ~]# cp /etc/issue /liux2025/lower1/
[root@docker01 ~]# cp /etc/resolv.conf /liux2025/lower2/
[root@docker01 ~]# ll /liux2025 -R
/liux2025:
total 0
drwxr-xr-x 2 root root 19 May 20 09:38 lower0
drwxr-xr-x 2 root root 19 May 20 09:38 lower1
drwxr-xr-x 2 root root 25 May 20 09:39 lower2
drwxr-xr-x 1 root root 6 May 20 09:32 merged
drwxr-xr-x 2 root root 6 May 20 09:32 uppper
drwxr-xr-x 3 root root 18 May 20 09:32 work
/liux2025/lower0:
total 4
-rw-r--r-- 1 root root 263 May 20 09:38 hosts
/liux2025/lower1:
total 4
-rw-r--r-- 1 root root 23 May 20 09:38 issue
/liux2025/lower2:
total 4
-rw-r--r-- 1 root root 57 May 20 09:39 resolv.conf
/liux2025/merged:
total 12
-rw-r--r-- 1 root root 263 May 20 09:38 hosts
-rw-r--r-- 1 root root 23 May 20 09:38 issue
-rw-r--r-- 1 root root 57 May 20 09:39 resolv.conf
...
#05 尝试在upper层写入准备初始数据
[root@docker01 ~]# cp /etc/hostname /liux2025/uppper/
[root@docker01 ~]# ll /liux2025 -R
...
/liux2025/merged:
total 16
-rw-r--r-- 1 root root 9 May 20 09:42 hostname
-rw-r--r-- 1 root root 263 May 20 09:38 hosts
-rw-r--r-- 1 root root 23 May 20 09:38 issue
-rw-r--r-- 1 root root 57 May 20 09:39 resolv.conf
/liux2025/uppper:
total 4
-rw-r--r-- 1 root root 9 May 20 09:42 hostname
#06 尝试在merged目录写入数据,观察数据实际写入的应该是upper层
[root@docker01 ~]# cp /etc/fstab /liux2025/merged/
[root@docker01 ~]# ll /liux2025 -R
...
/liux2025/merged:
total 20
-rw-r--r-- 1 root root 407 May 20 09:47 fstab
-rw-r--r-- 1 root root 9 May 20 09:42 hostname
-rw-r--r-- 1 root root 263 May 20 09:38 hosts
-rw-r--r-- 1 root root 23 May 20 09:38 issue
-rw-r--r-- 1 root root 57 May 20 09:39 resolv.conf
/liux2025/uppper:
total 8
-rw-r--r-- 1 root root 407 May 20 09:47 fstab
-rw-r--r-- 1 root root 9 May 20 09:42 hostname
...
#07 重新挂载,但不挂载upperdir层
[root@docker01 ~]# umount /liux2025/merged
[root@docker01 ~]# mount -t overlay overlay -o lowerdir=/liux2025/lower0:/liux2025/lower1:/liux2025/lower2,workdir=/liux2025/work /liux2025/merged/
#08 再次尝试写入数据失败,因为没有写入层
[root@docker01 ~]# cp /etc/os-release /liux2025/merged/
cp: cannot create regular file ‘/liux2025/merged/os-release’: Read-only file system
#09 卸载挂载路径,删除测试目录
[root@docker01 ~]# umount /liux2025/merged
[root@docker01 ~]# rm -rf /liux2025
通过 Dockerfile 定义构建步骤,每条指令生成一个镜像层;
分层存储减少重复数据,提升构建和分发效率。
docker run 触发镜像拉取(若本地不存在);
创建容器时,Docker 调用 runc(OCI 标准实现)创建命名空间和 Cgroups;
挂载 OverlayFS ,添加可写层,并配置网络和进程隔离。
容器进程由宿主机内核直接调度,启动速度达秒级;
停止容器时,可写层数据保留或丢弃(取决于是否使用持久化卷)。
总结:
Docker 的底层原理通过 Linux 命名空间实现资源隔离,Cgroups 控制资源分配,OverlayFS 管理分层文件系统,最终构建了一个轻量、高效、可移植的容器化平台。其核心优势在于将应用与环境解耦,显著提升了开发、测试和部署的效率。