镜像层与可写层原理
镜像层 = 只读的"模板"(所有容器共享)
可写层 = 每个容器独有的"草稿纸"(容器删除就没了)
单个容器的文件系统结构
容器看到的文件系统 (rootfs)
↓
┌─────────────────┐
│ 可写层 │ ← 容器运行时的修改都在这
│ (Container) │ (读写,容器独有)
├─────────────────┤
│ 镜像层3 │ ← 只读,所有用这个镜像的
│ (Layer 3) │ 容器共享
├─────────────────┤
│ 镜像层2 │ ← 只读,共享
│ (Layer 2) │
├─────────────────┤
│ 镜像层1 │ ← 只读,共享
│ (Layer 1) │
└─────────────────┘
↓
物理存储位置
场景:运行3个Nginx容器
物理存储上:
/var/lib/containerd/
├── 镜像层存储/
│ ├── layer1: nginx基础层 (100MB) ← 只有1份
│ ├── layer2: nginx配置层 (10MB) ← 只有1份
│ └── layer3: nginx应用层 (50MB) ← 只有1份
│
└── 可写层存储/
├── 容器A的可写层 (5MB) ← 容器A独有
├── 容器B的可写层 (3MB) ← 容器B独有
└── 容器C的可写层 (8MB) ← 容器C独有
总占用 = 160MB(镜像层) + 16MB(可写层) = 176MB
如果没有分层,需要: 160MB × 3 = 480MB
容器内的操作
bash
# 在容器A中操作
docker exec -it 容器A bash
# 1. 读取文件 /usr/share/nginx/index.html
cat /usr/share/nginx/index.html
# → 从镜像层读取(所有容器看到的一样)
# 2. 修改文件
echo "Hello A" > /usr/share/nginx/index.html
# → 触发 Copy-on-Write (写时复制)
# → 文件从镜像层复制到容器A的可写层
# → 修改只在容器A的可写层
# 3. 新建文件
echo "test" > /tmp/myfile.txt
# → 直接写入容器A的可写层
其他容器不受影响
bash
# 在容器B中
cat /usr/share/nginx/index.html
# → 仍然读取镜像层的原始文件
# → 看不到容器A的修改
五、写时复制(Copy-on-Write)机制
工作原理
1. 容器要修改 /etc/nginx/nginx.conf
2. 检查文件位置
┌─────────────────────────┐
│ 文件在镜像层? │
│ Yes → 触发COW │
└──────────┬──────────────┘
↓
┌──────────────────────────┐
│ 复制文件到可写层 │
└──────────┬───────────────┘
↓
┌──────────────────────────┐
│ 在可写层修改文件 │
└──────────┬───────────────┘
↓
┌──────────────────────────┐
│ 容器看到的是可写层的版本 │
│ 镜像层的原文件被"遮住" │
└──────────────────────────┘