Cgroup namespace

| 分类 Linux  | 标签 cgroup  namespace 

简介

内核从4.6开始,支持cgroup namespace。在这之前,在一个容器查看/proc/$PID/cgroup,或者在容器挂载cgroup时,会看到整个系统的cgroup信息:

# docker run -it --rm busybox /bin/sh
/ # cat /proc/self/cgroup 
8:blkio:/docker/a33bb329884b34cfbea83cdcdac8292976c1e2ed40b9089eb6cf4f257c464560
7:net_cls:/docker/a33bb329884b34cfbea83cdcdac8292976c1e2ed40b9089eb6cf4f257c464560
6:freezer:/docker/a33bb329884b34cfbea83cdcdac8292976c1e2ed40b9089eb6cf4f257c464560
5:devices:/docker/a33bb329884b34cfbea83cdcdac8292976c1e2ed40b9089eb6cf4f257c464560
4:memory:/docker/a33bb329884b34cfbea83cdcdac8292976c1e2ed40b9089eb6cf4f257c464560
3:cpuacct:/docker/a33bb329884b34cfbea83cdcdac8292976c1e2ed40b9089eb6cf4f257c464560
2:cpu:/docker/a33bb329884b34cfbea83cdcdac8292976c1e2ed40b9089eb6cf4f257c464560
1:cpuset:/docker/a33bb329884b34cfbea83cdcdac8292976c1e2ed40b9089eb6cf4f257c464560

另一方面,也会存在安全隐患,比如,容器中一旦挂载cgroup filesystem,可以修改整全局的cgroup配置。最后,如果想在容器内部运行systemd,我们希望每个容器都自己的cgroup结构,lxcfs也是为了解决这个问题,但是cgroup namespace更加安全。

有了cgroup namespace后,每个namespace中的进程都有自己cgroupns rootcgroup filesystem视图。

测试

# uname -a
4.8.10-1.el6.elrepo.x86_64

# cat /proc/self/cgroup 
4:memory:/

当我们查看/proc/[pid]/cgroup时,第3个字段是进程所属的group directory相对于cgroup root directory的路径,/表示当前进程位于cgroup root directory。

If the cgroup directory of the target process lies outside the root directory of the reading process’s cgroup namespace, then the pathname will show ../ entries for each ancestor level in the cgroup hierarchy.

# mkdir -p /cgroup/memory/docker/container1
# echo $$
12234

# echo $$ > /cgroup/memory/docker/container1/tasks
# cat /cgroup/memory/docker/container1/tasks
12234
22411

其中22411cat命令对应的进程。

# cat /proc/self/cgroup
4:memory:/docker/container1

使用unshare创建新的cgroup namespace:

# unshare -Cm bash
# cat /proc/self/cgroup
4:memory:/

可以看到,新的进程(及子进程)的cgroup root信息发生了变化。

我们可以查看init cgroupns进程的cgroup信息:

# cat /proc/1/cgroup
4:memory:/../..

但是,cgroup filesystem的挂载点仍然是init namespace中挂载点。所以,在新的cgroupns仍然能够看到全局的cgroup视图:

# cat /proc/self/mountinfo
51 38 0:27 /../.. /cgroup/memory rw,relatime - cgroup cgroup rw,memory

# ls /cgroup/memory/
docker ...

我们希望在新的cgroupns中,进程看到的cgroup挂载点显示为/(即有自己的cgroup root),我们需要重新挂载一下cgroup filesystem:

# mount --make-rslave / # Don't propagate mount events to other namespaces
# umount /cgroup/memory 
# mount -t cgroup -o memory cgroup /cgroup/memory
# cat /proc/self/mountinfo 
51 38 0:27 / /cgroup/memory rw,relatime - cgroup cgroup rw,memory

# ls /cgroup/memory/ 
看不到docker目录

这样,我们就只能看到当前cgroupns中的视图了。

从init cgroupns中,仍然能够看到子cgroupns中的进程的完整路径:

# cat /proc/12234/cgroup
4:memory:/docker/container1

总结

Cgroup namespace带来以下一些好处:

(1)可以限制容器的cgroup filesytem视图,使得在容器中也可以安全的使用cgroup;

(2)此外,会使容器迁移更加容易;在迁移时,/proc/self/cgroup需要复制到目标机器,这要求容器的cgroup路径是唯一的,否则可能会与目标机器冲突。有了cgroupns,每个容器都有自己的cgroup filesystem视图,不用担心这种冲突。

应用层

Docker本身还没有使用这一特性,runc已经有相关PR在实现中,参考#774#1184

主要参考


上一篇     下一篇