什么是容器技术
容器技术也被称为容器虚拟化。是虚拟化技术中的一种。
虚拟化技术主要包括硬件虚拟化,半虚拟化和操作系统虚拟化。容器虚拟化是操作系统虚拟化的一种,是轻量级的虚拟化技术。
虚拟化技术分类
容器技术的核心特性
Cgroups
(1) Cgroups 是什么?
control groups, 是Linux内核提供的一种可以限制、记录、隔离进程组所使用的物理资源的机制。
(2) Cgroups的三个组件
-
cgroup 是对进程分组管理的一种基址,一个cgroup包含一组进程,并可以在这个cgroup上增加Linux subsystem 的各种参数配置,将一组进程和一组子系统的系统参数关联起来。
-
Cgroups 实现了一个通用的进程分组框架,不同资源的具体管理则是由不同的子系统管理。一个子系统就是一个资源控制器
- devices: 设备权限控制
- cpuset: 分配指定的CPU和内存节点
- cpu: 控制CPU占用率
- cpuacct: 统计CPU使用情况
- memory: 限制内存的使用上限
- freezer: 暂停Cgroup中的进程
- net_cls: 配合tc(流量控制程序)限制网络带宽。
- net_prio: 设置进程的网络优先级
- huge_tlb: 限制HugeTLB的使用
- perf_event: 允许Perf工具基于Cgroup分组做性能检测
- blkio: 块设备设定输入、输出限制
- ns: 名称空间子系统
-
层级结构(hierarchy)
层级结构的功能是把一组cgroup串成一个树状的结构,一个这样的树便是一个层级结构,通过这种树状结构,Cgroups 可以做到继承。
比如,系统对一组定 时的任务进程通过 cgroupl 限制了 CPU 的使用率,然后其中有一个定时 dump 日志的进程还需要限制磁盘 IO,为了避免限制了磁盘 IO 之后影响到其他进程,就可以创建 cgroup2 ,使其继承于 cgroupl 井限制磁盘的 IO,这样 cgroup2 便继承了 cgroupl 中对 CPU 使用率的限制,并且增加了磁盘 IO 的限制而不影响到 cgroupl 中的其他进程。
(3) 三个组件的关系
- 系统在创建了新的层级结构之后,系统中所有的进程都会加入这个层级结构的cgroup根节点,这个cgroup根节点是这个层级结构默认创建的, 在这个层级结构中创建的cgroup都是这个cgroup根节点的子节点
- 一个subsystem只能附加到一个层级结构上面
- 一个层级结构可以附加多个subsystem
- 一个进程可以作为多个cgroup的成员,但这些cgroup必须在不同的层级结构中
- 一个进程fork出子进程时,子进程是和父进程在同一个cgroup中的,也可以根据需要将其移动到其他cgroup中。
Namespace
Namespace 是将内核的全局资源做封装,使得每个Namespace都有一份独立的资源,因此不同的进程在各自的Namespace内对一种资源的使用不会相互干扰。
目前Linux实现了6中不同类型的Namespace。
Namespace 类型 | 系统调用参数 | 内核版本 |
---|---|---|
Mount Namespace | CLONE_NEWNS | 2.4.19 |
UTS Namespace | CLONE_NEWUTS | 2.6.19 |
IPC Namespace | CLONE_NEWIPC | 2.6.19 |
PID Namespace | CLONE_NEWPID | 2.6.24 |
Network Namespace | CLONE_NEWNET | 2.6.29 |
User Namespace | CLONE_NEWUSER | 3.8 |
Namespace 的API主要使用如下3和系统调用
- clone() 创建新进程。
- unshare() 将进程移出某个Namespace。
- setns() 将进程加入到 Namespace 中。
1.UTS Namespace
UTS Namespace由于对主机名和域名进行隔离,也就是uname系统调用使用的结构体 struct utsname里面的nodename 和 domainname这两个字段,UTS这个名字也是由此而来的。
那么,为什么要使用UTS Namespace做隔离?这是因为主机名可以用来代替IP地址。因此,也就是可以使用主机名在网络上访问某台机器,如果不做隔离,这个机制在容器里就会出现。
2.IPC Namespace
IPC --进程间通信。Linux提供了很多种进程间通信的机制,IPC Namespace针对的System V IPC 和Posix 消息队列
IPC Namespace 能做到的事情是,是相同的标识符在两个Namespace中代表不同的消息队列,这样也就使得两个Namespace中的进程不能通过IPC进程通信了。
3.PID namespace
用于隔离进程PID号,不同的namespace里的进程PID号就可以是一样的了。
当创建一个PID namespace时,第一个进程的PID号是1,也就是init进程。init进程需要负责回收所有的孤儿进程的资源。另外,发送给init进程的任何信号都会被屏蔽,即使发送的是SIGKILL信号。也就是在容器内无法杀死 “init” 进程
当时当用ps命令查看系统的进程时,会发现竟然可以看到host的所有进程。
因为ps命令是从procfs读取信息的,而procfs并没有得到隔离,虽然能看到这些进程,但由于他们其实是在另一个PID Namespace中,因此无法向这些进程发送信号。
4.Mount Namespace
用来隔离文件系统挂载点,每个进程能看到的文件系统都在/proc/$$/mounts里。在创建一个新的Mount Namespace后,进程系统对文件系统挂载 / 卸载的动作就不会影响到其他Namespace。
5.Network Namespace
这个Namespace会对网络相关的系统资源进行隔离,每个Network Namespace都有自己的网络设备、ip地址、路由表、/proc/net 目录、端口号等。
6.User Namespace
User Namespace 用来隔离用户和组ID,也就是说一个进程在Namespace里的用户和组ID与它在host里的ID可以不一样。比如host的普通用户进程在容器里可以使0号用户(root)。这样在容器内可以做各种特权操作,但是它的特权被限制在容器内,离开了这个容器,它就是普通用户。