docker启动的容器本质上是Host中的一个进程,cgroup和namespace是最重要的两项技术,cgroup主要实现资源的限额,而namespce则用来实现资源的隔离
cgroup全称Control Group ,Linux操作系统通过cgroup可以设置进程使用CPU、内存、和IO资源的限额,比如可以在启动容器时通过:–cpu-shares、-m、–device-write-bps等启动参数来配置限额,其实这些底层就是在配置cgroup。
cgroup到底是啥东西么。可以通过host的目录来找到它
[root@VM_0_13_centos cgroup]# pwd
/sys/fs/cgroup
这里,咱们通过一个例子来深入理解它。
即通过 progrium/stress镜像来测试说明这个东西,启动这个镜像,run命令启动镜像时若本地没有该镜像则会自动去docker仓库去拉相应的镜像
[root@VM_0_13_centos ~]# docker run -it --cpu-shares 512 progrium/stress -c 1
再查看一下刚刚启动的容器ID,下面的ce348eec3e6b
[root@VM_0_13_centos cgroup]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ce348eec3e6b progrium/stress "/usr/bin/stress --v…" 17 hours ago Up 17 hours quirky_cartwright
然后在/sys/fs/cgroup/cpu/docker/
目录中,
[root@VM_0_13_centos cgroup]# cd /sys/fs/cgroup/cpu/docker/
Linux会为每一个容器创建一个cgroup的目录,以容器长ID命名,如下所示:
[root@VM_0_13_centos docker]# ll
total 0
drwxr-xr-x 2 root root 0 Oct 29 17:12 ce348eec3e6b9b68f517279478eef3ba573fca4d81bcc511a34e65505d80f31b
感兴趣的,可以再看下这个容器下的cgroup内容:
[root@VM_0_13_centos ce348eec3e6b9b68f517279478eef3ba573fca4d81bcc511a34e65505d80f31b]# ll
total 0
-rw-r--r-- 1 root root 0 Oct 29 17:12 cgroup.clone_children
--w--w--w- 1 root root 0 Oct 29 17:12 cgroup.event_control
-rw-r--r-- 1 root root 0 Oct 29 17:12 cgroup.procs
-r--r--r-- 1 root root 0 Oct 29 17:12 cpuacct.stat
-rw-r--r-- 1 root root 0 Oct 29 17:12 cpuacct.usage
-r--r--r-- 1 root root 0 Oct 29 17:12 cpuacct.usage_percpu
-rw-r--r-- 1 root root 0 Oct 29 17:12 cpu.cfs_period_us
-rw-r--r-- 1 root root 0 Oct 29 17:12 cpu.cfs_quota_us
-rw-r--r-- 1 root root 0 Oct 29 17:12 cpu.rt_period_us
-rw-r--r-- 1 root root 0 Oct 29 17:12 cpu.rt_runtime_us
-rw-r--r-- 1 root root 0 Oct 29 17:12 cpu.shares
-r--r--r-- 1 root root 0 Oct 29 17:12 cpu.stat
-rw-r--r-- 1 root root 0 Oct 29 17:12 notify_on_release
-rw-r--r-- 1 root root 0 Oct 29 17:12 tasks
目录中包含所有与cpu相关的cgroup配置,文件cpu.shares保存的就是 –cpu-shares的配置,值为512,
[root@VM_0_13_centos ce348eec3e6b9b68f517279478eef3ba573fca4d81bcc511a34e65505d80f31b]# cat cpu.shares
512
同样的,/sys/fs/cgroup/memory/docker
和 /sys/fs/cgroup/blkio/docker
中保存的是内存以及Block IO的cgroup配置。
在每个容器中,我们都可以看到文件系统、网卡等资源,这些资源看上去是各容器之间互相隔离的,拿网卡来说,每个容器都会认为自己有一块独立的网卡,即使host上只有一块物理网卡,这种方式非常好,它使得每个容器更像一台独立的计算机。
Linux实现这种方式的技术是namespace,namespace管理着host中全局唯一的资源,并可以让每个容器都觉得只有自己在独立的占有该资源,换句话说,namespace实现了容器间的资源的隔离。
Linux使用了6种namespace,分别对应6种资源:Mount、UTS、IPC、PID、Network和User。
1.Mount namespace
Mount namespace 让容器看上去拥有整个文件系统。
容器有自己的根目录:“/”,可以执行mount
和umount
命令,当然我们知道这些操作只有在当前容器中生效,不会影响到host和其他容器
2.UTS namespace
简单地说,UTS namespace让容器有自己的hostname,默认情况下,容器的hostname是他的短ID,可以通过-h或者 --hostname启动参数设置。
3.IPC namespace
IPC namespace让容器拥有自己的共享内存和信号量(semaphore)来实现进程间通信,而不会与host和其他容器的IPC混在一起。
4.PID namespace
容器在host中是以进程的方式运行的,例如当前host中运行了两个容器,
[root@VM_0_13_centos docker]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ce348eec3e6b progrium/stress "/usr/bin/stress --v…" 17 hours ago Up 17 hours quirky_cartwright
3127d82847fb ruibaby/halo "java -Djava.securit…" 6 months ago Up 6 months 0.0.0.0:80->8090/tcp halo
两个容器的短ID:ce348eec3e6b
、3127d82847fb
。
通过 ps axf 可以查看容器进程
[root@VM_0_13_centos docker]# ps axf | grep docker
4869 pts/1 S+ 0:00 | \_ grep --color=auto docker
9551 pts/3 Sl+ 0:01 \_ docker run -it --cpu-shares 512 progrium/stress -c 1
13028 ? Sl 6:41 \_ containerd-shim -namespace moby -workdir /var/lib/containerd/io.containerd.runtime.v1.linux/moby/3127d82847fb813da2f8da2de1ccb46dac59238df170bcf6aa3b978f16e0b07c -address /run/containerd/containerd.sock -containerd-binary /usr/bin/containerd -runtime-root /var/run/docker/runtime-runc
9731 ? Sl 0:01 \_ containerd-shim -namespace moby -workdir /var/lib/containerd/io.containerd.runtime.v1.linux/moby/ce348eec3e6b9b68f517279478eef3ba573fca4d81bcc511a34e65505d80f31b -address /run/containerd/containerd.sock -containerd-binary /usr/bin/containerd -runtime-root /var/run/docker/runtime-runc
11412 ? Ssl 68:50 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
13023 ? Sl 0:15 \_ /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 80 -container-ip 172.17.0.2 -container-port 8090
可以看出 13028
进程ID对应容器:3127d82847fb
,9731
进程ID对应容器:ce348eec3e6b
。
所有容器的进程都挂在dockerd进程下,并且容器也有自己的子进程,可以进入到容器中查看容器的子进程。
[root@VM_0_13_centos docker]# docker exec -it ce348eec3e6b bash
root@ce348eec3e6b:/# ps axf
PID TTY STAT TIME COMMAND
7 pts/1 Ss 0:00 bash
14 pts/1 R+ 0:00 \_ ps axf
1 pts/0 Ss+ 0:00 /usr/bin/stress --verbose -c 1
6 pts/0 R+ 1034:13 /usr/bin/stress --verbose -c 1
root@ce348eec3e6b:/#
5.Network namespace
Network namespace让容器拥有自己的独立的网卡、IP、路由等资源,后面单独写篇来详细了解。
6.User namespace
User namespace 让容器能够管理自己的用户,host不能看到容器中创建的用户
[zerah@VM_0_13_centos ~]$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
93448d822113 ubuntu:v1 "bash" 9 minutes ago Up 9 minutes eloquent_herschel
3127d82847fb ruibaby/halo "java -Djava.securit…" 6 months ago Up 6 months 0.0.0.0:80->8090/tcp halo
[zerah@VM_0_13_centos ~]$ docker exec -it 93448d822113 bash
root@93448d822113:/# useradd bob
root@93448d822113:/# whoami
root
root@93448d822113:/# su bob
$ whoami
bob
然后在host中新打开一个窗口,测试一下host能不能看到容器中的用户
[root@VM_0_13_centos ~]# su bob
su: user bob does not exist
在容器中创建了用户zerah,但host中并不会创建相应的用户
注:删除多个已停止的容器:
[root@VM_0_13_centos ~]# docker rm -v $(docker ps -aq -f status=exited)
Ubuntu下添加,删除,修改,查看用户和用户组:http://www.sunaiwen.com/?p=127