零基础+全方位带你学习探索Docker容器开发实战指南(底层实现系列)
- Docker简介
- 对比虚拟化技术的优势
- 底层特性
- Linux Container(LXC)
- 底层实现
- 隔离性 Linux namespace
- pid namespace(隔离空间机制)
- net namespace(隔离空间机制)
- ipc namespace(隔离空间机制)
- mnt namespace(隔离空间机制)
- uts namespace(隔离空间机制)
- user namespace(隔离空间机制)
- 控制组 cgroups
- cgroups的资源控制和管理
- 内容总结和分析
- 参考资料
Docker简介
Docker是一个开源的容器引擎,它可以帮助我们更快地交付应用。Docker可将应用程序和基础设施层隔离,并且能将基础设施当作程序一样进行管理。使用Docker,可更快地打包、测试以及部署应用程序,并可减少从编写到部署运行代码的周期。
对比虚拟化技术的优势
a) 不需要指令级模拟:LXC不需要对指令进行模拟或翻译,因为它直接在宿主操作系统的内核上运行,与宿主操作系统共享内核。这消除了指令级模拟的开销,提高了性能。
b) 不需要即时编译:LXC不需要进行即时编译(Just-in-time compilation),因为它直接在宿主操作系统的内核上运行。这减少了编译和优化的开销,提高了响应时间。
c) 容器可以在CPU核心的本地运行指令:LXC容器可以直接在CPU核心上本地运行指令,而无需任何专门的解释机制。这减少了额外的解释和转换开销,提高了性能。
d) 避免了准虚拟化和系统调用替换的复杂性:相比准虚拟化和系统调用替换等虚拟化技术,LXC更加简单和轻量级。它不需要进行复杂的虚拟化处理和系统调用的替换,减少了复杂性和性能开销。
底层特性
Docker的核心是一种操作系统级虚拟化方法,尽管与虚拟机(VM)相比,对其理解可能没有那么直观。然而,我们可以通过以下四个方面来更好地理解Docker的虚拟化方法:
-
隔离性:Docker利用Namespace提供了强大的隔离性,使得不同的Docker容器之间具有独立的命名空间。这意味着每个容器都可以拥有自己的进程树、网络接口、文件系统等,从而实现了隔离的运行环境。
-
可配额/可度量:通过使用Cgroups(控制组)技术,Docker可以对容器的资源进行限制和管理。这意味着可以为每个容器分配特定的CPU、内存、磁盘等资源。同时,可以通过监控和度量这些资源的使用情况,以进行性能优化和资源分配。
-
便携性:Docker使用AUFS(Advanced Multi-Layered Unification File System)等技术,实现了容器的便携性。通过将应用程序和其依赖项封装在一个可移植的容器中,可以将这个容器从一个环境快速部署到另一个环境,而无需担心依赖关系或配置问题。
-
安全性:Docker提供了多种安全性机制,如AppArmor、SELinux和GRSEC。这些机制可以帮助限制容器的权限和访问,从而确保容器之间的安全隔离,并防止恶意行为对整个系统的影响。
通过对这些技术细节的深入了解,我们可以更好地掌握Docker的核心概念和工作原理。
Linux Container(LXC)
Linux容器(Linux Containers)提供了一种轻量级的虚拟化技术,用于隔离进程和资源,而无需提供指令解释机制或其他复杂性的全虚拟化。容器有效地将由单个操作系统管理的资源划分到孤立的组中,以更好地平衡有冲突的资源使用需求。
LXC(Linux Containers)是建立在CGroup、Namespace、Chroot、veth和用户态控制脚本等技术基础上的容器化解决方案。它利用内核的新特性(如CGroup)提供用户空间的对象,用于保证资源的隔离和对应用程序或系统的资源控制。
通过使用LXC,可以创建和管理轻量级的容器,每个容器都具有自己独立的文件系统、进程空间和网络接口。容器之间相互隔离,可以运行不同的应用程序或服务,而不会相互干扰。同时,LXC还提供了一套用户态控制脚本,用于方便地管理和操作容器。
总而言之,Linux容器提供了一种轻量级的虚拟化技术,通过利用CGroup、Namespace、Chroot、veth和用户态控制脚本等技术,实现了资源的隔离和控制。LXC作为一种容器化解决方案,为用户提供了创建和管理容器的能力,实现了应用程序和服务的隔离运行。
底层实现
Docker底层的核心技术包括Linux上的命名空间(Namespaces)、控制组(Control groups)、联合文件系统(Union file systems)和容器格式(Container format),Docker底层的核心技术包括以下几项:
-
命名空间(Namespaces):它在Linux操作系统上实现了进程隔离,使每个容器都有独立的运行环境,而不会相互干扰。
-
控制组(Control groups):通过控制组,可以对容器中的资源(如CPU、内存、磁盘IO等)进行限制和管理,确保容器之间资源的合理分配和隔离。
-
联合文件系统(Union file systems):它允许将多个文件系统以层的形式叠加在一起,形成一个完整的文件系统视图。这样,在容器中的文件系统变更会被记录为增量的方式,从而实现文件的共享和节约存储空间。
-
容器格式(Container format):容器格式定义了容器的结构和元数据,包括容器的配置信息、依赖关系等。它使得容器可以在不同的Docker平台上进行交互和移植。
传统的虚拟机采用了一种不同的方式来实现虚拟化。通过在宿主机上运行一个专门的软件层,即Hypervisor(虚拟机监控程序),来模拟一个完整的硬件环境,为虚拟机的操作系统提供运行环境。虚拟机系统看到的环境是相互隔离的,虚拟机和宿主机之间无法直接共享资源。这样的方法在资源封装方面非常完整,但会导致系统资源的浪费。
相比之下,Docker利用Linux的命名空间和控制组等特性,实现了更轻量级的容器化。在容器中,每个进程都有自己独立的命名空间,使其在容器内运行时,只能看到限定的资源,并与宿主主机和其他容器隔离。这种方式不仅节省了资源,还提高了系统的效率和可伸缩性。通过容器,开发人员可以更灵活地部署和管理应用程序,提高开发和运维的效率。
隔离性 Linux namespace
每个用户实例之间相互隔离,互不影响。一般的硬件虚拟化方法通常使用虚拟机(VM),而LXC使用容器(container),更为具体地说是内核命名空间(kernel namespace)。其中包括pid、net、ipc、mnt、uts、user等命名空间,将容器的进程、网络、消息、文件系统、UTS(UNIX Time-sharing System)以及用户空间互相隔离开来。
容器化技术通过利用内核的命名空间机制,将每个容器的进程及相关资源隔离开来,从而实现对容器之间的隔离和互不影响。
- pid命名空间:确保了每个容器只能看到自己内部的进程ID,并与其他容器的进程ID彼此隔离;
- net命名空间:隔离了每个容器的网络栈,使其具有独立的网络环境;
- ipc命名空间:隔离了容器间的进程间通信;
- mnt命名空间:使容器拥有独立的文件系统视图;
- uts命名空间:用于隔离容器的主机名和域名;
- user命名空间:隔离用户和组ID,确保容器内的用户与宿主机上的用户不会发生冲突。
通过这些命名空间的隔离,容器可以在相互独立的环境中运行,使得它们能够高效地共享主机上的资源,避免资源浪费,并提供更高的系统效率和可伸缩性。
pid namespace(隔离空间机制)
在容器技术中,不同用户的进程是通过pid命名空间隔离开的,这意味着不同命名空间中的进程可以拥有相同的pid。在LXC中,所有的进程都有一个共同的父进程,即docker进程,而每个LXC进程都会被分配到不同的命名空间中。此外,由于允许嵌套使用,容器中还可以方便地实现Docker in Docker。
通过使用pid命名空间来隔离不同用户的进程,每个用户的进程都具有独立的进程ID,并且它们在命名空间之间是隔离的。同时,由于容器技术允许嵌套使用,这使得可以在一个容器中运行另一个容器,从而实现了Docker in Docker的场景。
在Docker中,所有LXC进程都以docker进程为父进程,但它们分别存在于不同的命名空间中,以实现相互隔离。通过这种方式,可以将不同的用户或应用程序的进程隔离开来,确保它们互不干扰。
这种进程隔离的方式使得容器技术具有很高的灵活性和安全性。通过在容器中创建独立的命名空间,可以保证每个用户或应用程序在容器内部都拥有自己独立的进程环境,这样可以提高系统的可靠性和安全性,同时也提供了更便捷的部署和管理方式。
net namespace(隔离空间机制)
net namespace是Linux内核提供的一种机制,用于实现进程间的网络隔离。通过结合pid namespace和net namespace,每个namespace中的进程和网络资源可以相互隔离。然而,目前网络端口仍然是共享的,因此需要采用其他方法来实现网络隔离。
为了解决这个问题,Docker默认采用veth方式,将容器中的虚拟网卡与主机上的docker bridge(docker0)连接起来。这样,每个容器的网络就能够实现隔离。此外,net namespace还提供了独立的网络设备、IP地址、IP路由表和/proc/net目录,进一步增强了网络隔离的效果。
通过net namespace,我们可以实现容器之间的网络隔离,使得每个容器拥有独立的网络环境。这对于构建安全可靠的容器化应用非常重要。
ipc namespace(隔离空间机制)
在容器中,进程之间的交互仍然使用常见的Linux进程间通信方法,如信号量、消息队列和共享内存。然而,与虚拟机不同的是,容器中的进程间通信实际上是在具有相同pid namespace的主机上进行的。因此,在申请IPC资源时,需要加入namespace信息,以确保每个IPC资源都具有唯一的32位ID。
mnt namespace(隔离空间机制)
mnt namespace类似于chroot,它可以将一个进程限制在特定的目录中执行。通过使用mnt namespace,不同namespace的进程可以看到不同的文件结构,从而实现了文件目录的隔离。与chroot不同的是,每个namespace中的容器在/proc/mounts中只包含其所在namespace的挂载点信息。为了优化这段内容,可以进行如下修改:
mnt namespace类似于chroot,它可以将一个进程限制在特定的目录中执行。通过使用mnt namespace,不同namespace的进程可以看到不同的文件结构,从而实现了文件目录的隔离。与chroot不同的是,每个namespace中的容器在/proc/mounts中只包含其所在namespace的挂载点信息。这种隔离机制使得每个namespace中的进程所看到的文件目录被有效地隔离开来。
uts namespace(隔离空间机制)
uts namespace允许每个容器拥有独立的主机名和域名,使其在网络上被视为一个独立的节点,而不仅仅是主机上的一个进程。
user namespace(隔离空间机制)
user namespace允许每个容器拥有不同的用户和组ID,这意味着可以在容器内部使用容器内部的用户来执行程序,而不是使用主机上的用户。
控制组 cgroups
Cgroups是Linux内核提供的一种资源管理机制,用于限制、记录和隔离进程组(process groups)所使用的物理资源,如CPU、内存、IO等。它的全称是control groups,最初由Google的工程师提出,并被整合进Linux内核。
控制组(cgroups)是 Linux 内核的一个重要特性,旨在实现对共享资源的隔离、限制和审计。通过控制组,我们能够有效地管理容器所分配到的资源,从而避免多个容器同时运行时对系统资源的竞争。
Cgroups在虚拟化技术中扮演着重要的角色。例如,LXC(Linux Containers)和Docker等容器化技术就是基于Cgroups来实现资源管理和隔离的。Cgroups为容器提供了资源限制和隔离的能力,使得容器可以在共享的物理资源上运行,而不会相互干扰。
cgroups的资源控制和管理
Cgroups最初的目标是为资源管理提供一个统一的框架,整合现有的子系统并为未来开发新的子系统提供接口。现在的Cgroups适用于多种应用场景,从单个进程的资源控制到操作系统层次的虚拟化。
-
a) 限制进程组的资源使用:通过Cgroups,可以为进程组设置资源使用上限,如内存使用上限。一旦进程组使用的资源达到限额,再申请资源就会触发OOM(out of memory)。
-
b) 进程组的优先级控制:通过Cgroups的CPU子系统,可以为进程组分配特定的CPU份额,实现优先级控制。
-
c) 进程组的隔离:使用Cgroups的ns子系统,可以为不同的进程组分配不同的namespace,实现进程、网络、文件系统挂载空间的隔离。
-
d) 记录进程组的资源使用情况:通过Cgroups的Cpuacct子系统,可以记录进程组使用的CPU时间,实现资源使用的统计和监控。
-
e) 进程组的控制:使用Cgroups的freezer子系统,可以将进程组挂起和恢复,实现对进程组的控制。
Cgroups提供了一种灵活的方式来管理和控制进程组的资源使用。通过将进程组分组并分配资源限制,可以确保不同进程组之间的资源互不干扰,从而实现资源的隔离和管理。
内容总结和分析
LXC负责资源管理,AUFS负责镜像管理。LXC是一个容器化解决方案,它包括了cgroup、namespace、chroot等组件,并通过cgroup进行资源管理。
从资源管理的角度来看,Docker、LXC和Cgroup之间的关系可以描述为:
-
Cgroup在最底层落实资源管理:Cgroup(Control Groups)是Linux内核提供的一种资源管理机制,用于限制、记录和隔离进程组所使用的物理资源。它在最底层实现了资源管理,通过对进程组进行分组和分配资源限制,确保不同进程组之间的资源互不干扰。
-
LXC在cgroup上封装了一层:LXC是建立在Cgroup、namespace、chroot等技术基础上的容器化解决方案。它利用Cgroup提供的资源管理能力,通过namespace实现进程隔离,使用chroot实现文件系统隔离等。LXC在Cgroup的基础上封装了一层,提供了更高级别的容器管理功能。
-
Docker在LXC封装了一层:Docker是基于LXC的容器化平台,它在LXC的基础上进行了封装和扩展。Docker提供了更高级别的容器管理和部署功能,通过Docker镜像和容器的概念,简化了应用程序的打包、分发和部署过程。
参考资料
- Docker官方网站:https://www.docker.com/
- Docker GitHub:https://github.com/docker/docker
- LXC官网:(http://linuxcontainers.org/)