10 Docker 资源隔离

技术实现

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


Namespace 类型

在最新的 Linux 5.6 内核中,提供了 8 种类型的 Namespace,但最新版本的 Docker 只使用了其中的前 6 种类型,如下表所示:

Namespace 名称 简称 作用 内核版本
Mount mnt 隔离挂载点 2.4.19
Process ID pid 隔离进程ID 2.6.24
Network net 隔离网络设备、端口号等 2.6.29
Interprocess Communication ipc 隔离信息量、消息队列和共享内存 2.6.19
UTS uts 隔离主机名和域名 2.6.19
User user 隔离用户和用户组 3.8
Control group cgroup 隔离 Cgroups 根目录 4.6
Time time 隔离系统时间 5.6

Namespace 各类型作用

通过使用 unshare 命令可以实现创建并访问不同类型的 Namespace,模拟 Dokcer 资源隔离的效果。以下只针对 Docker 使用的前 6 种类型来分析它们各自的作用:

##### Mount Namespace:实现在不同的进程中看到不同的挂载目录
### 通过unshare命令创建一个bash进程,作为窗口1
$ unshare --mount --fork /bin/bash
[root@centos7 ~]# mkdir /tmp/tmpfs
[root@centos7 ~]# mount -t tmpfs -o size=20m tmpfs /tmp/tmpfs
[root@centos7 ~]# df -h /tmp/tmpfs
Filesystem      Size  Used Avail Use% Mounted on
tmpfs            20M     0   20M   0% /tmp/tmpfs

### 打开一个新的命令行窗口,作为窗口2验证
[root@centos7 ~]# df -h /tmp/tmpfs
df: /tmp/tmpfs: No such file or directory

--------------------------------------------------------------------------------------------------
##### PID Namespace:实现每个容器的主进程为1号进程,而容器内的进程在主机上却拥有不同的PID
### 在当前命令行窗口加入了新创建的 PID Namespace,从而看不到主机上其他进程信息
$ unshare --pid --fork --mount-proc /bin/bash
[root@centos7 ~]# ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.0 115544  2004 pts/0    S    10:57   0:00 bash
root        10  0.0  0.0 155444  1764 pts/0    R+   10:59   0:00 ps aux

--------------------------------------------------------------------------------------------------
##### UTS Namespace:实现在容器内的主机名称为任意自定义的主机名
### 在当前命令行窗口加入了新创建的 UTS Namespace,作为窗口1
$ unshare --uts --fork /bin/bash
[root@centos7 ~]# hostname -b utsdocker && hostname
utsdocker

### 打开一个新的命令行窗口,作为窗口2验证
[root@centos7 ~]# hostname
centos7

--------------------------------------------------------------------------------------------------
##### IPC Namespace:实现在容器内的不同空间下的进程间不能通信
### 在当前命令行窗口加入了新创建的 IPC Namespace,作为窗口1
$ unshare --ipc --fork /bin/bash

## 创建系统间通信队列
[root@centos7 centos]# ipcmk -Q
Message queue id: 0

## 查看系统间通信队列列表
[root@centos7 ~]# ipcs -q
------ Message Queues --------
key          msqid      owner      perms      used-bytes   messages
0x73682a32   0          root       644        0            0

### 打开一个新的命令行窗口,作为窗口2验证
[root@centos7 ~]# ipcs -q
------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages

--------------------------------------------------------------------------------------------------
##### User Namespace:实现进程在容器内拥有root权限,而在主机上却只是普通用户
### unshare命令报错无效参数,需要修改系统允许创建 User Namespace 的数量
$ echo 65535 > /proc/sys/user/max_user_namespace

### 在当前命令行窗口加入了新创建的 User Namespace
$ unshare --user -r /bin/bash
[root@centos7 ~]# id
uid=0(root) gid=0(root) groups=0(root),65534(nfsnobody) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

### 虽然已是root用户,但执行重启失败,说明并不能获取到主机的root权限
[root@centos7 ~]# reboot
Failed to open /dev/initctl: Permission denied
Failed to talk to init daemon.

--------------------------------------------------------------------------------------------------
##### Net Namespace:实现每个进程拥有自己独立的IP地址、端口和网卡信息
### 在当前命令行窗口加入了新创建的 Net Namespace,作为窗口1
$ unshare --net --fork /bin/bash
[root@centos7 ~]# ip a
1: lo:  mtu 65536 qdisc noop state DOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

### 打开一个新的命令行窗口,作为窗口2验证
[root@centos7 ~]# ip a
1: lo:  mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0:  mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 02:11:b0:14:01:0c brd ff:ff:ff:ff:ff:ff
    inet 172.25.168.11/24 brd 172.25.168.255 scope global dynamic eth0
       valid_lft 86063337sec preferred_lft 86063337sec
    inet6 fe80::11:b0ff:fe14:10c/64 scope link
       valid_lft forever preferred_lft forever
3: docker0:  mtu 1500 qdisc noqueue state DOWN group default
    link/ether 02:42:82:8d:a0:df brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:82ff:fe8d:a0df/64 scope link
       valid_lft forever preferred_lft forever

你可能感兴趣的:(10 Docker 资源隔离)