一、docker文件系统与宿主机内核
1.1 系统内核加载
Docker架构
Docker 使用客户端/服务器端架构。 Docker 客户端与 Docker 守护进程对话,后者负责构建、运行和分发 Docker 容器的繁重工作。 Docker 客户端和守护程序可以在同一系统上运行,或者可以将 Docker 客户端连接到远程 Docker 守护程序。 Docker 客户端和守护进程使用 REST API、UNIX 套接字或网络接口进行通信。 另一个 Docker 客户端是 Docker Compose,它允许您使用由一组容器组成的应用程序。
Docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统叫 UnionFS宿主机 Linux 刚启动时会加载bootfs (boot file system)文件系统,当 bootloader 加载完成之后,整个内核就都在内存中了,此时内存的使用权已由 bootfs 转交给内核,此时系统也会卸载 bootfs,开始运行rootfs(root file system)。
rootfs 就是各种不同的操作系统发行版,比如 Ubuntu, Centos 等等,rootfs在 bootfs之上,包含的就是典型 Linux 系统中的 /dev、/proc/bin、/etc 等标准目录和文件。
不同的 Linux 发行版, boots 基本是一致的, rootfs 会有差別,因此不同的发行版可以公用 bootfs,底层直接用主机的 kernel
1.2 容器进程加载
docker文件系统
Docker镜像需要提供 rootfs 。对于精简的OS , rootfs 可以很小,只需要包合最基本的命令,工具和程序库就可以了,省去了一些无关的软件,如办公工具等。
docker进程启动后,在 Docker 镜像的最底层是 bootfs,几乎不变,这一层与我们典型的 Linux/Unix 系统是一样的,包含 bootloader 和 Kernel,
个G的镜像已经被读入到了内存中,而容器是操作镜像的方式,这个方式一般都不会太大。所以平时我们安装进虚拟机的 CentOS 都是好几个G,为什么 Docker 这里才200M
二、镜像、容器和存储驱动的关系
Docker为了节约存储空间共享数据会对镜像和容器进行分层,不同镜像可以共享相同数据,在镜像上为容器分配一个RW层来加快容器的启动顺序。
Docker中的存储驱动采用栈层式管理镜像层、写时复制管理容器层的存储空间。
2.1 栈层式管理镜像层
Docker的镜像层:Dockerfile中的每一条指令都会对应于Docker镜像中的一层。Dockerfile中命令与镜像层一一对应,则docker build完毕之后,镜像的总大小=每一层镜像的大小总和每个镜像都由多个镜像层组成,从下往上以栈的方式组合在一起形成容器的根文件系统,Docker的存储驱动用于管理这些镜像层,对外提供单一的文件系统。
Docker 的镜像实际上由一层一层的文件系统组成,这种层级的文件系统叫 UnionFS(联合文件系统)
由于联合文件系统的存在,如果镜像层是相同的,则不同的镜像会共享该层,宿主机只需在磁盘上保留一份共享镜像,同时内存中也只需要加载一份共享镜像,如上图中镜像A与镜像B就共享第二层镜像,使得A+B镜像文件大小并不等于A+B镜像占用宿主机存储空间容量的大小。doker images
命令列出的镜像体积总和并不能代表实际使用的磁盘空间,需要使用 docker system df
命令来代替。
由于联合文件系统的存在,容器文件系统内容的大小不等于Docker镜像大小。
2.2 写时复制管理容器层
写时复制采用了共享和复制技术,针对相同的数据系统只保留一份,所有操作都访问这一份数据。当有操作需要修改或添加数据时,操作系统会把这部分数据复制到新的地方再进行修改或添加,而其他操作仍然访问原数据区数据,这项技术节约了镜像的存储空间,加快了系统启动时间。
当容器启动时,Docker就会创建thin类型的可读写容器层,使用预分配存储空间,也就是开始时并不分配存储空间,当需要新建文件或修改文件时,才从存储池中分配一部分存储空间
每个容器运行时都有自己的容器层,保存容器运行相关数据(所有文件变化数据),因为镜像层是只读的,所以多个容器可以共享同一个镜像
为了区别镜像层,Docker为每个镜像层都计算了UUID,根据镜像层中的数据使用加密哈希算法生成UUID
删除容器时,Docker Daemon会删除容器层,保留镜像层
所有镜像层和容器层都保存在宿主机的文件系统/var/lib/docker/中,由存储驱动进行管理。
在下载镜像时,Docker Daemon会检查镜像中的镜像层与宿主机文件系统中的镜像层进行对比,如果存在则不下载,只下载不存在的镜像层。
容器占用的内存。
我们单台主机上可能会跑几十个容器,容器虽然都相互隔离,但是用的却是与宿主机相同的内核,CPU、内存、磁盘等硬件资源。注:容器没有内核。默认情况下,容器没有资源限制,可以使用主机内核调度程序允许的尽可能多的给定资源;如果不对容器资源进行限制,容器之间就会相互影响,一些占用硬件资源较高的容器会吞噬掉所有的硬件资源,从而导致其它容器无硬件资源可用,发生停服状态。Docker提供了限制内存,CPU或磁盘IO的方法, 可以对容器所占用的硬件资源大小以及多少进行限制,我们在使用docker create创建一个容器或者docker run运行一个容器的时候就可以来对此容器的硬件资源做限制。
先通过docker ps -a
找到容器的container id
,再使用ps -ef
找到容器对应的进程pid后,使用top
等查看容器进程的内存占用情况
命令:top -p 5140
为什么Docker镜像大小与仓库中不一致?
镜像原理之联合文件系统
https://www.cnblogs.com/poloyy/p/14970300.html