Docker 内功心法
又到了这周内功分享会的时间,这周分享的人正是大师兄。
“听说,最近 Docker 很火。今天,我就来带大家看看 Docker 的内功心法。”大师兄望着台下的数十门中弟子,面无表情的说到。
“好!”眼睛师兄起身鼓掌,“大师兄已经修习 Docker 功法了,大家跟着学起来啊!”
众人跟着鼓掌欢呼起来。小刀也鼓起掌,心想:终于要见识大师兄的功力了。
大师兄抬手示意大家安静,“Docker,或者说其他的容器功法,有别于传统的虚拟机技术,内功练的是~”大师兄边说边开始运功,双手展开,左手在空中划出半个圈。
“快速!”
右手再划出半个圈。
“轻盈!”
双手合拢,掌心相对,缓缓说到:“不需要修炼 Hypervisor 层和 GuestOS 层,直接共享系统内核和基础组件。”
大师兄双眼微闭,“所以修习者能够很快上手。”
“而这些都要归功于 Linux 生态中容器功法的多年积累。让我给你们瞧瞧,看招!”说罢,大师兄睁开双眼,小刀只觉一股真气直逼心头。
隔离大法:Namespace
一个 Docker 容器出现在了大家眼前。
大师兄的双手灵活地操控着容器运行,说到:“你们仔细看,这个 Docker 容器,其实不过是宿主机上的进程罢了。”
“这个宿主机上的 10477 号进程,在容器里,是 ID 为 1 的主进程。而且,它还看不到其他的进程,只能看到自己的子进程。你们知道这是为什么吗?”
许多弟子都纷纷摇头。
“它靠的就是 Namespace,命名空间,这是 Linux 启动进程的一个参数。”大师兄收起了容器,“给你们看一下什么是命名空间。”
大师兄张开左手,一道真气从左手涌出。
sudo ls -l /proc/1/ns
/proc/
将/ns 替换成具体的 pid,例如 1,就可以看到对应进程的 Namespace。
“这就是 Linux 的六大命名空间。”大师兄接着又张开了右手,又一道真气从右手涌出。接着双手并拢,两股真气交织在了一起。“这两个进程指向了同一个命名空间,所以就处在了同一个命名空间中。”
“而每个命名空间里的第一号进程,就是这个命名空间的「帮主」,所有它的子进程,就是它的「帮众」,而它也只能看到自己的帮众。”
Namespace 是 Linux 启动进程的一个参数,好比一个帮派,每个人(进程)都是一个帮派(Namespace)的一员。现在启动一个新的进程,给它创建了一个新的帮派。在这个帮派里,这个进程就是“帮主”,也是第一个成员。而且它还看不到其他帮派的人,只能看到自己帮派的帮众(进程)。
“这就是 Docker 使用的隔离大法。一切的一切,不过是障眼法罢了。”大师兄缓缓收功。
docker run 命令可以启动一个新的进程,并加入一个新的 Namespace,就是启动容器。而 docker exec 命令可以创建一个进程,并加入其他容器创建的 Namespace,也就是进入容器。
下面简单介绍下各个命名空间
命名空间
mnt(Mount Namespace)
这是文件系统的命名空间,通过挂载点实现文件隔离。
pid(PID Namespace)
PID (Process Identification) 的隔离,因为 PID 在系统中是唯一的,但是容器启动后第一个进程都是 PID 为 1 的“帮主”进程。
其实就是各个进程在各自的帮派(命名空间)里被“伪装”成“帮主”,但是在宿主机上却有另一个 PID。
ipc(IPC Namespace)
IPC(Inter-Process Communication,进程间通信)隔离,如消息队列、信号量、共享内存、网络 Socket 等。不同 IPC 命名空间下的进程互不可见,就好像在平行宇宙一样。
user(User Namespace)
主要是用户 ID,用户组 ID 等隔离,容器内的 root 用户,在宿主机上就是个“小弟”。
uts(UTS Namespace)
UTS(Unix Time-sharing System)命名空间提供主机名和域名的隔离,所以每个容器的主机名都是不同的,这样通过主机名建立的网络通信就不会乱。
net(Network Namespace)
Network 命名空间提供了网络的隔离,例如网络设备、IP、路由表、端口等,这样宿主机上不同的容器都可以绑定容器内的 80 端口了。
Namespace 的不足
“这就是 Docker 很快速轻盈的原因吧,因为启动容器就是启动一个进程。”小刀问到,“那它一定有什么不足,不然为什么替代不了虚拟机呢?”
“问的好!”大师兄看向小刀,心想:没想到这小子还挺会思考,幸好我做足了功课。
“命名空间可以隔离进程,隔离文件,隔离网络,但是,”大师兄停顿了一会,“它不能隔离内核。”
“所以很多人说它是不彻底的隔离。虚拟机里我们可以为所欲为,但是 Docker 容器里,还是要小~心~谨~慎~的。”最后几个字,大师兄一字一顿地说。
“小心谨慎。”小刀心里嘀咕,“会有什么问题呢?”
“比如说,修改系统时间。”大师兄好像看透了小刀的心思,“所有的容器和宿主机,都会受到影响。”
大师兄接着说:“对于多租户的场景,应用越狱的难度不高,安全性需要额外的保障。”
“最后,命名空间只起到了隔离的作用,没法针对进程,进行资源的限制。当然,这就需要我们的另一大法 CGroups 登场了。”大师兄调整站姿,又起一势。
限制大法:CGroups
俗话说,内功心法,贵在拿捏有度,而我们修炼 Docker 功法,就需要 CGroups 来平衡各方气息。
CGroups,全称是 control groups,是 Linux 用来做资源限制,优先级等功能,由 Google 贡献给 Linux 内核。Linux 把一系列的任务划分成各个任务组,通过对任务组资源的分配起到任务限制的目的。
大师兄手起一式,“带你们看看什么是 CGroups。”
“这里显示的是 cgroups 的子系统,例如 cpu 子系统管理 cpu 资源的使用,memory 子系统管理内存的使用。”大师兄手指向各个目录。
“我们看看 cpu 子系统怎么玩的吧。”,说罢,大师兄右手一挥,进入了 cpu 的目录,“里面就是一些配置,我们可以创建一个新的配置组。”
“怎么创建配置组呢?”小刀问道。
“简单!在这里创建一个目录就行,一个目录就是一个控制组。”大师兄边说边运功演示。
# 挂载 cgroups
mount –t cgroup
# 新建控制组
mkdir test
“瞧!我们可以看到里面其实是有内容的。”大师兄说到。
“太神奇了!为什么新建的目录会有内容呢?”小刀十分惊奇。
“这不过是 CGroups 的模版。”大师兄说到,“我们选择一个配置看一下,例如 cpu.cfs_quota_us
,这个配置设置 cpu 占用的时间,单位是微秒,-1 表示不限制,20000 表示限制 20000 / 100000,即 20% 的 cpu。”
“陆师弟,来运行个死循环看看。”大师兄对戴眼睛的弟子说到。
“好嘞!”眼睛师兄说罢起身运功,一个死循环进程启动。
#!/bin/bash
while [ 1 ]
do
echo 'haha'
done
“让我们通过 top
法器看看。”大师兄拿出了被称为 top
的法器,透过它,大家看到了刚才运行的进程,基本上占满了一核。
“然后我们修改 cpu.cfs_quota_us
为 20000,即限制 20%,将这个进程的 PID 24334 放进 tasks
文件中。”
“我们再来通过 top
看看进程的 cpu 使用,就降到差不多 20% 了。”大师兄简单的几招,立刻出现了效果。
“哇~”众师兄弟们一阵喧哗,交头接耳起来。小刀心想:没想到简简单单的几个招式,会起到这样的效果。
“这只是 cgroups 的一个简单的示例,还能做很多的限制,例如内存、磁盘 IO、设备、网络等。”待大家逐渐安静下来,大师兄双手运功收势。
rmdir test
收功完毕,大师兄说到:“今天就到这里了。带大家简单看看 Docker 的内功心法。好了,散吧!”
后记
Docker 的内功心法看似神奇,却不过是 Linux 的一些功能而已。摸清了门道,其实也没有那么复杂。
欲知后事,请看下回分解。
请关注「容器霸业」,知乎专栏同步更新。
上一章:容器霸业:2 谁主沉浮
下一章:容器霸业:4 运行时
参考文献
- Linux Namespace
- Namespaces in operation
- Docker 背后的内核知识——Namespace 资源隔离
- Linux CGroups
- Docker 背后的内核知识——cgroups 资源限制