管控风险可以防止由于软件缺陷而导致的错误问题,也可以防止由于消耗过量资源而导致计算机无响应的攻击类行为。
Docker 使用来了如下命名空间和相应功能来构建容器:
- MNT - 隔离各个进程间的文件系统挂载点;
- NET - 隔离网络接口,每个网络命名空间都有自己的路由表、防火墙、网络设备等;
- UTS - 隔离两个系统标识符:主机名和域名;
- PID - 隔离进程 ID ;
- IPC - 隔离各种 IPC 资源,如信号量、消息队列、共享内存等;
- USR - 隔离用户名和标识符;
chroot()
- 控制进程所看到的文件系统根目录;- Cgroups - 资源保护。
设置资源分配
默认情况下,容器可以不受限制地使用计算机的物理资源。而如果资源消耗过度则会引发性能问题甚至进程停止运行。
Docker 中可以控制容器的内存、CPU、设备I/O等的资源分配,这在创建容器时可以进行设置。
内存
可以用 --memory
或 -m
来控制容器所能够使用的最大内存:
# 启动一个 MariaDB 服务
docker run -d --name mariadb \
--memory 256m \
--cpu-shares 1024 \
--cap-drop net_raw \
-e MYSQL_ROOT_PASSWORD=test \
mariadb:5.5
参数的格式为 <数量><单位>
,其中单位可以是 b
k
m
g
。
在具有交换空间(扩展到磁盘的虚拟内存)的主机上,容器的内存分配可以大于可用的物理内存。
CPU
可以通过 --cpu-shares
为容器指定 CPU(相比于其他容器的)权重,Linux 会根据权重信息来确定每个容器所能占用的 CPU 资源百分比:
## 启动一个 WordPress 服务
docker run -d -P --name wordpress \
--memory 512m \
--cpu-shares 512 \
--cap-drop net_raw \
--link mariadb:mysql \
-e WORD_PRESS_DB_PASSWORD=test \
wordpress:5.0.0-php7.2-apache
假设当前还有另一个容器,并且权重设为 1024 ,那么 wordpress
容器将会获得 33% 的可用 CPU 资源。
与内存分配不同的是,仅当进程之间出现 CPU 资源争抢时才会进行资源分配,即容器可以占用空闲 CPU 资源,即便是超出了分配限制。
可以通过 --cpus
限制容器可用的 CPU 核心数,它通过配置 Linux 的完全公平调度(CFS)来给容器分配相应的 CPU 资源:
docker run -d -P --name wordpress \
--memory 512m \
--cpus 0.75 \
...
Docker 还支持将容器分配给特定的 CPU 集合。CPU 在工作时会涉及进程的上下文切换,上下文切换是指从执行一个进程变为执行另一个,这一过程非常消耗系统资源。因此必要的话可以将容器限定在一个 CPU 集合中,可以通过 --cpuset-cpus
设置:
# 限制容器运行在 CPU 集合 0 上
docker run -d --cpuset-cpus 0 ...
访问设备
Linux 系统可以连接各种设备,比如硬盘驱动器、USB 驱动器、鼠标、网络摄像头等。默认情况下容器可以访问某些主机设备,而不能默认访问的设备可以通过 --device
来将设备挂载到容器中:
docker run -it --rm \
--device /dev/video0:/dev/video0 \
ubuntu:16.04 ls -al /dev
--device
可以被设置多次,以对不同设备进行访问授权。
共享内存
Linux 提供了共享内存工具,它能够让进程间通信(InterProcess Communication, IPC)以内存级速度进行。一些科学计算和流行的数据库技术(如 PostgreSQL)就使用了共享内存技术。
Docker 默认为每个容器创建唯一的 IPC 命名空间,防止一个容器访问主机或其他容器的内存。Linux IPC 命名空间把共享内存基本单元划分为共享内存块、信号量和消息队列。
可以用 --ipc
选项实现容器之间共享 IPC 基本单元:
docker run -d -u nobody --name ipc_producer \
--ipc shareable \
dockerinaction/ch6_ipc -producer
docker run -d --name ipc_consumer \
--ipc container:ipc_producer \
dockerinaction/ch6_ipc -consumer
--ipc shareable
用于告知 Docker 其 IPC 命名空间可共享给别的容器;--ipc container:<容器>
应用目标容器的 IPC 命名空间。
可用 --ipc=host
使用主机的 IPC 命名空间。
用户权限
Docker 默认以镜像元数据指定的用户身份启动容器,通常是 root 用户。而 root 用户对容器几乎拥有完全的访问权限,因此尽量不使用 root 用户启动容器。
可以用 -u
或 --user
设置用户相关配置,如 -u nobody
代表以普通用户身份启动容器。
更多介绍见书中 P144 。
系统功能权限管理
Linux 上通过能力机制(capabilities)来管控 root 权限,它将 root 权限分割为不同的能力,每种能力都代表一定的特权操作,比如有:
- SYS_MODULE - 插入/删除核心模块
- CAP_NET_RAW - 进程与网络交互
当进程在尝试系统调用时,系统会先检查进程的能力集中是否包含此调用所涉及的能力,如果不包含则调用失败。
创建新容器时,Docker 几乎会删除能力集中的所有能力,只保留对于大多数程序必需且安全的能力。如果要进一步增加会减去能力,可以用 --cap-add
或 --cap-drop
:
docker run --rm -u nobody \
-cap-drop net_raw \
...
也可以用 --privileged
选项授予容器完整的系统功能。
增强工具
Docker 设置了默认的 seccomp 配置文件,用来阻止大多数程序不需要的内核系统调用(syscall)。还可以用自定义的 seccomp 配置文件、AppArmer、SELinux 等工具来增强容器。具体见书 P124 。