容器本质是一个进程,通过镜像层叠方式构建容器的文件系统,当需要改写文件时,把改写的文件复制到最顶层的读写层,其本质还是在宿主机文件系统的某一目录下存储这些信息,所有容器的rootfs最终存储在宿主机上,极有可能出现一个容器把宿主机上所有的磁盘容量耗尽的情况,届时其他容器将无法进行文件存储操作,所以有必要对容器的磁盘使用量进行限制
在全虚拟化和半虚拟化中,每一个租户都独立运行一个内核,比Docker使用操作系统虚拟化更安全
操作系统虚拟化指的是共享内核,内存,CPU以及磁盘等,所以容器的安全问题特别突出,特别是容器逃逸问题.当容器从监狱(jail)中逃出时,所有容器以及宿主机都将受到威胁
在Docker1.0版本之前采用黑名单形式来限制容器的能力,只禁止列出来的部分能力,所以会出现通过open_by_handle_at进行暴力扫描的问题,1.0版本后采用白名单的形式来限制容器的能力,除默认的能力清单外,其他均禁止
默认的Docker网络是网桥模式,所有容器连接到网桥上.容器通过veth pair技术创建veth pair网卡,然后将其中一端放入容器内并且命名为eth0,另外一张网卡留在宿主机网络环境中.容器内网卡发出的数据包都会发往宿主机上对应网卡,再由物理网卡进行转发.同理,物理网卡收到的数据根据地址会相应发送到不同的容器内.实际上所有容器共用一张物理网卡.
如果在同一宿主机中的某一个容器抢占了大部分带宽,将会影响其他容器的使用.如大流量的容器内下载程序会影响其他交互式应用的访问
Docker在0.6版本的时候给容器引入了超级权限,即在docker run 时加上--privileged参数,使容器获得超级权限.其获取过程如下:
Docker首先去检测docker run时是否指定了--privileged标志,如果指定就调用setPrivileged这个操作.setPrivileged函数完成两件事情,一是获取所有能力赋值给容器,使用函数为GetAllCapabilities,二是扫描宿主机所有设备文件挂载到容器内,使用函数为GetHostDeviceNodes
GetAllCapabilities做了什么
以一个非超级权限容器和超级权限容器进行对比
# docker run -d --name nginx1 nginx
# docker inspect --format="{{.State.Pid}}" nginx1
20175
# cat /proc/20175/status
CapInh:00000000a80425fb
CapPrm:00000000a80425fb
CapEff:00000000a80425fb
CapBnd:00000000a80425fb
以下为超级权限
# docker run -d --name nginx2 --privileged=true nginx
[root@alios ~]# docker inspect --format="{{.State.Pid}}" nginx2
19434
# cat /proc/19434/status
CapInh:0000001fffffffff
CapPrm:0000001fffffffff
CapEff:0000001fffffffff
CapBnd:0000001fffffffff
GetHostDeviceNodes做了什么
GetHostDeviceNodes将会获取宿主机目录下的所有设备文件,并将其设置到容器
查看Docker容器没有--privileged参数时,即普通权限下/dev目录下的文件
# docker exec -it nginx1 bash
root@601936256ce6:/# ls /dev
core fd fullfuse mqueue null ptmx pts random shm stderr stdin stdout ttyurandom zero
加了--privileged参数时,即超级权限下的/dev目录下的文件
# docker exec -it nginx2 bash
root@c267a3971fa7:/# ls /dev
autofs dri mapper pts tty0 tty20 tty32 tty44 tty56ttyS1 vcs5 vhci
bsg fb0 mcelog random tty1 tty21 tty33 tty45 tty57ttyS2 vcs6 vhost-net
btrfs-control fd mem raw tty10 tty22 tty34 tty46 tty58ttyS3 vcsa vport2p1
bus full mqueue rtc0 tty11 tty23 tty35 tty47 tty59uhid vcsa1 zero
core fuse net sg0 tty12 tty24 tty36 tty48 tty6uinput vcsa2
cpu hidraw0 network_latency shm tty13 tty25 tty37 tty49 tty60urandom vcsa3
cpu_dma_latency hpet network_throughput snapshot tty14 tty26 tty38 tty5 tty61usbmon0 vcsa4
crash hwrng null snd tty15 tty27 tty39 tty50 tty62usbmon1 vcsa5
dm-0 input nvram sr0 tty16 tty28 tty4 tty51 tty63vcs vcsa6
dm-1 kmsg oldmem stderr tty17 tty29 tty40 tty52 tty7vcs1 vda
dm-2 loop-control port stdin tty18 tty3 tty41 tty53 tty8vcs2 vda1
dm-3 loop0 ppp stdout tty19 tty30 tty42 tty54 tty9vcs3 vfio
dm-4 loop1 ptmx tty tty2 tty31 tty43 tty55 ttyS0vcs4 vga_arbiter
可以看到,加了特权后,宿主机所有设备文件都挂载在容器内
--privileged参数给的权限太多,需要慎重使用,如果需要挂载某个特定的设备,可以如以下操作
--device=/dev/sdc:dev/xvdc:rwm
定向挂载设备到容器,而不是把宿主机全部设备挂载到容器上
此外,可以通过--add-cap和--drop-cap参数对容器的能力进行调整,以最大限度地保证容器使用的安全