容器
-
基于镜像
镜像image就是附加一个JSON配置文件的tar包。镜像常常是嵌套的,防止重复内容占用空间 -
容器运行时会从某处下载镜像,这个地方称为registry。Registry通常是一个通过HTTP协议暴露镜像的元数据和文件以供下载的容器仓库
-
运行时将层次化的镜像解压到支持Copy on Write(CoW)的文件系统里。通常这通过覆盖(overlay)文件系统来实现,所有的层次层层覆盖来构成一个合并的文件系统。 这个步骤通常不能通过命令行直接访问,而是当运行时创建容器时会自动在后台发生
-
运行时来实际地执行容器。 它告诉内核给容器分配合适的资源限制,创建隔离的层(为进程,网络,文件系统等),使用各种机制的混合(包括cgroups,namespaces,capabilities, seccomp, AppArmor, SELinux,等等),底层实际调用的是runC命令
-
容器引擎常见的就是docker,也可以是其他容器引擎,创建容器就是把磁盘上的容器镜像运行成宿主机的一个进程
Namespace
首先要理解docker本质上是一个运行在宿主机上的一个进程,用于帮助进程隔离出自己单独的空间.
Linux Namespace可以隔离一系列的系统资源,如进程ID,网络资源,用户ID.
Linux现在实现了六种Namespace
-
UTS Namespace
主要用来进行hostname和domain的隔离 -
IPC Namespace
控制了进程兼通信的一些东西,比方说信号量。 -
PID Namespace
用来进行进程ID的隔离,保证了容器的 init 进程是以 1 号进程来启动的。 -
Mount Namespace
用来隔离各个进程看到的挂载点视图
是保证容器看到的文件系统的视图,是容器镜像提供的一个文件系统,也就是说它看不见宿主机上的其他文件
-
User Namespace
隔离用户的用户组ID,一个在宿主机上以非root用户可以在一个User namespace内映射成root用户 -
Network Namespace
网络设备,IP地址,端口的隔离使得每个容器有自己独立的虚拟网络设备.即使不同容器的服务映射到相同的端口,都不会冲突.在宿主机搭建了网桥后,能很方便实现容器之间的通信.并且不同容器之间应用可以使用相同的端口.
Cgroups
Cgroup提供了对一组进程与将来子进程的资源限制,控制和统计的能力.
这些资源包括cpu,内存,存储,网络等.通过Cgroups可以方便限制某个进程的资源使用,并且可以实时进行对进程的监控与统计
两种cgroup驱动
-
systemd
system daemon 的cgroup驱动 -
cgroupfs
要用 CPU share 为多少,直接把 pid 写入对应的一个 cgroup 文件,然后把对应需要限制的资源也写入相应的 memory cgroup 文件和 CPU 的 cgroup 文件就可以了
三个组件
- cgroup
对进程分组管理的一种机制,负责把一组进程和一组subsystem的系统参数关联起来 - subsystem
一组资源控制的模块 - hierarchy
把cgroup串成一个树状的结构
容器常用的cgroup
- cpu
- memory
- device
上面三个好理解 - freezer
停止容器的时候,freezer会把当前进程全部写入cgroup,然后所有进程都冻结掉,目的是防止在停止的时候,有进程会去做fork,这样的话防止进程逃逸到宿主机上去。 - blkio
block io,主要限制磁盘IOPS和bps速率 - pid
限制容器里可以用到的最大进程数量
操作cgroup
- 创建并且挂载一个hierarchy
mkdir cgroup-test
sudo mount -t cgroup -o none,name=cgroup-test cgroup-test ./cgroup-test
ls ./cgroup-test
- 在创建好的hierarchy上cgroup根节点扩展出两个子cgroup,子cgroup会扩展父cgroupd的属性
- 在cgroup中添加和移动进程
一个进程在一个cgroup的hirearchy进程中,只能在一个cgroup节点上存在,只要把该进程ID写入该cgroup节点的tasks文件,就可以把进程移动到这个cgroup节点
sudo sh -c "echo $$ >> tasks"
- 通过subsystem限制cgroup中的进程资源
通过
mount | grep memory
查看哪个目录挂在了memory subsystem的hierarchy上
sudo mkdir test-limit && cd test-limit
sudo sh -c "echo "100m" > memory.limit_in_bytes"
sudo sh -c "echo $$ > tasks"
stress --vm-bytes 200m --vm-keep -m 1
我们可以看到,虽然压测声明占用内存为200m,但实际上cgroup为其限制了内存资源只能使用100m.
下面用go来模拟cgroup限制容器的资源
package main
import (
"fmt"
"io/ioutil"
"os"
"os/exec"
"path"
"strconv"
"syscall"
)
//挂在了memory subsystem的hierarcy目录
const cgroupMemoryHierarchyMount =