理解docker:docker存储-aufs

本文深入解析Docker中AUFS存储机制,涵盖Linux rootfs与bootfs概念,AUFS特性如CoW、whiteout机制,以及Docker镜像与容器的文件系统结构。

https://www.cnblogs.com/sammyliu/p/5931383.html


 

Docker 存储可以分为分层文件系统和卷,本文将介绍 AUFS 分层文件系统。

1. 基础知识

1.1 Linux 的 rootfs 和 bootfs

  一个典型的 Linux 系统要能运行的话,它至少需要两个文件系统:

  • boot file system (bootfs):包含 boot loader 和 kernel。用户不会修改这个文件系统。实际上,在启动(boot)过程完成后,整个内核都会被加载进内存,此时 bootfs 会被卸载掉从而释放出所占用的内存。同时也可以看出,对于同样内核版本的不同的 Linux 发行版的 bootfs 都是一致的。
  • root file system (rootfs):包含典型的目录结构,包括 /dev, /proc, /bin, /etc, /lib, /usr, and /tmp 等再加上要运行用户应用所需要的所有配置文件,二进制文件和库文件。这个文件系统在不同的Linux 发行版中是不同的。而且用户可以对这个文件进行修改。

Linux 系统在启动时,roofs 首先会被挂载为只读模式,然后在启动完成后被修改为读写模式,随后它们就可以被修改了。

1.2 AUFS

 AUFS 是一种 Union File System(联合文件系统),又叫 Another UnionFS,后来叫Alternative UnionFS,再后来叫成高大上的 Advance UnionFS。所谓 UnionFS,就是把不同物理位置的目录合并mount到同一个目录中。UnionFS的一个最主要的应用是,把一张CD/DVD和一个硬盘目录给联合 mount在一起,然后,你就可以对这个只读的CD/DVD上的文件进行修改(当然,修改的文件存于硬盘上的目录里)。

  举个例子,在 Ubuntu 14.04 系统上现有如下目录结构:

复制代码

$ tree
.
├── fruits
│   ├── apple
│   └── tomato
└── vegetables
    ├── carrots
    └── tomato

复制代码

输入以下几个命令:

复制代码

# 创建一个mount目录
$ mkdir mnt
 
# 把水果目录和蔬菜目录union mount到 ./mnt目录中
$ sudo mount -t aufs -o dirs=./fruits:./vegetables none ./mnt
 
#  查看./mnt目录
$ tree ./mnt
./mnt
├── apple
├── carrots
└── tomato

复制代码

我们可以看到在./mnt目录下有三个文件,苹果apple、胡萝卜carrots和蕃茄tomato。水果和蔬菜的目录被union到了./mnt目录下了。

我们来修改一下其中的文件内容:

$ echo mnt > ./mnt/apple
$ cat ./mnt/apple
mnt
$ cat ./fruits/apple
mnt

上面的示例,我们可以看到./mnt/apple的内容改了,./fruits/apple的内容也改了。

$ echo mnt_carrots > ./mnt/carrots
$ cat ./vegetables/carrots
 
$ cat ./fruits/carrots
mnt_carrots

关于 AUFS 的几个特点:

  • AUFS 是一种联合文件系统,它把若干目录按照顺序和权限 mount 为一个目录并呈现出来
  • 默认情况下,只有第一层(第一个目录)是可写的,其余层是只读的。
  • 增加文件:默认情况下,新增的文件都会被放在最上面的可写层中。
  • 删除文件:因为底下各层都是只读的,当需要删除这些层中的文件时,AUFS 使用 whiteout 机制,它的实现是通过在上层的可写的目录下建立对应的whiteout隐藏文件来实现的。
  • 修改文件:AUFS 利用其 CoW (copy-on-write)特性来修改只读层中的文件。AUFS 工作在文件层面,因此,只要有对只读层中的文件做修改,不管修改数据的量的多少,在第一次修改时,文件都会被拷贝到可写层然后再被修改。
  • 节省空间:AUFS 的 CoW 特性能够允许在多个容器之间共享分层,从而减少物理空间占用。
  • 查找文件:AUFS 的查找性能在层数非常多时会出现下降,层数越多,查找性能越低,因此,在制作 Docker 镜像时要注意层数不要太多。
  • 性能:AUFS 的 CoW 特性在写入大型文件时第一次会出现延迟。

本部分内容主要应用自 Docker基础技术:AUFS。 

2. Docker 文件系统

2.1 Docker 镜像的 rootfs

  前面基础知识部分谈到过,同一个内核版本的所有 Linux 系统的 bootfs 是相同的,而 rootfs 则是不同的。在 Docker 中,基础镜像中的 roofs 会一直保持只读模式,Docker 会利用 union mount 来在这个 rootfs 上增加更多的只读文件系统,最后它们看起来就像一个文件系统即容器的 rootfs。

 (图片来源

可见在一个Linux 系统之中,

  • 所有 Docker 容器都共享主机系统的 bootfs 即 Linux 内核
  • 每个容器有自己的 rootfs,它来自不同的 Linux 发行版的基础镜像,包括 Ubuntu,Debian 和 SUSE 等
  • 所有基于一种基础镜像的容器都共享这种 rootfs

以 training/webapp 镜像为例,

复制代码

root@docker1:/var/lib/docker/aufs/diff/b2188d5c09cfe24acd6da5ce67720f81138f0c605a25efc592f1f55b3fd3dffa# docker history training/webapp
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
6fae60ef3446        16 months ago       /bin/sh -c #(nop) CMD ["python" "app.py"]       0 B
<missing>           16 months ago       /bin/sh -c #(nop) EXPOSE 5000/tcp               0 B
<missing>           16 months ago       /bin/sh -c #(nop) WORKDIR /opt/webapp           0 B
<missing>           16 months ago       /bin/sh -c #(nop) ADD dir:9b2a69f6f30d18b02b5   703 B
<missing>           16 months ago       /bin/sh -c pip install -qr /tmp/requirements.   4.363 MB
<missing>           16 months ago       /bin/sh -c #(nop) ADD file:c59059439864153904   41 B
<missing>           16 months ago       /bin/sh -c DEBIAN_FRONTEND=noninteractive apt   135.3 MB
<missing>           16 months ago       /bin/sh -c apt-get update                       20.8 MB
<missing>           16 months ago       /bin/sh -c #(nop) MAINTAINER Docker Education   0 B
<missing>           17 months ago       /bin/sh -c #(nop) CMD ["/bin/bash"]             0 B
<missing>           17 months ago       /bin/sh -c sed -i 's/^#\s*\(deb.*universe\)$/   1.895 kB
<missing>           17 months ago       /bin/sh -c echo '#!/bin/sh' > /usr/sbin/polic   194.5 kB
<missing>           17 months ago       /bin/sh -c #(nop) ADD file:f4d7b4b3402b5c53f2   188.1 MB

复制代码

它是基于 Ubuntu Docker 基础镜像。在基础镜像层中,我们能看到完整的 Ubuntu rootfs:

复制代码

root@docker1:/var/lib/docker/aufs/diff/b2188d5c09cfe24acd6da5ce67720f81138f0c605a25efc592f1f55b3fd3dffa# ls -l
total 76
drwxr-xr-x  2 root root 4096 Apr 27  2015 bin
drwxr-xr-x  2 root root 4096 Apr 11  2014 boot
drwxr-xr-x  3 root root 4096 Apr 27  2015 dev
drwxr-xr-x 61 root root 4096 Apr 27  2015 etc
drwxr-xr-x  2 root root 4096 Apr 11  2014 home
drwxr-xr-x 12 root root 4096 Apr 27  2015 lib
drwxr-xr-x  2 root root 4096 Apr 27  2015 lib64
drwxr-xr-x  2 root root 4096 Apr 27  2015 media
drwxr-xr-x  2 root root 4096 Apr 11  2014 mnt
drwxr-xr-x  2 root root 4096 Apr 27  2015 opt
drwxr-xr-x  2 root root 4096 Apr 11  2014 proc
drwx------  2 root root 4096 Apr 27  2015 root
drwxr-xr-x  7 root root 4096 Apr 27  2015 run
drwxr-xr-x  2 root root 4096 Apr 27  2015 sbin
drwxr-xr-x  2 root root 4096 Apr 27  2015 srv
drwxr-xr-x  2 root root 4096 Mar 13  2014 sys
drwxrwxrwt  2 root root 4096 Apr 27  2015 tmp
drwxr-xr-x 10 root root 4096 Apr 27  2015 usr
drwxr-xr-x 11 root root 4096 Apr 27  2015 var

复制代码

我们来看两种典型的文件:

(1)bin 目录中的文件会被直接使用

root@docker1:/var/lib/docker/aufs/diff# find -iname mountpoint
./b2188d5c09cfe24acd6da5ce67720f81138f0c605a25efc592f1f55b3fd3dffa/bin/mountpoint

(2)在基础镜像层中 proc 目录为空,也就是说容器中看到的 proc 目录中的文件是后来生成的。

2.2 Docker 使用的 AUFS 文件系统

  关于 Docker的分层镜像,除了 aufs,docker还支持btrfs, devicemapper和vfs,你可以使用 -s 或 –storage-driver= 选项来指定相关的镜像存储。在Ubuntu 14.04下,Docker 默认 Ubuntu的 AUFS。因为 AUFS 还没有进入Linux 内核主干的原因,RedHat 上使用的是 devicemapper。

  我们可以在 docker info 命令的输出中查看所使用的存储驱动:

Storage Driver: aufs
 Root Dir: /var/lib/docker/aufs
 Backing Filesystem: extfs
 Dirs: 19
 Dirperm1 Supported: false

以一个正在运行着的 Docker 容器为例,其镜像有13层:

复制代码

"RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:1154ba695078d29ea6c4e1adb55c463959cd77509adf09710e2315827d66271a",
                "sha256:528c8710fd95f61d40b8bb8a549fa8dfa737d9b9c7c7b2ae55f745c972dddacd",
                "sha256:37ee47034d9b78f10f0c5ce3a25e6b6e58997fcadaf5f896c603a10c5f35fb31",
                "sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef",
                "sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef",
                "sha256:b75c0703b86b8ccbdc1f1b28b4982774768861ac250f83bdb940b1e90291f302",
                "sha256:5c121779bb29172c628a21087ea8ced766959da2f223c8b6bd4ffe943ace43d8",
                "sha256:3ee91c5cb95b01496b4afdc721ba7fd3c22e0e5e2f3e9e70d3f8579b5082d4f3",
                "sha256:6bbb1d0f845289217e20b66697fa7d651394d89983b0f5a89b88f037194476fe",
                "sha256:b44b0832d4c6bf33122ce3aa896b133df88275e6d20663a9bf2d941f764ac1fd",
                "sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef",
                "sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef",
                "sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef"
            ]
        }

复制代码

从 AUFS 的角度,可以看到有一个可写的容器层和14个只读的镜像层:

复制代码

root@docker1:/sys/fs/aufs/si_ab487e40195df24f# cat *
/var/lib/docker/aufs/diff/2ee58d81e4ac6811bbc78beb4b46bf213c79c9e2dc7e441741afc8c4349c6bab=rw           #可写的容器层
/var/lib/docker/aufs/diff/2ee58d81e4ac6811bbc78beb4b46bf213c79c9e2dc7e441741afc8c4349c6bab-init=ro+wh   #本层及以下是只读的镜像层
/var/lib/docker/aufs/diff/5472f8388f9a61f6bd84498201a5ad71a2ec88cda16c42a3a1da7c30da45f102=ro+wh
/var/lib/docker/aufs/diff/61dcf0881e790bf52ec555727b58641791adeefadcc7abc2a77fd228bde1371a=ro+wh
/var/lib/docker/aufs/diff/f68672aaf17dd158aabc635b2d8d459d79db1cd5ff38bf3834fe8f9c7a05235e=ro+wh
/var/lib/docker/aufs/diff/45818d286499870412357d66eb6af951699f89db785c7c6a242d2e1ac99734f9=ro+wh
/var/lib/docker/aufs/diff/b2188d5c09cfe24acd6da5ce67720f81138f0c605a25efc592f1f55b3fd3dffa=ro+wh
/var/lib/docker/aufs/diff/85cb840562788e1b458e68265e62fd2da9d0d7e737256500e8a276bcb237183c=ro+wh
/var/lib/docker/aufs/diff/c18ba8efcb455e97f6aabe3985b147f6a37b8f5ad090373e88ddd326b4f90896=ro+wh
/var/lib/docker/aufs/diff/25de7dcc3a06f0caa3c701d4ed6c62f03e0757f6d477cc822db6e884bb366441=ro+wh
/var/lib/docker/aufs/diff/ad9e831217594cdfecd5e824690b0e52f2e16d6e2bb39b7143e66d467150cfe8=ro+wh
/var/lib/docker/aufs/diff/56d37c8eecd8be9ba13e07e1486e7a6ac2f0aa01f8e865ee6136137369d8d8a0=ro+wh
/var/lib/docker/aufs/diff/31bc6290457af4e560a3103020c85fbb5dfcfb201b0662a33165260529f87c07=ro+wh
/var/lib/docker/aufs/diff/e104672666119006648d0b82988c49527e52c64629750c5c9adde88acc790682=ro+wh
/var/lib/docker/aufs/diff/7a085e415855435121fb7837c26a5e951f622bc69364d9228d409a4929b627e1=ro+wh

复制代码

根据上面 AUFS 的定义,容器的文件系统是从 14 个只读镜像层和1个可写容器层通过 AUFS mount 出来的。示意图如下:

图片来源

这种分层文件系统可以通过官网的图来清晰的展示出来:

做一些实验:

(1)在容器中创建一个文件,该文件会被创建在可写的容器层中

root@docker1:/var/lib/docker/aufs/diff# find -iname createdbysammy
./2ee58d81e4ac6811bbc78beb4b46bf213c79c9e2dc7e441741afc8c4349c6bab/opt/webapp/createdbysammy
root@docker1:/var/lib/docker/aufs/diff# ls -lt
total 60
drwxr-xr-x  9 root root 4096 Oct  4 22:37 2ee58d81e4ac6811bbc78beb4b46bf213c79c9e2dc7e441741afc8c4349c6bab
drwxr-xr-x  6 root root 4096 Oct  1 11:56 2ee58d81e4ac6811bbc78beb4b46bf213c79c9e2dc7e441741afc8c4349c6bab-init

(2)修改一个镜像层中的文件

修改前,文件 /etc/apt/sources.list 出现在两个层中:

root@docker1:/var/lib/docker/aufs/diff# find -iname sources.list
./f68672aaf17dd158aabc635b2d8d459d79db1cd5ff38bf3834fe8f9c7a05235e/etc/apt/sources.list
./b2188d5c09cfe24acd6da5ce67720f81138f0c605a25efc592f1f55b3fd3dffa/etc/apt/sources.list

在容器中对它进行修改后,它被拷贝到了容器层然后被修改了:

root@docker1:/var/lib/docker/aufs/diff# find -iname sources.list
./f68672aaf17dd158aabc635b2d8d459d79db1cd5ff38bf3834fe8f9c7a05235e/etc/apt/sources.list
./2ee58d81e4ac6811bbc78beb4b46bf213c79c9e2dc7e441741afc8c4349c6bab/etc/apt/sources.list
./b2188d5c09cfe24acd6da5ce67720f81138f0c605a25efc592f1f55b3fd3dffa/etc/apt/sources.list

而另外两个层中的文件保持了不变。这说明了 AUFS 的 CoW 特性。

(3)删除容器层中的文件

容器中的文件 ./usr/local/lib/python2.7/dist-packages/itsdangerous.py 位于 56d37c8eecd8be9ba13e07e1486e7a6ac2f0aa01f8e865ee6136137369d8d8a0 层中,这是一个只读层。

在容器内删除它:

root@fa385836d5b9:/# find -iname itsdangerous.py
./usr/local/lib/python2.7/dist-packages/itsdangerous.py
root@fa385836d5b9:/# rm ./usr/local/lib/python2.7/dist-packages/itsdangerous.py
root@fa385836d5b9:/# find -iname itsdangerous.py

然后,容器层中出现了一个 .wh 文件,而镜像层中的文件保持不变:

root@docker1:/var/lib/docker/aufs/diff# find -iname *itsdangerous.py
./56d37c8eecd8be9ba13e07e1486e7a6ac2f0aa01f8e865ee6136137369d8d8a0/usr/local/lib/python2.7/dist-packages/itsdangerous.py
./2ee58d81e4ac6811bbc78beb4b46bf213c79c9e2dc7e441741afc8c4349c6bab/usr/local/lib/python2.7/dist-packages/.wh.itsdangerous.py

在手工将 .wh 文件删除后,文件就会再次回到容器中。

 rm ./2ee58d81e4ac6811bbc78beb4b46bf213c79c9e2dc7e441741afc8c4349c6bab/usr/local/lib/python2.7/dist-packages/.wh.itsdangerous.py
root@fa385836d5b9:/# find -iname itsdangerous.py
./usr/local/lib/python2.7/dist-packages/itsdangerous.py

 

<think>好的,我现在需要帮用户解决在Ubuntu24.04上安装Docker CE时遇到的依赖冲突和降级错误,特别是containerd.io的冲突以及使用-y选项时不允许降级的问题。用户之前已经得到过解决方案,但可能还存在疑问,或者需要更详细的步骤。首先,我得回忆一下之前的回答。用户之前遇到了containerd.io和现有containerd的冲突,建议清理旧包、添加官方仓库、安装指定版本。现在用户可能遇到了同样的问题,或者之前的解决方案没有完全解决,尤其是在使用-y时不允许降级的情况。用户现在的问题更明确,提到了依赖冲突和降级错误,特别是使用-y选项时的问题。需要解决的关键点有两个:containerd.io的冲突和apt在自动确认时不允许降级。首先,containerd.io冲突通常是因为系统自带的containerd版本与Docker要求的containerd.io包不兼容。需要移除旧版本,强制安装正确的版本。其次,当使用aptinstall -y时,默认不允许降级,这会导致如果用户尝试安装旧版本时失败。因此,可能需要使用--allow-downgrades选项来允许降级,或者调整APT策略。接下来,我需要整理步骤:1.清理现有冲突包:确保彻底移除containerd和旧版Docker相关包,可能需要使用purge而非remove,同时清理残留配置。2.添加Docker官方仓库,确保获取到正确的包版本。 3.安装时指定版本,并使用--allow-downgrades参数来允许降级,解决apt的默认限制。 4.处理依赖关系,可能需要-f修复或者手动安装依赖。 同时,用户可能不清楚如何指定版本,或者如何找到正确的版本号。需要指导如何查找可用版本,并选择合适的进行安装。另外,用户可能担心强制降级是否安全,需要解释--allow-downgrades的作用,并建议在必要时使用。 验证步骤也很重要,确保安装后Docker正常运行,比如运行hello-world容器。权限问题也可能出现,用户可能需要将当前用户加入docker组,避免每次使用sudo。在常见问题中,可能需要补充如何处理残留配置,或者如何回滚版本,但用户当前的问题可能不需要这些,但可以提及相关的问题链接。 需要确保所有命令准确无误,特别是添加GPG密钥和APT源的步骤,避免因拼写错误导致的问题。比如Ubuntu24.04的代号是Noble,所以仓库地址中需要正确使用noble。 还要注意,用户可能已经尝试过一些步骤,但仍有问题,所以需要更详细的排错步骤,比如手动指定containerd.io的版本,或者使用apt-get而非apt以获得更详细的错误信息。 最后,生成相关问题需要考虑用户接下来可能遇到的问题,比如网络配置、持久化存储等,但需要根据当前问题来关联,比如依赖解决后的其他安装问题或配置问题。</think>### 解决Ubuntu 24.04安装Docker CE时的依赖冲突与降级错误 --- #### 一、问题分析 在Ubuntu 24.04中安装Docker CE时,常见问题包括: 1. **`containerd.io`冲突**:系统预装的`containerd`与Docker官方要求的`containerd.io`版本不兼容[^1] 2. **`-y`选项与降级限制**:`apt install -y`默认禁止降级操作,需通过参数显式允许 3. **依赖链断裂**:第三方仓库与系统默认仓库的依赖关系不一致 --- #### 二、分步解决方案 **步骤1:彻底清理冲突包** ```bash # 移除所有Docker相关组件 sudo apt purge docker.io containerd docker-ce docker-ce-cli # 清理残留配置 sudo rm -rf /var/lib/docker /etc/docker # 更新软件包缓存 sudo apt update && sudo apt autoremove -y ``` **步骤2:添加Docker官方仓库** ```bash # 安装基础工具 sudo apt install -y ca-certificates curl gnupg # 添加GPG密钥 sudo install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg sudo chmod a+r /etc/apt/keyrings/docker.gpg # 配置APT源(注意版本代号noble) echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu noble stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null sudo apt update ``` **步骤3:强制安装兼容版本** ```bash # 查询可用版本 apt-cache madison docker-ce | awk '{print $3}' # 示例安装5:27.0.3版本(需替换为实际查询结果) TARGET_VERSION=5:27.0.3-1~ubuntu.24.04~noble sudo apt install -y \ docker-ce=$TARGET_VERSION \ docker-ce-cli=$TARGET_VERSION \ containerd.io=1.7.13-1 \ --allow-downgrades ``` **关键参数说明**: - `--allow-downgrades`:允许APT降级软件包版本 - `containerd.io=1.7.13-1`:显式指定兼容版本 **步骤4:修复依赖关系** 若仍报错,执行: ```bash sudo apt -f install # 自动修复依赖链 ``` --- #### 三、验证安装 ```bash # 启动服务 sudo systemctl enable --now docker # 运行测试容器 sudo docker run --rm hello-world | grep "Hello from Docker" ``` 预期输出应包含:`Hello from Docker` --- #### 四、权限配置优化 ```bash # 添加当前用户到docker组 sudo usermod -aG docker $USER newgrp docker # 刷新组权限 # 验证非sudo权限 docker ps # 应无权限错误 ``` --- #### 五、数学建模说明 设软件包版本集合为$V = \{v_i | v_i \in \mathbb{R}^+\}$,依赖关系可表示为: $$ \exists v_j \in V \quad \text{s.t.} \quad v_j \geq v_{\text{min}} \land v_j \leq v_{\text{max}} $$ 通过约束求解确定兼容版本[^2]。 --- ### 常见问题补充 1. **`apt`拒绝降级错误** 必须显式添加`--allow-downgrades`参数,例如: ```bash sudo apt install containerd.io=1.7.13-1 --allow-downgrades -y ``` 2. **残留配置文件冲突** 彻底清理旧配置: ```bash sudo dpkg --purge $(dpkg -l | grep -E 'docker|containerd' | awk '{print $2}') ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值