容器基础

**容器(Container)**是一个具有特殊属性的任务或任务集合,用于隔离任务并限制对系统资源的访问。

container

进程描述符和任务结构

内核将进程列表存储在一个称为**任务列表(task list)**的循环双向链表中。

task-list

任务列表中的每个元素都是struct task_struct类型的进程描述符。进程描述符包含特定进程的所有信息。

task-struct

/proc

proc

/proc是一个特殊的文件系统挂载(procfs),通过读取"文件"条目直接从内核访问系统和进程信息。

task-struct-example

属性

凭证(Credentials)

凭证(Credentials)是进程标识符。凭证描述任务的用户身份,该身份确定其对共享资源(如文件、信号量和共享内存)的权限。

任务的所有凭证都保存在一个名为struct cred的引用计数结构中。每个任务通过其task_struct中的cred指针指向其凭证。

传统UNIX权限实现区分两类:

  • 用户ID为0(root)的特权进程

  • 所有其他进程

权能(Capabilities)

从内核2.2开始,Linux将与超级用户关联的权限分解为称为权能(Capabilities)的不同单元。

Linux权能的引入是为了将root的角色分解为离散的子部分,这些子部分可以授予非root进程,使其能够执行特权操作。

capabilities

进程具有权能"允许集合"的概念,该集合充当其可能拥有的权能的限制性超集。重要的是,默认情况下,这个边界集合会传递给任何子进程,因此容器的"init"进程为容器内的所有进程创建了一个限制性权能集合(因为所有进程都从PID 1派生)。

容器是应该以受限权能集合运行的任务。

restricted-capabilities

要查看权能列表,可以使用capsh

$ capsh --print

文件系统

容器的文件系统根目录通常通过pivot_root系统调用与其他容器和主机的根文件系统隔离。

容器的根挂载通常植根于容器专用文件系统,如AUFS或OverlayFS。在OverlayFS的情况下,容器的/根目录实际上位于/var/lib/docker/overlay2中。

overlayfs-root-path

命名空间(Namespaces)

命名空间(Namespace)将全局系统资源包装在抽象中,使得命名空间内的进程看起来拥有自己的全局资源隔离实例。对全局资源的更改对命名空间的其他成员进程可见,但对其他进程不可见。

Linux上有8种类型的命名空间。

命名空间
隔离内容

Cgroup

Cgroup根目录

IPC

提供SystemV IPC和POSIX消息队列的命名空间版本

Network

提供命名空间和隔离的网络栈。大多数容器用例涉及网络服务,因此这将成为容器的核心功能

Mount

提供挂载点的命名空间视图。结合pivot_root()系统调用,这将用于隔离容器的文件系统与主机的文件系统

PID

提供进程ID(PID)的命名空间树。这允许每个容器拥有完整的隔离进程树,其中它有一个'init'进程,在该命名空间内作为PID 1运行。在容器中运行的进程在主机上的PID与在容器PID命名空间内的PID不同

Time

启动和单调时钟

User

提供用户ID(UID)和组ID(GID)的命名空间版本。这是现代容器系统最重要的功能之一,因为它用于提供"非特权容器"。这些容器中,容器内的root(UID 0)在容器外部不是root,大大提高了容器的安全性

UTS

提供系统标识符的命名空间版本

namespace-user-example

在大多数情况下,使用clone(2)unshare(2)创建新命名空间需要CAP_SYS_ADMIN权能。用户命名空间是例外:从Linux 3.8开始,创建用户命名空间不需要特权。

每个进程都有一个/proc/[pid]/ns/子目录,为每个命名空间包含一个条目。

参考资料:

Cgroups

Cgroups是Linux控制组。

控制组(通常称为cgroups)是一个Linux内核功能,允许将进程组织到层次组中,然后可以限制和监控这些组对各种类型资源的使用。内核的cgroup接口通过称为cgroupfs的伪文件系统提供,其中层次结构通过每个挂载中的目录树表达。

cgroupfs

分组在核心cgroup内核代码中实现,而资源跟踪和限制在一组按资源类型的子系统(内存、CPU等)中实现。

cgroup文件系统最初包含一个根cgroup /,所有进程都属于它。通过在cgroup文件系统中创建目录来创建新的cgroup。

$ mkdir /sys/fs/cgroup/cpu/cg1

这创建了一个新的空cgroup。可以通过将其PID写入cgroup的cgroup.procs文件将进程移动到此cgroup:

$ echo $$ > /sys/fs/cgroup/cpu/cg1/cgroup.procs

Linux安全模块

AppArmorSELinux是Linux安全模块,提供强制访问控制(MAC),其中程序的访问规则由配置文件描述。

Docker和LXC在强制模式下启用默认的LSM配置文件,主要用于限制容器对敏感的/proc/sys条目的访问。

该配置文件还拒绝mount系统调用。

seccomp

从内核3.17开始,Linux有一种通过seccomp子系统过滤系统调用访问的机制。

seccomp

Seccomp策略有两个版本:

  • 严格模式(Strict mode) - 一小部分允许的系统调用,无法自定义

  • 过滤模式(Filter mode) - 系统调用过滤器编写为伯克利数据包过滤器(BPF)程序;这允许对系统调用使用设置更细粒度的策略(有一些注意事项,seccomp-bpf过滤器可以检查系统调用参数,但无法解引用指针)

容器安全模型

container-security-model

参考资料

最后更新于