导图社区 Docker底层原理
介绍几种 Docker 使用的核心技术,如果我们了解它们的使用方法和原理,就能清楚 Docker 的实现原理。
编辑于2021-02-25 18:42:16Docker底层原理
一、 概述
1. 什么是虚拟化
容器与虚拟机本质区别及虚拟化技术分级
是指通过虚拟化技术将一台计算机虚拟为多台逻辑计算机。
2. 什么是操作系统级虚拟化
也被称作容器化,是操作系统自身的一个特性,它允许多个相互隔离的用户空间实例的存在。这些用户空间实例也被称作为容器。
Container技术不是在OS外来建立虚拟环境,而是在OS内的核心系统层来打造虚拟执行环境,透过共享Host OS的作法,取代一个一个Guest OS的功用。Container也因此被称为是OS层的虚拟化技术。
Container技术的发展: 早在1982年,Unix系统内建的chroot机制也是一种Container技术。其他如1998年的FreeBSD jails、2005年出现的Solaris Zones和OpenVZ,或像是Windows系统2004年就有的Sandboxie机制都属于在操作系统内建立孤立虚拟执行环境的作法,都可称为是Container的技术。直到2013年,dotCloud这家PaaS服务公司开源释出了一套将Container标准化的平台Docker,大受欢迎,所以,dotCloud决定以Docker为名成立新公司力推。
操作系统级虚拟化将操作系统所管理的计算机资源,包括进程、文件、设备、网络等分组,然后交给不同的容器使用。容器中运行的进程只能看到分配给该容器的资源。从而达到隔离与虚拟化的目的。 实现操作系统虚拟化需要用到Namespace及cgroups技术。
二、 Linux Namespaces
命名空间是Linux内核的一项功能,该功能对内核资源进行分区。控制进程可以访问的资源,以使一组进程看到一组资源,而另一组进程看到另一组资源。资源可能存在于多个空间中。Linux系统以每种类型的单个名称空间开始,供所有进程使用。进程可以创建其他名称空间,并加入不同的名称空间。 简单的讲,利用Namespace可以实现我们想要的资源隔离,控制哪些资源可以使用。
1. UTS
UTS("UNIX Time-sharing System")名字空间允许每个容器拥有独立的hostname和domain name,使其在 网络上可以被视作一个独立的节点而非主机上的一个进程。
系统调用参数:CLONE_NEWUTS
隔离内容:主机名和域名
2. 进程间通信 ipc
IPC全称 Inter-Process Communication,是Unix/Linux下进程间通信的一种方式,IPC有共享内存、信号量、消息队列等方法。所以,为了隔离,我们也需要把IPC给隔离开来,这样,只有在同一个Namespace下的进程才能相互通信。如果你熟悉IPC的原理的话,你会知道,IPC需要有一个全局的ID,即然是全局的,那么就意味着我们的Namespace需要对这个ID隔离,不能让别的Namespace的进程看到。
系统调用参数:CLONE_NEWIPC
隔离内容:信号量、消息队列和共享内存
3. 进程id pid
不同用户的进程就是通过pid名字空间隔离开的,且不同名字空间中可以有相同pid。所有的LXC进程在 Docker中的父进程为Docker进程,每个LXC进程具有不同的名字空间。同时由于允许嵌套,因此可以很 方便的实现嵌套的Docker容器。
系统调用参数:CLONE_NEWPID
隔离内容:进程编号
4. 网络 net
有了pid名字空间,每个名字空间中的pid能够相互隔离,但是网络端口还是共享host的端口。网络隔离是通过net 名字空间实现的,每个net名字空间有独立的网络设备,IP地址,路由表,/proc/net目录。这样每 个容器的网络就能隔离开来。Docker默认采用veth的方式,将容器中的虚拟网卡同host上的一个Docker 网桥docker0连接在一起。
系统调用参数:CLONE_NEWNS
隔离内容:网络设备、网络栈、端口等
5. 挂载Mount mnt
类似chroot,将一个进程放到一个特定的目录执行。mnt名字空间允许不同名字空间的进程看到的文件结 构不同,这样每个名字空间中的进程所看到的文件目录就被隔离开了。同chroot不同,每个名字空间中的 容器在 /proc/mounts的信息只包含所在名字空间的 mount point
系统调用参数:CLONE_NEWNS
隔离内容:挂载点(文件系统)
6. 用户id user
同进程 ID 一样,用户 ID 和组 ID 在命名空间内外是不一样的,并且在不同命名空间内可以存在相同的 ID
系统调用参数:CLONE_NEWUSER
隔离内容:用户和用户组
7. 小结:
简单的讲,利用Namespace可以实现我们想要的资源隔离,控制哪些资源可以使用。
三、 控制组CGroup
CGroup 是 Control Groups 的缩写,是 Linux 内核提供的一种可以限制、记录、隔离进程组 (process groups) 所使用的物理资源 (如 cpu memory i/o 等等) 的机制。2007 年进入 Linux 2.6.24 内核,CGroups 不是全新创造的,它将进程管理从 cpuset 中剥离出来,作者是 Google 的 Paul Menage。CGroups 也是 LXC 为实现虚拟化所使用的资源管理手段。 CGroup 是将任意进程进行分组化管理的 Linux 内核功能。CGroup 本身是提供将进程进行分组化管理的功能和接口的基础结构,I/O 或内存的分配控制等具体的资源管理功能是通过这个功能来实现的。这些具体的资源管理功能称为 CGroup 子系统或控制器。CGroup 子系统有控制内存的 Memory 控制器、控制进程调度的 CPU 控制器等。运行中的内核可以使用的 Cgroup 子系统由/proc/cgroup 来确认。
CGroup的主要功能:
1. 资源限制,可以将组设置为不超过配置的内存限制,其中还包括文件系统缓存[8] [9]
2. 优先次序,一些组可能会在CPU利用率或磁盘I / O吞吐量中获得更大份额。
3. 会计,衡量组的资源使用情况,例如可用于计费目的
4. 控制,冻结进程组,记录检查点并重新启动
CGroup常见的子系统包括:
1. blkio 对块设备(比如硬盘)的IO进行访问限制
2. cpu 设置进程的CPU调度的策略,比如CPU时间片的分配
3. memory 用于控制cgroup中进程的占用以及生成内存占用报告
4. net_cls 使用等级识别符(classid)标记网络数据包,这让 Linux 流量控制器 tc (traffic controller) 可以识别来自特定 cgroup 的包并做限流或监控
5. net_prio 设置cgroup中进程产生的网络流量的优先级
6. hugetlb 限制使用的内存页数量
7. pids 限制任务的数量
8. ns 可以使不同cgroups下面的进程使用不同的namespace.
小结:
1. 每个subsystem(子系统)会关联到定义的cgroup上,并对这个cgroup中的进程做相应的限制和控制. 简单的讲,利用CGroup,可以控制能使用的资源的量。
2. 有了Namespace和CGroup这两个特性,容器做到了控制资源隔离和访问的量。但是我们还是需要方便的管理功能和接口,Docker在容器的基本功能的基础上提供了出色的管理功能和接口,成为了容器领域里的事实标准,我们一般说容器,默认的是用Docker的技术。
四、 Docker
Docker 是一个开放源代码软件,是一个开放平台,用于开发应用、交付应用、运行应用。 容器是将操作系统层虚拟化,虚拟机则是虚拟化硬件
Docker的主要特性有:
1. 分层容器
Docker使用AUFS / devicemapper / btrfs使用文件系统的只读层来构建容器。容器由只读层组成,这些只读层在提交后将成为容器映像。镜像是一个包含用于构建应用程序的图层的容器。当docker容器运行时,只有顶层是可读写的,下面的所有层都是只读的,顶层是临时数据,直到将其提交到新层为止。使用只读文件系统的覆盖层会带来固有的复杂性和性能损失。
2. 单一应用容器
Docker将容器限制为仅一个进程。默认的docker baseimage OS模板并非旨在支持多个应用程序,进程或服务,如init,cron,syslog,ssh等。您可以想象这会引入一定的复杂性,并且对日常使用场景具有巨大的影响。由于当前的体系结构,应用程序和服务旨在在正常的多进程OS环境中运行,因此您需要找到一种Docker方式来做事或使用支持Docker的工具。对于LAMP容器的应用程序,需要构建3个相互使用服务的容器,一个PHP容器,一个Apache容器和一个MySQL容器。能在一个容器中建造所有3个容器吗?可以,但无法在同一容器中运行php-fpm,apache和mysqld,也无法安装单独的进程管理器(如runit或supervisor)。
3. 状态分离
Docker将容器存储与应用程序分开,可以在数据卷容器中将持久性数据安装在主机中的容器外部。除非用例只是具有非持久性数据的容器,否则有可能使Docker容器的可移植性降低。这也是容器编排更容易支持无状态应用的根本原因。
4. 镜像注册
Docker提供了一个公共和私有镜像注册,用户可以在其中推送和提取镜像。镜像用于组成应用程序的只读层。这使用户可以轻松共享和分发应用程序。
五、 ContainerD
Containerd是行业标准的容器运行时,重点是简单性,健壮性和可移植性。containerd可用作Linux和Windows的守护程序。它管理着主机系统的容器的整个生命周期,从镜像传输和存储到容器执行和监督,再到低级存储再到网络附件等等。containerd旨在嵌入到更大的系统中,而不是由开发人员或最终用户直接使用。
containerD是用Go语言构建的,有兴趣的可以去看它的代码: https://github.com/containerd/containerd
六、 RunC
RunC是一个轻量级的工具,它是用来运行容器的,只用来做这一件事,并且这一件事要做好。我们可以认为它就是个命令行小工具,可以不用通过 docker 引擎,直接运行容器。事实上,runC 是标准化的产物,它根据 OCI 标准来创建和运行容器。而 OCI(Open Container Initiative)组织,旨在围绕容器格式和运行时制定一个开放的工业化标准。
不同的容器技术是如何使用RunC的
Docker/Podman/CRI-O都使用了RunC。那么我们看看除了Docker,现在还有哪些容器的运行时呢?请看下一节
七、 CRI-O
CRI-O是Kubernetes的轻量级容器运行时,这就是CRI-O提供的。该名称源于CRI(Container Runtime Interface)加开放容器倡议(OCI open container initiative ),因为CRI-O严格关注符合OCI的运行时和容器映像。CRI-O的范围是与Kubernetes一起使用,以管理和运行OCI容器。尽管该项目确实具有一些用于故障排除的面向用户的工具,但它并不是面向开发人员的工具。
八、 Podman
Podman管理容器使用传统的fork / exec模型,因此容器进程是Podman进程的后代。Docker使用客户端/服务器模型。执行的docker命令是Docker客户端工具,它通过客户端/服务器操作与Docker守护进程通信。然后,Docker守护程序创建容器并处理stdin / stdout与Docker客户端工具的通信。Podman可以运行于非root用户模式下,而docker的守护进程必须用root用户启动。Podman的模型被认为是更为安全的模型。同时因为唯有守护进程,你的系统看上去也更为干净。 当然Podman的问题是它还很新,管理工具和功能都很弱,你可能需要buildah来构建镜像,社区和生态都还很小。如果你想用Podman取代Docker,请谨慎操作。
Podman是一个无守护进程的容器引擎,用于在Linux系统上开发,管理和运行OCI容器。容器可以以root用户或普通用户的模式运行。
九、 LXC/LXD
LXC是一个系统容器运行时,旨在执行“完整的系统容器”,通常由完整的操作系统映像组成。在最常见的用例中,LXC进程将引导完整的Linux发行版,如Debian,Fedora,Arch等,并且用户将与虚拟机映像进行交互。LXC也可以用于运行(但不下载)应用程序容器,但是这种用法需要对底层操作系统的详细信息有更多的了解,并且这种做法不太常见。LXC可以从各种公共镜像下载“完整系统容器”映像,并以密码方式对其进行验证。LXC没有中央守护程序,可以与instart系统(例如upstart和systemd)集成。 LXC是一种容器技术,可为您提供轻量级Linux容器,而Docker是基于容器的单个应用程序虚拟化引擎。它们听起来可能相似,但完全不同。与LXC容器不同,Docker容器的行为不像轻量级VM,因此不能被视为轻量级VM。Docker容器在设计上仅限于单个应用程序。你可以登录到LXC容器,将其像OS一样对待,然后安装您的应用程序和服务,它将按预期运行。您无法在Docker容器中做到这一点。Docker基础OS模板被简化为单个应用程序环境,并且没有适当的初始化或支持诸如服务,守护程序,syslog,cron或运行多个应用程序之类的东西。
LXC是Linux内核容器功能的用户空间接口。通过功能强大的API和简单的工具,它使Linux用户可以轻松地创建和管理系统或应用程序容器。
LXD与LXC相似,但它是liblxc之上的REST API,它派生了一个监视器和容器进程。这样可以确保LXD守护程序不是故障的中心点,并且在LXD守护程序发生故障的情况下容器可以继续运行。所有其他细节与LXC几乎相同。简单的说LXD = LXC + RestAPI
Docker 和 LXD/LXC 区别
LXD/LXC是一个系统容器。Docker是一个应用程序容器,
LXC不能跨机器上进行移植,而Docker可以跨机器甚至跨平台移植。
当然还有其它区别,比如标准化的API等,就不多赘述了。
阅读前须知:克隆后可删除
本人持续更新包括但不限于计算机类知识框架
如果您觉得脉络清晰、减少了学习成本
不妨动动小手,点个
关注
克隆后您将在导图中获得:
学习链接
摘自CSDN、CNblog、StackOverFlow等权威论坛, 省去您的搜索整理时间
详细备注
即摘要, 方便您理解概念、类比相似条目、延伸拓展
导图结构近似最科学的笔记方法 ——康奈尔笔记法
1. 笔记栏:
Record(记录):
搜集过滤信息、整理归纳信息。
2. 问题/线索栏:
Reduce(简化):
简化提炼重点。
Recite(复述):
只用简化信息,尽量完整的复述出来。
3. 总结栏:
Reflect(反思):
将自己的听课随感、意见、经验体会之类的内容,与知识内容区分开,写在卡片或笔记本的某一单独部分,加上标题和索引,编制成提纲、摘要,分成类目。
Review(复习):
这样一则以康乃尔笔记法写成的笔记,可以让我们事后回顾与查找资料时更容易找到重点,但也同时能找到细节资料。
上述蓝底黑字部分我已经帮您处理完毕, 如何使用知识就请您大显身手吧!
图例