容器通过Linux内核的Namespace实现了资源隔离

什么是NameSpace

NameSpace是Linux内核的一项功能,该功能对内核资源进行分区,以使一组进程看到一组资源,而另一组进程看到另一组资源。
NameSpace的工作方式通过为一组资源和进程设置相同的NameSpace而起作用,但是这些NameSpace引用了不同的资源。资源可能存在于多个NameSpace中。这些资源可以是ID、主机名、用户ID、文件名、与网络访问相关的名称和进程间通信。
NameSpace是Linux内核的一个特性,可以实现在同一主机系统中对进程ID、主机名、用户名ID、文件名、网络和进程间通信等资源的隔离。

Linux的NameSpace主要有以下8中,Docker使用了其中标黄的6种。
image.png

NameSpace有什么作用

  1. Mount NameSpace

作用:隔离不同的进程或进程组看到的挂载点;
实现容器内只能看到自己的挂载信息,在容器内的挂载操作不会影响主机的挂载目录
unshareutil-linux工具包种的一个工具(centOS7及之后已经内置此工具),可以实现创建并访问不同类型的NameSpace

  1. # 创建一个bash进程并且新建一个Mount Namespace
  2. sudo unshare --mount --fork /bin/bash
  3. # 在/tmp目录下创建一个目录
  4. mkdir /tmp/tmpfs
  5. # 使用mount命令挂载一个tmpfs类型的目录
  6. mount -t tmpfs -o size=20m tmpfs /tmp/tmpfs
  7. # 使用df命令查看已经挂载的目录信息,可以看见挂载信息
  8. # 新打开一个终端窗口,使用df -h命令,挂载信息又消失不见了
  9. # 在当前窗口查看当前进程的NameSpace信息
  10. ls -l /proc/self/ns/
  11. # 新打开一个创建查看进程的NameSpace信息
  12. ls -l /proc/self/ns/
  13. # 由此我们可以推论出,新疆的Mount Namespace内mount是和外部完全隔离的
  1. PID NameSpace

作用:隔离进程
在不同的PID NameSpace内,进程可以拥有相同的PID号
利用PID NameSpace可以实现每个容器的主进程为1 号进程,而容器在宿主机的进程号则各不相同

  1. # 创建一个bash进程,并且新建一个PID NameSpace
  2. unshare --pid --fork --mount-proc /bin/bash
  3. # 使用命令查看进程
  4. ps aux
  5. USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
  6. root 1 1.0 0.0 116848 4652 pts/1 S 17:34 0:00 /bin/bash
  7. root 30 0.0 0.0 155484 3720 pts/1 R+ 17:34 0:00 ps aux
  1. UTS NameSpace

作用:隔离主机名
允许每个UTS NameSpace拥有一个独立的主机名,可以实现容器内的主机名为任意主机名

  1. # 使用unshare命令创建一个UTS NameSpace
  2. unshare --mount --fork /bin/bash
  3. # 使用hostname命令设置主机名
  4. hostname -b dmxyhostname
  5. # 接着使用hostname查看主机名,主机名已修改
  6. # 新打开一个窗口,执行hostname,主机名还是原来的主机名
  1. IPC NameSpace

作用:隔离进程间通信
PID NameSpace和IPC NameSpace一起使用可以实现同一IPC NameSpace内的进程彼此间可以通信,不同的IPC NameSapce的进程却不能通信

  1. User NameSpace

作用:隔离用户和用户组
User NameSpace可以实现进程在容器内拥有root权限,而主机上却依旧只是普通用户

  1. # 使用unshare命令创建新的NameSpace
  2. unshare --user -r /bin/bash
  3. # 执行ID命令,可以看出id为root
  4. root@server:~# id
  5. uid=0(root) gid=0(root) groups=0(root),65534(nogroup)
  1. Net NameSpace

作用:隔离网络设备、IP地址和端口等信息
Net NameSpace可以让每个进程都拥有自己独立的IP地址,端口和网卡信息

  1. # 宿主机执行ip a命令
  2. baifan@server:~$ ip a
  3. 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
  4. link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  5. inet 127.0.0.1/8 scope host lo
  6. valid_lft forever preferred_lft forever
  7. inet6 ::1/128 scope host
  8. valid_lft forever preferred_lft forever
  9. 2: ens3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
  10. link/ether fa:a1:a0:31:25:00 brd ff:ff:ff:ff:ff:ff
  11. inet 100.10.1.157/24 brd 100.10.1.255 scope global ens3
  12. valid_lft forever preferred_lft forever
  13. inet6 fe80::f8a1:a0ff:fe31:2500/64 scope link
  14. valid_lft forever preferred_lft forever
  15. 3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
  16. link/ether 02:42:e9:98:cd:37 brd ff:ff:ff:ff:ff:ff
  17. inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
  18. valid_lft forever preferred_lft forever
  19. 4: calidb28572045c@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
  20. link/ether ee:ee:ee:ee:ee:ee brd ff:ff:ff:ff:ff:ff link-netns cni-6f5fab55-9b8b-48a7-86cf-b40fb305a9fe
  21. inet6 fe80::ecee:eeff:feee:eeee/64 scope link
  22. valid_lft forever preferred_lft forever
  23. 7: vxlan.calico: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN group default
  24. link/ether 66:3d:e4:f9:01:ff brd ff:ff:ff:ff:ff:ff
  25. inet 10.1.206.192/32 scope global vxlan.calico
  26. valid_lft forever preferred_lft forever
  27. inet6 fe80::643d:e4ff:fef9:1ff/64 scope link
  28. valid_lft forever preferred_lft forever
  29. # 使用unshare创建一个Net NameSapce
  30. baifan@server:~$ sudo unshare --net --fork /bin/bash
  31. [sudo] password for baifan:
  32. # 在新的Net NameSpace中执行ip a命令
  33. root@server:/home/baifan# ip a
  34. 1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
  35. link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

为什么Docker需要NameSpace

当Docker新建一个容器的时候,会创建这六种Namespace,然后将容器中的进程加入这些Namespace中