聊聊容器化的原理

云计算 云原生
有了隔离,子容器之间可以相对独立、互不打扰地工作。每个容器都是为了处理特定工作的,比如有的容器负责提供数据库服务,有的容器负责提供缓存服务,有的容器负责应用系统的运行。如何决定容器创建后做什么工作呢?答案是通过Dockerfile。

容器化

无论LXC还是Docker,底层主要的核心技术是Cgroups、Namespace。Cgroups是Linux内核提供的一种用来限定进程资源使用的技术,可以限制和隔离进程所使用的物理资源,比如CPU、内存、磁盘和网络I/O。相对于物理资源隔离,Namespace则是用来隔离进程ID、网络等系统资源的,类似Java中的类加载器(classloader)。即使是同样的PID、同样的IP,不同的Namespace之间也是相互独立的,毫无影响。比如父容器通过调用clone()函数创建两个子进程,ID分别为100、101,这两个子进程拥有自己的Namespace,映射到子进程后,分别对应PID为1的init进程,虽然在两个Namespace里PID都为1,但是有了Namespace的隔离,两者互不影响,如图所示。

图片图片

有了隔离,子容器之间可以相对独立、互不打扰地工作。每个容器都是为了处理特定工作的,比如有的容器负责提供数据库服务,有的容器负责提供缓存服务,有的容器负责应用系统的运行。如何决定容器创建后做什么工作呢?答案是通过Dockerfile。

我们把Dockerfile比作人体的DNA,它记录了容器运行的子进程,进而决定了容器的核心功能。通过Dockerfile我们可以构建镜像,随时拉起多个容器,实现应用的高速扩展。业务应用的镜像本质上都很相似,假设应用A的Dockerfile为DockerfileA,应用B的Dockerfile为DockerfileB,它们都依赖于操作系统、JDK、Tomcat、日志采集器等,只有应用的War包不一样。如果每个镜像都重复维护多个共性的部分,带来的资源损耗和维护成本都是巨大的。

Docker采用分层技术来解决这个问题,每个容器都有自己独立的容器层,不同的容器共享一个镜像层,这样容器之间就可以共享基础资源。我们保存一个基础镜像(通常称作base镜像)到磁盘后,它就可以被其他镜像共享了,如图所示。

图片图片

Dockerfile底层用的核心文件共享技术就是UFS。UFS是一种轻量级、高性能、分层的文件系统。UFS把文件系统的每次修改作为一个个层进行叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。如果一次同时加载多个文件系统,UFS会把各层文件叠加起来,最终文件系统会包含所有底层文件和目录,从外部视角来看,用户看到的是一个文件系统。镜像就是利用UFS的特性,通过分层来进行继承、叠加,通常我们会先制作一个基础镜像,通过基础镜像衍生出各种具体的应用镜像。UFS是Docker镜像的基础。

这段内容涉及到了几个核心的虚拟化和容器化技术,让我们来解释一下

Cgroups(Control Groups)

Cgroups 是 Linux 内核提供的一种资源管理机制,用于限制和隔离进程对系统资源的使用,如 CPU、内存、磁盘和网络带宽等。它允许系统管理员为不同的进程组分配资源,并限制每个组能够使用的资源量。

Cgroups(Control Groups)是 Linux 内核提供的一种资源管理机制,其原理主要涉及以下几个方面

资源隔离

Cgroups 允许管理员将系统中的进程划分为不同的组,并为每个组分配特定的资源限制。这样可以确保每个组内的进程只能使用分配给它们的资源,而不会影响其他组的进程。

资源控制

Cgroups 允许管理员为每个组设置资源限制,包括 CPU、内存、磁盘和网络带宽等。这些限制可以是硬限制(无法超出)或软限制(可以超出一段时间),从而实现对系统资源的精确控制和管理。

层次结构

Cgroups 支持层次结构,允许管理员创建多层次的组织结构。这种层次结构可以使得资源的管理更加灵活,可以根据需要对不同层次的组进行不同程度的资源分配和限制。

控制接口

Cgroups 提供了一组控制接口,允许管理员动态地管理和调整组的资源限制。这些接口可以通过文件系统的方式进行访问和操作,使得资源管理变得简单和灵活。

我们来总结一下,Cgroups 的原理是通过为进程分组和设置资源限制,实现对系统资源的隔离和控制,从而确保系统能够有效地利用资源,提高系统的性能和稳定性。

安全问题

Cgroups 本身并不会引入安全问题,因为它是 Linux 内核提供的一种资源管理机制,旨在帮助管理员对系统资源进行更好地管理和控制。然而,在实际使用过程中,存在一些安全隐患需要注意

资源竞争

如果不合理地配置了 Cgroups,会导致资源竞争问题,即某些组或进程占用了过多的资源,导致其他组或进程无法正常运行。因此,需要合理设置资源限制,避免资源过度分配。

权限问题

Cgroups 的配置和管理涉及到系统的权限管理,如果权限设置不当,会导致未授权的用户获取到对系统资源的控制权限,从而造成安全隐患。因此,需要严格管理和控制对 Cgroups 的访问权限。

DoS 攻击

如果攻击者能够绕过 Cgroups 的限制,恶意占用系统资源,会导致系统资源耗尽,从而影响系统的正常运行。因此,需要及时监控和响应异常行为,防止 DoS(拒绝服务)攻击。

我们来总结一下,Cgroups 本身并不会引入安全问题,但在使用过程中需要注意合理配置和管理,避免出现资源竞争、权限问题和 DoS 攻击等安全隐患。同时,及时更新系统和内核版本,以修复已知的安全漏洞,提高系统的安全性。

Namespace(命名空间)

Namespace 是 Linux 内核提供的一种隔离机制,用于隔离进程的全局资源,如进程 ID(PID)、网络、文件系统、用户等。不同的 Namespace 提供了一种虚拟化的环境,使得在同一主机上运行的进程之间彼此隔离,互不干扰。

Namespace 是 Linux 内核提供的一种隔离机制,用于将系统资源划分为多个独立的、互相隔离的环境。它允许在同一主机上运行的进程看到不同的系统资源,从而实现资源的隔离和虚拟化。Linux 内核提供了多种类型的 Namespace,包括 PID(进程 ID)、Network(网络)、Mount(文件系统挂载点)、IPC(进程间通信)、UTS(主机名和域名)等。以下是 Namespace 的一些主要类型及其作用

PID Namespace

每个 PID Namespace 都有自己的进程 ID 空间,进程在其中的 ID 对于其他 Namespace 是不可见的。这使得在不同的 PID Namespace 中运行的进程之间相互隔离,各自拥有自己的进程树,从而可以更好地管理和控制进程。

Network Namespace

每个 Network Namespace 都有自己的网络栈,包括网络设备、IP 地址、路由表、网络连接等。这使得在不同的 Network Namespace 中运行的进程之间拥有独立的网络环境,可以实现网络的隔离和虚拟化。

Mount Namespace

每个 Mount Namespace 都有自己的文件系统挂载点,使得在不同的 Mount Namespace 中可以拥有不同的文件系统视图。这样可以实现文件系统的隔离,使得不同的进程可以拥有不同的文件系统环境。

IPC Namespace

IPC Namespace 提供了进程间通信机制的隔离,使得在不同的 IPC Namespace 中的进程无法直接通信,从而增强了系统的安全性和隔离性。

UTS Namespace

UTS Namespace 提供了主机名和域名的隔离,使得在不同的 UTS Namespace 中可以拥有不同的主机名和域名,从而实现了系统标识信息的隔离。

这些 Namespace 可以被用来创建容器,实现容器之间的隔离和虚拟化。通过将不同类型的 Namespace 组合在一起,可以实现更加灵活和强大的容器隔离环境,为容器提供了更加安全和可靠的运行环境。

安全问题

Namespace 本身并不具有安全问题,它是 Linux 内核提供的一种资源隔离机制,用于创建隔离的运行环境。然而,在实际使用中,如果配置不当或者存在漏洞,会导致安全问题的产生。以下是一些导致安全问题的情况

提权漏洞

如果容器中运行的进程具有提权漏洞,会导致攻击者获得 root 权限,并从容器中逃逸到宿主主机。

容器逃逸

如果容器本身存在漏洞,攻击者会利用这些漏洞从容器中逃逸,获取宿主主机上的敏感信息或者控制宿主主机。

命名空间隔离不完整

如果命名空间隔离不完整或者存在漏洞,会导致容器之间的信息泄露或者相互影响。

共享命名空间

如果容器共享了某些命名空间,会导致容器之间的信息共享,增加了攻击面。

为了确保容器环境的安全性,需要采取一系列安全措施,包括但不限于

  • 及时更新容器镜像和基础操作系统,修复已知漏洞。
  • 限制容器的权限,使用最小特权原则。
  • 启用安全策略,如 SELinux、AppArmor 等,限制容器的系统调用。
  • 实施网络隔离和安全组策略,限制容器之间的通信。
  • 使用安全审计工具对容器环境进行监控和审计,及时发现异常行为。
  • 使用容器运行时的安全特性,如 Docker 的安全扫描、容器签名等。

我们来总结一下,虽然 Namespace 本身不会引起安全问题,但是在实际使用中需要注意配置和管理,以确保容器环境的安全性。

Dockerfile

Dockerfile 是一个文本文件,用于定义 Docker 镜像的内容和构建步骤。通过 Dockerfile,可以指定基础镜像、容器中运行的命令、文件和目录的添加、环境变量的设置等。使用 Dockerfile 可以轻松地创建自定义的 Docker 镜像,方便地部署和管理应用程序。

分层文件系统(Union File System,UFS)

分层文件系统是一种文件系统技术,允许将多个文件系统挂载到同一个虚拟文件系统中,形成一个层次结构。在 Docker 中,每个容器都有自己的容器层,不同的容器可以共享相同的基础镜像层。这种分层机制可以节省磁盘空间,并提高镜像的重用性和部署效率。

分层文件系统(Union File System,UFS)是一种文件系统技术,通过将多个文件系统层叠加挂载到同一个虚拟文件系统中,形成一个层次结构。在 Docker 中,分层文件系统的概念被广泛应用于容器镜像的构建和管理中。

分层文件系统的主要原理是利用文件系统的层叠加特性,每个文件系统层可以包含文件和目录,并且可以被其他文件系统层叠加在其上。在 Docker 中,每个容器都由多个文件系统层组成,包括只读的基础镜像层和读写的容器层。这些层次结构的组合使得容器可以像构建积木一样,根据需要组装不同的镜像,而无需重复存储相同的文件。

具体来说,分层文件系统的工作原理如下

基础镜像层(Base Image Layer)

基础镜像层包含了容器的基础文件系统,通常包括操作系统的核心文件和系统工具。这一层是只读的,所有容器都共享同一个基础镜像层。基础镜像层通常由 Docker Hub 或私有仓库提供,并由开发者维护和更新。

容器层(Container Layer)

每个容器都有自己的容器层,用于存储容器的特定文件和目录,包括应用程序、配置文件、日志等。容器层是可写的,并且可以根据容器的运行状态进行修改。当容器启动时,容器层会叠加在基础镜像层之上,构成容器的完整文件系统。

写时复制(Copy-on-Write)

当容器对文件系统进行写操作时,分层文件系统采用写时复制(Copy-on-Write)策略。这意味着在写操作发生时,文件系统会在容器层上创建一个新的文件副本,而不是直接修改基础镜像层中的文件。这样可以确保每个容器都拥有自己独立的文件系统,同时最大程度地节省存储空间。

镜像的组装和重用

由于分层文件系统的特性,Docker 镜像可以通过叠加不同的文件系统层来构建。这使得镜像可以像积木一样灵活组装,从而实现镜像的复用和共享。如果多个镜像共享相同的基础镜像层,它们之间只需存储不同的容器层,大大减少了存储空间的消耗。

我们来总结一下,分层文件系统是 Docker 中非常重要的一个概念,它通过利用文件系统的层叠加特性,实现了镜像的高效构建、部署和管理。通过写时复制和镜像的重用,分层文件系统可以节省存储空间,并提高容器的性能和效率。

安全问题

分层文件系统在 Docker 中虽然带来了诸多优势,但也存在一些安全考虑

容器逃逸(Container Escape)

尽管容器之间是通过分层文件系统进行隔离的,但在某些情况下,恶意用户通过利用操作系统或 Docker 引擎的漏洞,从容器中逃逸出来,获取主机系统的权限。这种容器逃逸攻击导致主机系统被入侵或受到破坏。

镜像污染(Image Poisoning)

如果基础镜像层或其他共享层中存在漏洞或恶意代码,那么所有依赖这些镜像构建的容器都受到影响。攻击者可以通过修改或篡改镜像的文件来植入恶意软件或后门,从而危害容器内的应用程序和数据安全。

不安全的基础镜像

如果使用了不安全或未经验证的基础镜像,那么容器构建的整个分层文件系统都受到威胁。建议使用官方或可信赖的基础镜像,并及时更新镜像以修补已知的漏洞和安全问题。

文件系统权限

在容器内部,文件系统的权限通常是由容器运行时的配置和用户设置决定的。如果文件系统权限配置不当,导致容器中的敏感文件被非授权用户访问或修改,从而造成数据泄露或损坏。

为了减轻这些安全风险,建议采取以下措施

  • 使用官方或可信赖的基础镜像,并定期更新以获取最新的安全补丁和修复程序。
  • 实施安全最佳实践,如使用容器运行时的安全配置、限制容器的特权访问、禁止不必要的系统调用等。
  • 配置容器的访问控制策略,限制容器之间的通信和资源访问,确保容器只能访问其需要的最小权限资源。
  • 监控容器的运行状态和行为,及时发现和应对的安全威胁和攻击行为。

我们来总结一下,虽然分层文件系统为容器化应用提供了便利和效率,但在实际应用中仍需注意安全风险,并采取相应的措施加以防范和应对。

这些技术共同构成了容器化技术的核心,使得容器能够实现资源隔离、轻量级和快速部署的特性。

作用关系图

使用Plantuml画三者的作用关系图,如下

@startuml


left to right direction
skinparam packageStyle rectangle
skinparam padding 10
skinparam defaultFontName Helvetica


package "Host" {
    package "Namespace" {
        [Process 1] as Process1
        [Process 2] as Process2
        [Process 3] as Process3
    }


    package "Cgroup" {
        [Cgroup 1] as Cgroup1
        [Cgroup 2] as Cgroup2
        [Cgroup 3] as Cgroup3
    }


    package "UnionFS" {
        [Layer 1] as Layer1
        [Layer 2] as Layer2
        [Layer 3] as Layer3
    }


    Process1 --> Cgroup1
    Process2 --> Cgroup2
    Process3 --> Cgroup3


    Cgroup1 --> Layer1
    Cgroup2 --> Layer2
    Cgroup3 --> Layer3
}


@enduml

图片图片

这个图展示了在主机上的三种关键技术之间的关系:Namespace(命名空间)、Cgroup(控制组)和分层文件系统(UnionFS)。

  • Namespace用于隔离进程的全局资源,如进程ID(PID)、网络、文件系统等。在图中,每个进程(Process)都被分配到自己的Namespace中,以确保它们之间的隔离。
  • Cgroup用于控制和限制进程对系统资源的使用,如CPU、内存等。每个进程都被分配到相应的Cgroup中,以限制其对资源的访问。
  • 分层文件系统(UnionFS)允许将多个文件系统挂载到同一个虚拟文件系统中,形成一个层次结构。每个Cgroup都与一个或多个分层文件系统的层相关联,这些层包含了进程所需的文件系统内容。

总之,Namespace提供了隔离的执行环境,Cgroup控制了资源使用,而分层文件系统则提供了文件系统的层次结构,使得容器可以共享和重用文件系统的内容。


责任编辑:武晓燕 来源: 海燕技术栈
相关推荐

2022-01-05 00:03:32

场景容器Airflow

2020-06-10 08:55:36

Docker容器工具

2020-07-14 07:27:48

容器IoCSpring

2022-03-04 08:45:11

Docker开源Linux

2021-07-14 14:05:24

Fragment项目结构

2020-06-10 08:28:51

Kata容器I

2023-04-28 08:43:46

2023-06-30 07:51:44

springboot初始化逻辑

2021-09-14 13:25:23

容器pod僵尸进程

2022-01-19 08:01:13

Linuxdocker容器

2018-04-24 09:05:09

容器存储接口

2021-11-06 18:40:27

js底层模块

2023-07-03 09:59:00

并发编程并发容器

2023-11-28 07:55:05

Calico容器网络

2022-06-21 07:51:06

Redis高可用哨兵进程

2023-03-27 08:49:51

2022-10-30 15:00:50

2021-07-07 05:00:17

初始化源码

2022-12-11 20:09:50

网络编程通信

2021-04-19 10:45:52

Webpack热更新前端
点赞
收藏

51CTO技术栈公众号