一、前言:
Docker容器技术凭借其轻量级、可移植性和隔离性,已成为现代应用开发与部署的主流选择。然而,容器环境的安全漏洞与性能瓶颈也日益凸显。本文将深入解析Docker安全加固与性能优化的核心策略,结合具体代码示例和生产级实践经验,帮助开发者构建安全高效的容器化应用生态。
Docker容器的安全性,很大程度上依赖于Linux系统自身
评估Docker的安全性时,主要考虑以下几个方面:
Linux内核的命名空间机制提供的容器隔离安全
Linux控制组机制对容器资源的控制能力安全。
Linux内核的能力机制所带来的操作权限安全
Docker程序(特别是服务端)本身的抗攻击性。
其他安全增强机制对容器安全性的影响
#在rhel9中默认使用cgroup-v2 但是cgroup-v2中不利于观察docker的资源限制情况,所以推荐使用cgroup-v1
bash
[root@docker-node1 ~]# mount -t cgroup
[root@docker-node1 ~]# mount -t cgroup2
cgroup2 on /sys/fs/cgroup type cgroup2 (rw,nosuid,nodev,noexec,relatime,nsdelegate,memory_recursiveprot)
[root@docker-node1 ~]# grubby --update-kernel=/boot/vmlinuz-$(uname -r) \
--args="systemd.unified_cgroup_hierarchy=0 systemd.legacy_systemd_cgroup_controller"
[root@docker-node1 ~]# reboot
[root@docker-node1 ~]# mount -t cgroup
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd)
cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,net_cls,net_prio)
cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpu,cpuacct)
cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event)
cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
cgroup on /sys/fs/cgroup/misc type cgroup (rw,nosuid,nodev,noexec,relatime,misc)
cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids)
cgroup on /sys/fs/cgroup/rdma type cgroup (rw,nosuid,nodev,noexec,relatime,rdma)
cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb)

1 命名空间隔离的安全
当docker run启动一个容器时,Docker将在后台为容器创建一个独立的命名空间。命名空间提供了最基础也最直接的隔离。
与虚拟机方式相比,通过Linux namespace来实现的隔离不是那么彻底。
容器只是运行在宿主机上的一种特殊的进程,那么多个容器之间使用的就还是同一个宿主机的操作系统内核。
在 Linux 内核中,有很多资源和对象是不能被 Namespace 化的,比如:磁盘等等
bash
[root@docker ~]# docker run -d --name web nginx
3c6b649a200fc56afafe9f47494903fe56e71cabcd534d6c9e6f8b5854f29cac
[root@docker ~]# docker inspect web | grep Pid
"Pid": 4328,
"PidMode": "",
"PidsLimit": null,
[root@docker ~]# cd /proc/4328/ns/ #进程的namespace
[root@docker ns]# ls
cgroup ipc mnt net pid pid_for_children time time_for_children user uts
bash
[root@docker ns]# ls -d /sys/fs/cgroup/memory/docker/3c6b649a200fs省略部分854f29cac/ #资源隔离信息
/sys/fs/cgroup/system.slice/docker-ecb8abbbfc85bf3d62fc82afb3950ab6b6a2e80092738274a233bbb8db0c5ce2.scope
/sys/fs/cgroup/system.slice/docker.service
/sys/fs/cgroup/system.slice/docker.socket
[root@docker ns]# ls -d /sys/fs/cgroup/memory/docker/3c6b649a200fs省略部分854f29cac/ #资源隔离信息
/sys/fs/cgroup/system.slice/docker-ecb8abbbfc85bf3d62fc82afb3950ab6b6a2e80092738274a233bbb8db0c5ce2.scope
/sys/fs/cgroup/system.slice/docker.service
/sys/fs/cgroup/system.slice/docker.socket


2 控制组资源控制的安全
当docker run启动一个容器时,Docker将在后台为容器创建一个独立的控制组策略集合。
Linux Cgroups提供了很多有用的特性,确保各容器可以公平地分享主机的内存、CPU、磁盘IO等资源。
确保当发生在容器内的资源压力不会影响到本地主机系统和其他容器,它在防止拒绝服务攻击(DDoS)方面必不可少
bash
[root@docker ~]# docker run -it --name test busybox #内存资源默认没有被隔离
/ # free -m
total used free shared buff/cache available
Mem: 3627 648 516 16 2463 2678
Swap: 2063 1 2062
/ # exit
[root@docker ~]# free -m
total used free shared buff/cache available
Mem: 3627 907 557 15 2463 2719
Swap: 2062 1 2061

3 内核能力机制
能力机制(Capability)是Linux内核一个强大的特性,可以提供细粒度 的权限访问控制。
大部分情况下,容器并不需要真正的 root权限,容器只需要少数的能力即可。
默认情况下,Docker采白名单机制,禁用"必需功能"之外的其他权限。
4 Docker服务端防护
使用Docker容器的核心是Docker服务端 ,确保只有可信的用户 才能访问到Docker服务。
将容器的root用户映射到本地主机上的非root用户 ,减轻容器和主机之间因权限 提升而引起的安全问题。
允许Docker 服务端在非root权限下运行,利用安全可靠的子进程来代理执行需要特权权限的操作。这些子进程只允许在特定范围内进行操作。
bash
[root@docker ~]# ls -ld /var/lib/docker/ #默认docker是用root用户控制资源的
drwx--x--- 12 root root 171 8月 20 13:21 /var/lib/docker/

二、 Docker的资源限制
Linux Cgroups 的全称是 Linux Control Group。
是限制一个进程组能够使用的资源上限,包括 CPU、内存、磁盘、网络带宽等等。
对进程进行优先级设置、审计,以及将进程挂起和恢复等操作。
Linux Cgroups 给用户暴露出来的操作接口是文件系统
它以文件和目录的方式组织在操作系统的 /sys/fs/cgroup 路径下。
执行此命令查看:mount -t cgroup
bash
[root@docker ~]# mount -t cgroup #在rhel9中默认使用cgroup2
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd)
cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,net_cls,net_prio)
cgroup on /sys/fs/cgroup/misc type cgroup (rw,nosuid,nodev,noexec,relatime,misc)
cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpu,cpuacct)
cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids)
cgroup on /sys/fs/cgroup/rdma type cgroup (rw,nosuid,nodev,noexec,relatime,rdma)
cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb)
cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
在 /sys/fs/cgroup 下面有很多诸如 cpuset、cpu、 memory 这样的子目录,也叫子系统。
在每个子系统下面,为每个容器创建一个控制组(即创建一个新目录)。
控制组下面的资源文件里填上什么值,就靠用户执行 docker run 时的参数指定。
2.1限制cpu使用
ubuntu-latest.tar.gz
(1). 限制cpu的使用量
bash
[root@docker ~]# docker run -it --rm --name test \
--cpu-period 100000 \ #设置 CPU 周期的长度,单位为微秒(通常为 100000,即 100 毫秒)
--cpu-quota 20000 ubuntu #设置容器在一个周期内可以使用的 CPU 时间,单位也是微秒。
root@5797d76b20f5:/# dd if=/dev/zero of=/dev/null &
root@5797d76b20f5:/# top

在cgroup中查看docker的资源限制
bash
[root@docker ~]# cat /sys/fs/cgroup/cpu/docker/"docker id(所要查看容器的id)"/cpu.cfs_period_us #cpu总量划分
[root@docker ~]# cat /sys/fs/cgroup/cpu/docker/"docker id(所要查看容器的id)"/cpu.cfs_quota_us #cpu限制

(2). 限制cpu的优先级
bash
#开启容器时如果指定了cpu使用优先级,那么设定文件为
[root@docker ~]# cat /sys/fs/cgroup/cpu/docker/"docker id(所要查看容器的id)"/cpu.shares
#确保在系统中只有一个cpu核心在下
[root@docker-node1 ~]# cd /sys/devices/system/cpu/
[root@docker-node1 cpu]# ls
cpu0 cpufreq crash_hotplug isolated modalias offline possible present uevent
cpu1 cpuidle hotplug kernel_max nohz_full online power smt vulnerabilities
#关闭cpu的核心,当cpu都不空闲下才会出现争抢的情况,为了实验效果我们可以关闭一个cpu核心
root@docker ~]# echo 0 > /sys/devices/system/cpu/cpu1/online
[root@docker ~]# cat /proc/cpuinfo
[root@docker-node1 cpu1]# cat /proc/cpuinfo | grep cores
cpu cores : 1

bash
[root@docker-node1 ~]# docker run -it --rm --name test ubuntu
root@69183e546633:/# dd if=/dev/zero of=/dev/null &
root@69183e546633:/# top
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
9 root 20 0 2736 1408 1408 R 49.5 0.1 0:40.64 dd
1 root 20 0 4588 3712 3200 S 0.0 0.2 0:00.02 bash
10 root 20 0 8848 5248 3200 R 0.0 0.3 0:00.00 top
[root@docker-node1 ~]# docker run -it --rm --name test1 ubuntu
root@871f9f2bf1ba:/# dd if=/dev/zero of=/dev/null &
root@871f9f2bf1ba:/# top
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
9 root 20 0 2736 1408 1408 R 49.5 0.1 0:40.64 dd
1 root 20 0 4588 3712 3200 S 0.0 0.2 0:00.02 bash
10 root 20 0 8848 5248 3200 R 0.0 0.3 0:00.00 top

bash
#资源限制
[root@docker-node1 ~]# docker run -it --rm --cpu-shares 100 ubuntu #设定cpu优先级,最大为1024,值越大优先级越高
root@0dd481be0925:/# dd if=/dev/zero of=/dev/null &
root@0dd481be0925:/# top

bash
[root@docker-node1 ~]# docker run -it --rm ubuntu:latest
root@f61925d3c218:/#
root@f61925d3c218:/# dd if=/dev/zero of=/dev/null &
root@f61925d3c218:/# top
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
8 root 20 0 2736 1408 1408 R 89.7 0.1 0:24.24 dd
1 root 20 0 4588 3968 3456 S 0.0 0.2 0:00.01 bash
9 root 20 0 8848 5120 3072 R 0.0 0.3 0:00.00 top

bash
(3). 限制内存使用
bahs
#开启容器并限制容器使用内存大小
[root@docker system.slice]# docker run -d --name test --memory 200M --memory-swap 200M nginx
#查看容器内存使用限制
[root@docker ~]# cd /sys/fs/cgroup/memory/docker/d09100472de41824bf0省略部分id96b977369dad843740a1e8e599f430/
[root@docker d091004723d4de41824f6b38a7be9b77369dad843740a1e8e599f430]# cat memory.limit_in_bytes
209715200
[root@docker d091004723d4de41824f6b38a7be9977369dad843740a1e8e599f430]# cat memory.memsw.limit_in_bytes
209715200

bash
#测试容器内存限制,在容器中我们测试内存限制效果不是很明显,可以利用工具模拟容器在内存中写入数据
#在系统中/dev/shm这个目录被挂在到内存中
```bash
#安装检测工具
[root@docker-node1 ~]# rpm -ivh libcgroup-0.41-19.el8.x86_64.rpm
[root@docker-node1 ~]# rpm -ivh libcgroup-tools-0.41-19.el8.x86_64.rpm
/sys/fs/cgroup/memory/docker/4f212de78b0847d54de5508aeec7930c984dec81d59c1d0d007358d55e62bdff/
[root@docker-node1 ~]# cgexec -g memory:docker/4f212de78b0847d54de5508aeec7930c984dec81d59c1d0d007358d55e62bdff dd if=/dev/zero of=/dev/shm/bigfile bs=1M count=200
已杀死
cgexec -g memory:doceker/容器id -g表示使用指定控制器类型
(4). 限制docker的磁盘io
bash
[root@docker-node1 ~]# docker run -it --name test --rm ubuntu:latest
root@0530d0384458:/# dd if=/dev/zero of=/bigfile bs=1M count=1000
限制前下载速率到:412MB/s
硬盘直达,最快,用的是内存 1.7Gb/s


限制后下载速率到:31.4MB/s

三、 Docker的安全加固
1、Docker默认隔离性
在系统中运行容器,我们会发现资源并没有完全隔离开
bash
[root@docker ~]# free -m #系统内存使用情况
total used free shared buff/cache available
Mem: 3627 1128 1714 207 1238 2498
Swap: 2062 0 2062
[root@docker ~]# docker run --rm --memory 200M -it ubuntu
root@e06bdc13b764:/# free -m #容器中内存使用情况
total used free shared buff/cache available
Mem: 3627 1211 1630 207 1239 2415
Swap: 2062

#虽然我们限制了容器的内容使用情况,但是查看到的信息依然是系统中内存的使用信息,并没有隔离开
2、解决Docker的默认隔离性
LXCFS 是一个为 LXC(Linux Containers)容器提供增强文件系统功能的工具。
主要功能
资源可见性:
LXCFS 可以使容器内的进程看到准确的 CPU、内存和磁盘 I/O 等资源使用信息。在没有 LXCFS 时,容器内看到的资源信息可能不准确,这会影响到在容器内运行的应用程序对资源的评估和管理。
性能监控:
方便对容器内的资源使用情况进行监控和性能分析。通过提供准确的资源信息,管理员和开发人员可以更好地了解容器化应用的性能瓶颈,并进行相应的优化。
安装lxcfs
#在rhel9中lxcfs是被包含在epel源中,我们可以直接下载安装包进行安装
root@docker \~\]# ls lxcfs
lxcfs-5.0.4-1.el9.x86_64.rpm lxc-libs-4.0.12-1.el9.x86_64.rpm lxc-templates-4.0.12-1.el9.x86_64.rpm
\[root@docker \~\]# dnf install lxcfs/\*.rpm
运行lxcfs并解决容器隔离性
\[root@docker \~\]# lxcfs /var/lib/lxcfs \&
\[root@docker \~\]# docker run -it -m 256m
-v /var/lib/lxcfs/proc/cpuinfo:/proc/cpuinfo:rw
-v /var/lib/lxcfs/proc/diskstats:/proc/diskstats:rw
-v /var/lib/lxcfs/proc/meminfo:/proc/meminfo:rw
-v /var/lib/lxcfs/proc/stat:/proc/stat:rw
-v /var/lib/lxcfs/proc/swaps:/proc/swaps:rw
-v /var/lib/lxcfs/proc/uptime:/proc/uptime:rw
ubuntu
root@69ec0c67ff04:/# free -m
total used free shared buff/cache available
Mem: 256 1 254 0 0 254
Swap: 512 0 512
### 3、容器特权
在容器中默认情况下即使我是容器的超级用户也无法修改某些系统设定,比如网络
```bash
[root@docker-node1 ~]# docker run -it --name test --rm busybox:latest
/ # ip a
1: lo: