本文共 26746 字,大约阅读时间需要 89 分钟。
https://docs.docker.com/engine/security/userns-remap/#prerequisites
注:以下验证环境为centos7.5 docker 18.09.0
User namespaces
CAP_SYS_TIME CAP_SYS_MODULE CAP_MKNOD
groupadd -g 5000 dockertestuseradd -u 5000 -g dockertest dockertest
# id dockertestuid=5000(dockertest) gid=5000(dockertest) groups=5000(dockertest)
dockertest:231072:65536
{"userns-remap":"dockertest"}
# docker info|grep RootDocker Root Dir: /var/lib/docker/231072.231072
docker run -itd --rm --name=centos centos:latest /bin/sh
查看该sh对应在host上的进程,可以看到其用户为231072,即在/etc/subuid中设置的值
[root@localhost 9783]# ps -ef|grep sh ...231072 5392 5375 0 Dec06 pts/0 00:00:00 /bin/sh...
在容器里面创建一个名为test的用户,并在新创建的用户下执行如下命令,可以看到test的uid为1000,按照上面的映射原理,其对应host的uid为231072+1000=232072
[test@0f3005ba4d63 etc]$ id uid=1000(test) gid=1000(test) groups=1000(test)
[test@0f3005ba4d63 etc]$ ping 127.0.0.01
在host上查看ping的进程,可以看到其uid为232072,跟预期一致。
# ps -ef|grep ping232072 10466 9809 0 02:44 pts/1 00:00:00 ping 127.0.0.1
在/proc/10466(对应容器中的ping进程)下面查看uid_map和gid_map文件,可以看到该进程的user namespaces的映射关系:base+docker_offset
[root@localhost 10466]# cat uid_map 0 231072 65536[root@localhost 10466]# cat gid_map 0 231072 65536
# chown 232072:232072 test1 # chmod 4777 test1
# ll -rwsrwxrwx. 1 232072 232072 8632 Dec 20 22:55 test1
# ./test1 real_user_id=0, effictive_user_id=1000, saved_user_id=1000Cap data ES=0x0, PS=0xa80425fb, IS=0xa80425fb
在root user namespace中修改test1文件的用户和组为200:200,再在容器中以root权限运行,可以看出SUID的标志位被忽略了,但该标志位仍在。
# ./test1real_user_id=0, effictive_user_id=0, saved_user_id=0Cap data ES=0xa80425fb, PS=0xa80425fb, IS=0xa80425fb
# ls -al-rwsrwxrwx. 1 65534 65534 8632 Dec 20 14:55 test1
# cat /proc/1/uid_map 0 0 4294967295
下面演示设置uid_map和gid_map,首先使用root账户创建一个user namespace,查看其bash进程pid和uid,可以看到uid都是65535
# unshare -fUu /bin/bash # echo $$ 9988 # id uid=65534(nfsnobody) gid=65534(nfsnobody) groups=65534(nfsnobody) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
在root user namespace下修改9988进程的uid_map
# echo "0 0 10000" > uid_map
在新的user namespace查看新的id,其uid已经变为0,修改gid的方式也一样。需要特别注意的是设置到uid_map(gid_map)中的第二个参数必须是一个存在的user id,且必须是创建该user namespace的用户的id(此处均为0),否则即使设置成功了也不会生效。比如使用root user namespace下有一个newusr的用户,id为3000,使用echo "0 3000 10000" > uid_map并不会使得新user namespace中的uid变为0。参见
# id uid=0(root) gid=65534(nfsnobody) groups=65534(nfsnobody) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
The writing process must have the same effective user ID as the process that created the user namespace.
PID namespaces
Docker PID namespaces:
PID namespaces使得每个 PID namespace 中的进程可以有其独立的 PID; 每个容器可以有其 PID 为 1 的root 进程;因为 namespace 中的进程 ID 和 host 无关,也使得容器可以在不同的 host 之间迁移。这也使得容器中的每个进程有一对映射的PID:容器中的 PID 和 host 上的 PID。
#!/bin/shwhile true dosleep 5done
sh-4.2# ps -efUID PID PPID C STIME TTY TIME CMDroot 1 0 0 01:19 pts/0 00:00:00 /bin/shroot 6 0 0 01:23 pts/1 00:00:00 /bin/shroot 26 6 0 01:31 pts/1 00:00:00 /bin/sh ./testcontainer.shroot 84 0 0 01:36 pts/2 00:00:00 /bin/sh
[root@localhost ns]# ps -ef|grep testcontainerroot 13748 83414 0 10:38 pts/7 00:00:00 grep --color=auto testcontainerroot 101442 79761 0 09:31 ? 00:00:00 /bin/sh ./testcontainer.sh
# lltotal 0lrwxrwxrwx. 1 root root 0 Dec 5 09:35 ipc -> ipc:[4026532574]lrwxrwxrwx. 1 root root 0 Dec 5 09:35 mnt -> mnt:[4026532572]lrwxrwxrwx. 1 root root 0 Dec 5 09:35 net -> net:[4026532577]lrwxrwxrwx. 1 root root 0 Dec 5 09:35 pid -> pid:[4026532575]lrwxrwxrwx. 1 root root 0 Dec 5 09:35 user -> user:[4026531837]lrwxrwxrwx. 1 root root 0 Dec 5 09:35 uts -> uts:[4026532573]
# lltotal 0lrwxrwxrwx. 1 root root 0 Dec 5 10:42 ipc -> ipc:[4026531839]lrwxrwxrwx. 1 root root 0 Dec 5 10:42 mnt -> mnt:[4026531840]lrwxrwxrwx. 1 root root 0 Dec 5 10:42 net -> net:[4026531956]lrwxrwxrwx. 1 root root 0 Dec 5 10:42 pid -> pid:[4026531836]lrwxrwxrwx. 1 root root 0 Dec 5 10:42 user -> user:[4026531837]lrwxrwxrwx. 1 root root 0 Dec 5 10:42 uts -> uts:[4026531838]
自定义pid namespaces
unshare --fork --pid --mount-proc
sh-4.2# ping 127.0.0.1
[root@localhost home]# ps -ef|grep pingroot 37067 35718 0 16:01 pts/1 00:00:00 ping 127.0.0.1[root@localhost home]# ps -ef|grep 35718root 35718 35717 0 15:05 pts/1 00:00:00 /bin/shroot 37067 35718 0 16:01 pts/1 00:00:00 ping 127.0.0.1[root@localhost home]# ps -ef|grep 35717root 35717 35547 0 15:05 pts/1 00:00:00 unshare -pf --mount-proc /bin/shroot 35718 35717 0 15:05 pts/1 00:00:00 /bin/sh
# ll (查看ping进行对应的ns)total 0lrwxrwxrwx. 1 root root 0 Dec 10 16:21 ipc -> ipc:[4026531839]lrwxrwxrwx. 1 root root 0 Dec 10 16:21 mnt -> mnt:[4026532669]lrwxrwxrwx. 1 root root 0 Dec 10 16:21 net -> net:[4026531956]lrwxrwxrwx. 1 root root 0 Dec 10 16:21 pid -> pid:[4026531836]lrwxrwxrwx. 1 root root 0 Dec 10 16:21 user -> user:[4026531837]lrwxrwxrwx. 1 root root 0 Dec 10 16:21 uts -> uts:[4026531838]# ll ../../37067/ns/ (查看unshare进程对应的ns)total 0lrwxrwxrwx. 1 root root 0 Dec 10 16:22 ipc -> ipc:[4026531839]lrwxrwxrwx. 1 root root 0 Dec 10 16:22 mnt -> mnt:[4026532669]lrwxrwxrwx. 1 root root 0 Dec 10 16:22 net -> net:[4026531956]lrwxrwxrwx. 1 root root 0 Dec 10 16:22 pid -> pid:[4026532670]lrwxrwxrwx. 1 root root 0 Dec 10 16:22 user -> user:[4026531837]lrwxrwxrwx. 1 root root 0 Dec 10 16:22 uts -> uts:[4026531838]
# nsenter --pid=pid# mount -t proc proc /proc# ps -efUID PID PPID C STIME TTY TIME CMDroot 1 0 0 16:37 pts/1 00:00:00 /bin/shroot 3 1 0 16:37 pts/1 00:00:00 ping 127.0.0.1root 39 0 0 16:40 pts/2 00:00:00 -bashroot 78 39 0 16:40 pts/2 00:00:00 ps -ef
Mount namespaces
docker mount namespaces(后续会增加一个讲解docker 存储的篇章)
自定义mount namespaces
当一个进程调用clone或unshare创建一个mount namespace时,子mount namespace的mount point list会拷贝父namespace下的mount point list,可以查看/proc/$pid/mountinfo文件,可以看到子namespace和父namespace中的内容是一样的,但后续各自namespace对mount的操作将互不影响(取决于shared subtrees特性)
为了解决在多个mount namespace的场景下,对同一个mount point在不同mount namespace中的维护(mount umount)问题,Linux 2.6.15版本中推出了Share Subtrees特性,Share Subtrees有4种propagation类型:
[root@host /]# dd if=/dev/zero of=./vdisk1 bs=1M count=10[root@host /]# dd if=/dev/zero of=./vdisk2 bs=1M count=10[root@host /]# dd if=/dev/zero of=./vdisk3 bs=1M count=10[root@host /]# dd if=/dev/zero of=./vdisk4 bs=1M count=10[root@host /]# mkfs vdisk1 [root@host /]# mkfs vdisk2[root@host /]# mkfs vdisk3[root@host /]# mkfs vdisk4[root@host /]# mkdir mntS[root@host /]# mkdir mntP[root@host /]# mkdir /mntS-B
将vdisk1 mount到/mntS,vdisk2 mount到/mntP,/mntS-B bind mount到/mntS
[root@host /]# mount --make-shared vdisk1 /mntS[root@host /]# mount --make-private vdisk2 /mntP [root@host ~]# mount --bind /mntS /mntS-B/
在当前mount namespace下面查看mount结果,可以看到/mntS和/mntS-B的类型为shared,peer group ID为162;而mntP没有任何类型标识,即为private。mountinfo文件中第一列为mount point ID,第二列为父mount point ID,可以看到它们的父mount point ID都是40
[root@host /]# cat /proc/self/mountinfo |grep mnt181 40 7:0 / /mntS rw,relatime shared:162 - ext2 /dev/loop0 rw,seclabel275 40 7:1 / /mntP rw,relatime - ext2 /dev/loop1 rw,seclabel283 40 7:0 / /mntS-B rw,relatime shared:162 - ext2 /dev/loop0 rw,seclabel
查看40对应的信息,可以看到其mount point为系统根目录"/",根目录对应的类型为shared,peer group ID为1。默认情况下子mount point会继承父mount point的propagation类型,所以上述mount --make-shared vdisk1 /mntS也可以写为mount vdisk1 /mntS
[root@host /]# cat /proc/self/mountinfo | awk '$1 == 40' | sed 's/ - .*//'40 0 253:0 / / rw,relatime shared:1
创建一个mount namespace,并将其hostname改为container。unshare默认会将新创建的mount namespace的propagation类型转变为private,使用--propagation unchanged可以让其继承父mount namespace的propagation类型
[root@host /]# unshare -fmu --propagation unchanged[root@host /]# hostname container[root@host /]# exec bash[root@container /]#
查看新创建的namespace中的/mntS和/mntP的信息,可以看大盘/mntS和/mntS-B的shared peer group ID为162,与host上/mntS的ID一致,可以看到两个/mntS为同一个peer group;而/mntP均为private类型
[root@container ~]# cat /proc/self/mountinfo |grep mnt500 463 7:0 / /mntS rw,relatime shared:162 - ext2 /dev/loop0 rw,seclabel501 463 7:1 / /mntP rw,relatime - ext2 /dev/loop1 rw,seclabel502 463 7:0 / /mntS-B rw,relatime shared:162 - ext2 /dev/loop0 rw,seclabel
在container mount namespace中的/mntS和/mntP下创建子目录,并将vdisk3和vdisk4 mount到这两个目录
[root@container /]# mkdir -p /mntS/mntS-sub[root@container /]# mkdir -p /mntP/mntP-sub[root@container /]# mount vdisk3 /mntS/mntS-sub/[root@container /]# mount vdisk4 /mntP/mntP-sub/
在container下查看moutinfo,可以发现/mntS和/mntP的子目录下的mout point继承了父mount point的propagation类型
[root@container /]# cat /proc/self/mountinfo |grep mnt500 463 7:0 / /mntS rw,relatime shared:162 - ext2 /dev/loop0 rw,seclabel501 463 7:1 / /mntP rw,relatime - ext2 /dev/loop1 rw,seclabel502 463 7:0 / /mntS-B rw,relatime shared:162 - ext2 /dev/loop0 rw,seclabel503 500 7:2 / /mntS/mntS-sub rw,relatime shared:254 - ext2 /dev/loop2 rw,seclabel506 502 7:2 / /mntS-B/mntS-sub rw,relatime shared:254 - ext2 /dev/loop2 rw,seclabel523 501 7:3 / /mntP/mntP-sub rw,relatime - ext2 /dev/loop3 rw,seclabel
在host上查看mountinfo,发现其与container中不同在于没有mntP-sub目录的信息,这也表面了private类型下的mount umount事件不会传递,而shared则会在同peer group内传递这些事件
[root@host ~]# cat /proc/self/mountinfo |grep mnt181 40 7:0 / /mntS rw,relatime shared:162 - ext2 /dev/loop0 rw,seclabel275 40 7:1 / /mntP rw,relatime - ext2 /dev/loop1 rw,seclabel283 40 7:0 / /mntS-B rw,relatime shared:162 - ext2 /dev/loop0 rw,seclabel508 181 7:2 / /mntS/mntS-sub rw,relatime shared:254 - ext2 /dev/loop2 rw,seclabel505 283 7:2 / /mntS-B/mntS-sub rw,relatime shared:254 - ext2 /dev/loop2 rw,seclabel
[root@host /]# mkdir mntS1[root@host /]# mkdir mntS2[root@host /]# mount --make-shared vdisk1 /mntS1/[root@host /]# mount --make-shared vdisk2 /mntS2/
查看host上mntS*目录的mountinfo,可以看到其类型为shared,分属于2个不同的peer group
[root@host /]# cat /proc/self/mountinfo |grep mnt181 40 7:0 / /mntS1 rw,relatime shared:162 - ext2 /dev/loop0 rw,seclabel276 40 7:1 / /mntS2 rw,relatime shared:170 - ext2 /dev/loop1 rw,seclabel
创建一个新的mount namespace,集成其父mount namespace的propagation属性
[root@host /]# unshare -fum --propagation unchanged[root@host /]# hostname container[root@host /]# exec bash
当然,其与host上的mount point属于同一个peer group
[root@container /]# mount --make-slave /mntS2 [root@container /]# cat /proc/self/mountinfo |grep mnt491 286 7:0 / /mntS1 rw,relatime shared:162 - ext2 /dev/loop0 rw,seclabel492 286 7:1 / /mntS2 rw,relatime shared:170 - ext2 /dev/loop1 rw,seclabel
将container的mntS2的propagation类型转变为slave,查看mountinfo信息,可以看到/mntS2变为slave,其master为ID为170的peer group,就是host上的/mntS2
[root@container /]# cat /proc/self/mountinfo |grep mnt491 286 7:0 / /mntS1 rw,relatime shared:162 - ext2 /dev/loop0 rw,seclabel492 286 7:1 / /mntS2 rw,relatime master:170 - ext2 /dev/loop1 rw,seclabel
在/mntS1和/mntS2下创建新的mount point,可以看到在/mntS1下的mount point类型为shared,而在/mntS2下面的mount point类型为private
[root@container /]# mkdir -p /mntS1/mntS1-sub[root@container /]# mkdir -p /mntS2/mntS2-sub[root@container /]# mount vdisk3 /mntS1/mntS1-sub/[root@container /]# mount vdisk4 /mntS2/mntS2-sub/[root@container /]# cat /proc/self/mountinfo |grep mnt491 286 7:0 / /mntS1 rw,relatime shared:162 - ext2 /dev/loop0 rw,seclabel492 286 7:1 / /mntS2 rw,relatime master:170 - ext2 /dev/loop1 rw,seclabel493 491 7:2 / /mntS1/mntS1-sub rw,relatime shared:246 - ext2 /dev/loop2 rw,seclabel503 492 7:3 / /mntS2/mntS2-sub rw,relatime - ext2 /dev/loop3 rw,seclabel
查看host的mountinfo,可以看到/mntS1新建的子目录,而无法看到slave类型的/mntS2新建的子目录。即slave的mount umount事件是无法传递到master的
[root@host mntS2]# cat /proc/self/mountinfo |grep mnt181 40 7:0 / /mntS1 rw,relatime shared:162 - ext2 /dev/loop0 rw,seclabel276 40 7:1 / /mntS2 rw,relatime shared:170 - ext2 /dev/loop1 rw,seclabel495 181 7:2 / /mntS1/mntS1-sub rw,relatime shared:246 - ext2 /dev/loop2 rw,seclabel
在host的/mnt2目录下创建一个新的mount point,可以看到/mntS2/mntS2-sub2创建成功,并创建一个新的子peer group
[root@host /]# mkdir -p /mntS2/mntS2-sub2[root@host /]# mount vdisk5 /mntS2/mntS2-sub2/[root@host /]# cat /proc/self/mountinfo |grep mnt181 40 7:0 / /mntS1 rw,relatime shared:162 - ext2 /dev/loop0 rw,seclabel276 40 7:1 / /mntS2 rw,relatime shared:170 - ext2 /dev/loop1 rw,seclabel495 181 7:2 / /mntS1/mntS1-sub rw,relatime shared:246 - ext2 /dev/loop2 rw,seclabel504 276 7:4 / /mntS2/mntS2-sub2 rw,relatime shared:256 - ext2 /dev/loop4 rw,seclabel
在container中查看moutinfo,可以看到在host上新建的mount point,且为同一个peer group,ID为256。符合slave的定义,即slave的mount umount事件无法传递给master,但是反过来是可以的
[root@container /]# cat /proc/self/mountinfo |grep mnt491 286 7:0 / /mntS1 rw,relatime shared:162 - ext2 /dev/loop0 rw,seclabel492 286 7:1 / /mntS2 rw,relatime master:170 - ext2 /dev/loop1 rw,seclabel493 491 7:2 / /mntS1/mntS1-sub rw,relatime shared:246 - ext2 /dev/loop2 rw,seclabel503 492 7:3 / /mntS2/mntS2-sub rw,relatime - ext2 /dev/loop3 rw,seclabel506 492 7:4 / /mntS2/mntS2-sub2 rw,relatime master:256 - ext2 /dev/loop4 rw,seclabel
make-shared make-slave make-priv make-unbindshared shared slave/priv [1] priv unbindslave slave+shared slave [2] priv unbindslave+shared slave+shared slave priv unbindprivate shared priv [2] priv unbindunbindable shared unbind [2] priv unbind
使用mount --bind时的转换规则如下
source(A) shared private slave unbind───────────────────────────────────────────────────────────────dest(B) shared | shared shared slave+shared invalid nonshared | shared private slave invalid
使用mount move时的转换规则如下:
source(A) shared private slave unbind──────────────────────────────────────────────────────────────────dest(B) shared | shared shared slave+shared invalid nonshared | shared private slave unbindable
mount 命名空间通过/proc/[pid]/mounts, /proc/[pid]/mountinfo, 和/proc/[pid]/mountstats文件,使得通过mount命令仅能查看到容器的挂载信息
UTS namespaces
用于在独立的namespace下设置系统hostname和NIS domain name。使用方式比较简单,其中hostname的使用参见上述mount namespace,使用unshare创建uts namespace时指定选项-u即可
Network namespaces
用于创建一个独立的网络namespace,其中包括独立的网卡,ip,掩码,路由,iptables等,主要通过ip link,ip netns,ip addr,iptables,ip route,bridge等命令实现,可以参见
由于的存在,容器中的网络信息和容器外面的网络信息并不相同,如使用ip,nstat,ss等命令查看网络信息时,实际读取的是/proc/net中的信息,从Linux 2.6.25开始,/proc/net会符号链接到/proc/self/net(如下图)。如果两个进程属于不同的命名空间,则它们的/proc/$pid/net的信息相同;如果两个进程属于相同的命名空间,则它们的/proc/$pid/net的信息相同。
容器的网络信息可以通过其对应的进程下面的/proc/$pid/net查看
除/proc/$pid/net目录外,网络命名空间还了/sys/class/net,/proc/sys/net,socket等。
IPC namespaces
IPC用于进程间通信,常用到的方法有:信号量,共享内存,消息队列,系统文件和socket,前面四个主要用于本机上ipc通信,最后一个套接字可以支持不同主机间的ipc通信。IPC namespace用于隔离信号量,共享内存和消息队列(文件系统可以由mount namespace隔离,socket可以由network namespace隔离)
如下文件在不同IPC namespace中是不同的(其中消息队列有POSIX和system V两个标准)
* POSIX消息队列接口 /proc/sys/fs/mqueue.* System V IPC /proc/sys/kernel, namely: msgmax,msgmnb, msgmni, sem, shmall, shmmax, shmmni, and shm_rmid_forced.* System V IPC /proc/sysvipc.
使用ipcs -l可知当前系统使用的消息队列是system V的
[root@host kernel]# ipcs -l------ Messages Limits --------max queues system wide = 468max size of message (bytes) = 8192default max size of queue (bytes) = 16384------ Shared Memory Limits --------max number of segments = 4096max seg size (kbytes) = 18014398509465599max total shared memory (kbytes) = 18014398442373116min seg size (bytes) = 1------ Semaphore Limits --------max number of arrays = 128max semaphores per array = 250max semaphores system wide = 32000max ops per semop call = 32semaphore max value = 32767
[root@host kernel]# cat /proc/sys/kernel/msg*819216384468
[root@host ~]# ipcmk -QMessage queue id: 32768[root@host ~]# ipcmk -M 50Shared memory id: 1540114[root@host ~]# ipcs------ Message Queues --------key msqid owner perms used-bytes messages0xc8232df1 32768 root 644 0 0------ Shared Memory Segments --------key shmid owner perms bytes nattch status0xc932e3e5 1540114 root 644 50 0------ Semaphore Arrays --------key semid owner perms nsems
[root@host ~]# unshare -fui[root@host ~]# hostname container[root@host ~]# exec bash[root@container ~]# ipcs------ Message Queues --------key msqid owner perms used-bytes messages------ Shared Memory Segments --------key shmid owner perms bytes nattch status------ Semaphore Arrays --------key semid owner perms nsems
IPC命名空间根据接口不同了如下文件:
Cgroup namespaces:
docker在1.8版本之后将分配给容器的cgroup挂载到了容器中。下例使用--memory选项限制容器使用的内存大小为200M(container ID=962f63bbfbde77dff734d0c832b5538c5ac4df599825b78e22183cc75e87195e )
# docker run --rm --memory=200M -it busybox:latest /bin/sh
在容器里面查看cgroup的mount的信息如下,容器962f63bbfbde的cgroup挂载点在host的/sys/fs/cgroup下面,采用的挂载propagation类型为MS_SLAVE
# cat /proc/self/mountinfo |grep cgroup193 192 0:54 / /sys/fs/cgroup ro,nosuid,nodev,noexec,relatime - tmpfs tmpfs rw,seclabel,mode=755194 193 0:25 /docker/962f63bbfbde77dff734d0c832b5538c5ac4df599825b78e22183cc75e87195e /sys/fs/cgroup/systemd ro,nosuid,nodev,noexec,relatime master:9 - cgroup cgroup rw,seclabel,xattr,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd195 193 0:27 / /sys/fs/cgroup/rdma ro,nosuid,nodev,noexec,relatime master:10 - cgroup cgroup rw,seclabel,rdma196 193 0:28 /docker/962f63bbfbde77dff734d0c832b5538c5ac4df599825b78e22183cc75e87195e /sys/fs/cgroup/net_cls,net_prio ro,nosuid,nodev,noexec,relatime master:11 - cgroup cgroup rw,seclabel,net_cls,net_prio197 193 0:29 /docker/962f63bbfbde77dff734d0c832b5538c5ac4df599825b78e22183cc75e87195e /sys/fs/cgroup/perf_event ro,nosuid,nodev,noexec,relatime master:12 - cgroup cgroup rw,seclabel,perf_event198 193 0:30 /docker/962f63bbfbde77dff734d0c832b5538c5ac4df599825b78e22183cc75e87195e /sys/fs/cgroup/pids ro,nosuid,nodev,noexec,relatime master:13 - cgroup cgroup rw,seclabel,pids199 193 0:31 /docker/962f63bbfbde77dff734d0c832b5538c5ac4df599825b78e22183cc75e87195e /sys/fs/cgroup/hugetlb ro,nosuid,nodev,noexec,relatime master:14 - cgroup cgroup rw,seclabel,hugetlb200 193 0:32 /docker/962f63bbfbde77dff734d0c832b5538c5ac4df599825b78e22183cc75e87195e /sys/fs/cgroup/cpuset ro,nosuid,nodev,noexec,relatime master:15 - cgroup cgroup rw,seclabel,cpuset201 193 0:33 /docker/962f63bbfbde77dff734d0c832b5538c5ac4df599825b78e22183cc75e87195e /sys/fs/cgroup/cpu,cpuacct ro,nosuid,nodev,noexec,relatime master:16 - cgroup cgroup rw,seclabel,cpu,cpuacct202 193 0:34 /docker/962f63bbfbde77dff734d0c832b5538c5ac4df599825b78e22183cc75e87195e /sys/fs/cgroup/blkio ro,nosuid,nodev,noexec,relatime master:17 - cgroup cgroup rw,seclabel,blkio203 193 0:35 /docker/962f63bbfbde77dff734d0c832b5538c5ac4df599825b78e22183cc75e87195e /sys/fs/cgroup/devices ro,nosuid,nodev,noexec,relatime master:18 - cgroup cgroup rw,seclabel,devices204 193 0:36 /docker/962f63bbfbde77dff734d0c832b5538c5ac4df599825b78e22183cc75e87195e /sys/fs/cgroup/freezer ro,nosuid,nodev,noexec,relatime master:19 - cgroup cgroup rw,seclabel,freezer205 193 0:37 /docker/962f63bbfbde77dff734d0c832b5538c5ac4df599825b78e22183cc75e87195e /sys/fs/cgroup/memory ro,nosuid,nodev,noexec,relatime master:20 - cgroup cgroup rw,seclabel,memory
在host上查看cgroup的mount,与容器中一一对应,如容器中的memory 的master:20对应host上的memory shared:20
28 27 0:25 / /sys/fs/cgroup/systemd rw,nosuid,nodev,noexec,relatime shared:9 - cgroup cgroup rw,seclabel,xattr,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd30 27 0:27 / /sys/fs/cgroup/rdma rw,nosuid,nodev,noexec,relatime shared:10 - cgroup cgroup rw,seclabel,rdma31 27 0:28 / /sys/fs/cgroup/net_cls,net_prio rw,nosuid,nodev,noexec,relatime shared:11 - cgroup cgroup rw,seclabel,net_cls,net_prio32 27 0:29 / /sys/fs/cgroup/perf_event rw,nosuid,nodev,noexec,relatime shared:12 - cgroup cgroup rw,seclabel,perf_event33 27 0:30 / /sys/fs/cgroup/pids rw,nosuid,nodev,noexec,relatime shared:13 - cgroup cgroup rw,seclabel,pids34 27 0:31 / /sys/fs/cgroup/hugetlb rw,nosuid,nodev,noexec,relatime shared:14 - cgroup cgroup rw,seclabel,hugetlb35 27 0:32 / /sys/fs/cgroup/cpuset rw,nosuid,nodev,noexec,relatime shared:15 - cgroup cgroup rw,seclabel,cpuset36 27 0:33 / /sys/fs/cgroup/cpu,cpuacct rw,nosuid,nodev,noexec,relatime shared:16 - cgroup cgroup rw,seclabel,cpu,cpuacct37 27 0:34 / /sys/fs/cgroup/blkio rw,nosuid,nodev,noexec,relatime shared:17 - cgroup cgroup rw,seclabel,blkio38 27 0:35 / /sys/fs/cgroup/devices rw,nosuid,nodev,noexec,relatime shared:18 - cgroup cgroup rw,seclabel,devices39 27 0:36 / /sys/fs/cgroup/freezer rw,nosuid,nodev,noexec,relatime shared:19 - cgroup cgroup rw,seclabel,freezer40 27 0:37 / /sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime shared:20 - cgroup cgroup rw,seclabel,memory
在host上查看memory限制如下,为200M
# pwd/sys/fs/cgroup/memory/docker/962f63bbfbde77dff734d0c832b5538c5ac4df599825b78e22183cc75e87195e# cat memory.limit_in_bytes 209715200
在container上查看memory限制如下,也为200M
# pwd/sys/fs/cgroup/memory # cat memory.limit_in_bytes 209715200
由于容器的/proc /sys /dev路径没有做绝对的隔离,会产生一些使用上的问题,如应用程序读取/proc/meminfo时显示的是host的内存信息,而不是cgroup限制的容器的内存信息。参见
容器所在的cgroup可以通过容器的进程查看/proc/$pid/cgroup,进而直到其对应的cgroup所在目录
TIPS:
# nsenter --uts=uts --preserve-credentials hostname 0f3005ba4d63
$ uname -aLinux . 4.19.10-1.el7.elrepo.x86_64 #1 SMP Mon Dec 17 08:44:04 EST 2018 x86_64 x86_64 x86_64 GNU/Linux[nfsnobody@ charlie]$ cat /boot/config-4.19.10-1.el7.elrepo.x86_64|grep CONFIG_USER_NSCONFIG_USER_NS=y
参考:
https://success.docker.com/article/introduction-to-user-namespaces-in-docker-engine
https://docs.docker.com/engine/security/userns-remap/#disable-namespace-remapping-for-a-container
https://success.docker.com/article/user-namespace-runtime-error
http://man7.org/linux/man-pages/man7/namespaces.7.html
http://man7.org/linux/man-pages/man7/pid_namespaces.7.html
http://man7.org/linux/man-pages/man1/unshare.1.html
http://man7.org/linux/man-pages/man7/mount_namespaces.7.html
http://man7.org/linux/man-pages/man7/user_namespaces.7.html
http://www.10tiao.com/html/606/201810/2664605819/1.html
https://segmentfault.com/a/1190000006899213
https://segmentfault.com/a/1190000006912742
https://segmentfault.com/a/1190000006913195
转载地址:http://txakz.baihongyu.com/