Docker安全配置
虚拟机通过添加Hypervisor层,虚拟出网卡、内存、CPU等虚拟硬件,再在其上建立虚拟机,每个虚拟机都有自己的系统内核。而Docker容器则是通过隔离的方式,将文件系统、进程、设备、网络等资源进行隔离,再对权限、CPU资源等进行控制,最终让容器之间互不影响,容器无法影响宿主机。容器与宿主机共享内核、文件系统、硬件等资源。
Docker安全及日志管理
文章目录
资源列表
操作系统 | 配置 | 主机名 | IP |
---|---|---|---|
CentOS 7.9 | 2C4G | master | 192.168.93.165 |
CentOS 7.9 | 2C4G | client | 192.168.93.166 |
基础环境
- 关闭防火墙
systemctl stop firewalld
systemctl disable firewalld
- 关闭安全内核机制
setenforce 0
sed -i "s/^SELINUX=.*/SELINUX=disabled/g" /etc/selinux/config
- 修改主机名
hostnamectl set-hostname master
hostnamectl set-hostname client
- 绑定映射关系
cat >> /etc/hosts << EOF
192.168.93.165 master
192.168.93.166 client
EOF
一、Docker安全相关介绍
1.1、Docker容器与虚拟机的区别
1.1.1、隔离与共享
- 虚拟机通过添加Hypervisor层,虚拟出网卡、内存、CPU等虚拟硬件,再在其上建立虚拟机,每个虚拟机都有自己的系统内核。而Docker容器则是通过隔离的方式,将文件系统、进程、设备、网络等资源进行隔离,再对权限、CPU资源等进行控制,最终让容器之间互不影响,容器无法影响宿主机。容器与宿主机共享内核、文件系统、硬件等资源
1.1.2、性能与损耗
- 与虚拟机相比,容器资源损耗要少。同样的宿主机下,能够建立容器的数量要比虚拟机多。但是,虚拟机的安全性要比容器稍好,要从虚拟机攻破宿主机或其他虚拟机,需要先攻破Hypervisor层,这是极其困难的。而docker容器与宿主机共享内核、文件系统等资源,更有可能对其他容器、宿主机产生影响
1.2、Docker存在的安全问题
1.2.1、Docker自身漏洞
- 作为一款应用Docker本身实现上会有代码缺陷。CVE官方记录Docker历史版本公有超过20项漏洞,可参见Docker官方网站。黑客常用的攻击手段主要有代码执行、权限提升、信息泄露、权限绕过等。目前Docker版本更迭非常快,Docker用户最好将Docker升级为最新的版本
1.2.2、Docker源码问题
Docker提供了Docker hub,可以让用户上传创建的镜像,以便其他用户下载,快速搭建环境。但同时也带来了一些安全问题。例如下面三种方式:
(1)、客户上传恶意镜像
- 如果有客户在制作的镜像中植入木马】后门等恶意软件,那么环境从一开始就已经不安全了,后续更没有什么安全可言
(2)、镜像使用有漏洞的软件
- Docker hub上能下载的镜像里面,75%的镜像都安装了有漏洞的软件。所以下载镜像后,需要检查里面软件的版本信息,对应的版本是否存在漏洞,并及时更新打上补丁
(3)中间人攻击篡改镜像
- 镜像在传输的过程中可能被篡改,目前新版本的Docker已经提供了相应的校验机制来预防这个问题
1.3、Docker架构缺陷与安全机制
Docker本身的架构与机制就可能产生问题,例如这样一种攻击场景,黑客已经控制了宿主机上的一些容器,或者获得了通过在公有云上建立容器的方式,然后对宿主机或其他容器发起攻击
1.3.1、容器之间的局域网攻击
- 主机上的容器之间可以构成局域网,因此针对局域网的ARP欺骗】嗅探、广播风暴等攻击方式更可以用上。所以,在一个主机上部署多个容器需要合理的配置网络,设置iptables规则
1.3.2、DDos攻击耗尽资源
- Cgroup安全机制就是要防止此类攻击的,不要为单一的容器分配过多的资源即可避免类似问题
1.3.3、有漏洞的系统调用
- Docker与虚拟机的一个重要的区别就是Docker与宿主机公有一个操作系统内核。一旦宿主机内核存在可以越权或者提权漏洞,尽管Docker使用普通用户执行,在容器被入侵时,攻击者还可以利用内核漏洞跳到宿主机做更多的事情
1.3.4、共享root用户权限
- 如果以root用户权限运行容器,容器内的root用户也就拥有了宿主机的root权限
1.4、Docker安全基线标准
- 根据Docker官方文档整理,下面从内核、主机、网络、镜像、容器以及其他等6个方面总结Docker安全基线标准
1.4.1、内核级别
- 及时更新内核
- UserNameSpace(容器内的root权限在容器之外处于非高权限状态)
- Cgroups(对资源的配额和度量)
- SElinux/AppArmor/GRSEC(控制文件访问权限)
- Capability(权限划分)
- Seccomp(限定系统调用)
- 禁止将容器的命令空间与宿主机进程命令空间共享
1.4.2、主机级别
-
为容器创建独立分区
-
仅运行必要的服务
-
禁止将宿主机上敏感目录映射到容器
-
对Docker守护进程、相关文件和目录进行审计
-
设置适当的默认文件描述符数
-
用户权限为root的Docker相关文件的访问权限应该为644或者更低权限
-
周期性检查每个主机的容器清单,并清理不必必要的容器
1.4.3、网络级别
- 通过iptables设定规则实现禁止或允许容器之间网络流量
- 允许Docker修改iptables
- 禁止将Docker绑定到其他IP/Port或者UnixSocket
- 禁止在容器上映射特权端口
- 容器上只开放所需要的端口
- 禁止在容器上使用主机网络模式(host)
1.4.4、镜像级别
- 创建本地镜像仓库服务器
- 镜像中软件都为最新版本
- 使用可信镜像文件,并通过安全通道下载
- 重新构建镜像而非对容器和镜像打补丁
- 合理管理镜像标签,及时移除不再使用的镜像
- 使用镜像扫描
- 使用镜像签名
1.4.5、容器级别
- 容器最小化,操作系统镜像最小集
- 容器以单一主进程的方式运行
- 禁止privileged标记使用特权容器
- 禁止在容器上运行ssh服务
- 以只读的方式挂载容器的根目录系统
- 明确定义属于容器的数据盘符
- 通过设置no-failure限制容器尝试重启的次数
- 限制容器中可用的进程数,以方式fork bomb
1.4.6、其他设置
- 定期对宿主机系统及容器进行安全审计
- 使用最少资源和最低权限运行容器
- 避免在同一宿主机上部署大量容器,维持一个能够管理的数量
- 监控Docker容器的使用,性能以及其他各项指标
- 增加实时 威胁检测和事件响应功能
- 使用中心和远程日志收集服务
实例:容器相关的常用安全配置方法
一、Docker TLS通信安全
- 按照Docker官方的说法,为了防止链劫持、会话劫持等问题导致Docker通信时被中间人攻击,c/s两端应该通过加密的方式通讯
1.1、创建密钥
hostnamectl set-hostname master
[root@master ~]# mkdir /tls
[root@master ~]# cd /tls/
[root@master tls]# echo "127.0.0.1 master" >> /etc/hosts
# 使用OpenSSL创建CA、服务器的端口段密钥
[root@master tls]# openssl genrsa -aes256 -out ca-key.pem 4096
Generating RSA private key, 4096 bit long modulus
...................++
...........................................................................................................................++
e is 65537 (0x10001)
Enter pass phrase for ca-key.pem: # 密码123123
Verifying - Enter pass phrase for ca-key.pem: # 确定密码
[root@master tls]# openssl req -new -x509 -days 365 -key ca-key.pem -sha256 -out ca.pem
Enter pass phrase for ca-key.pem: # 输入刚刚的密码123123
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:HN
Locality Name (eg, city) [Default City]:ZhengZhou
Organization Name (eg, company) [Default Company Ltd]:kgc
Organizational Unit Name (eg, section) []:kgc
Common Name (eg, your name or your server's hostname) []:master
Email Address []:
[root@master tls]# openssl genrsa -out server-key.pem 4096
Generating RSA private key, 4096 bit long modulus
......................................................................................................++
..................................................................................................................++
e is 65537 (0x10001)
[root@master tls]# openssl req -subj "/CN=master" -sha256 -new -key server-key.pem -out server.csr
# 由于可以通过IP地址贺DNS名称进行TLS连接,因此IP地址需要在创建证书时指定,例如,允许连接的IP为127.0.0.1、192.168.93.166
[root@master tls]# echo subjectAltName = DNS:master,IP:192.168.93.165,IP:127.0.0.1 >> extfile.cnf
# 将Docker守护程序密钥的扩展用法属性设置为仅用于服务器身份验证
[root@master tls]# echo extendedKeyUsage = serverAuth >> extfile.cnf
# 生成签名证书
[root@master tls]# openssl x509 -req -days 365 -sha256 -in server.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem -extfile extfile.cnf
Signature ok
subject=/CN=master
Getting CA Private Key
Enter pass phrase for ca-key.pem:
[root@master tls]# openssl genrsa -out key.pem 4096
Generating RSA private key, 4096 bit long modulus
.....................................................................................................................................................++
...........................................................................................................................................................................................................................................................................................++
e is 65537 (0x10001)
[root@master tls]# openssl req -subj '/CN=client' -new -key key.pem -out client.csr
[root@master tls]# echo extendedKeyUsage = clientAuth > extfile-client.cnf
# 生成签名证书
[root@master tls]# openssl x509 -req -days 365 -sha256 -in client.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out cert.pem -extfile extfile-client.cnf
Signature ok
subject=/CN=client
Getting CA Private Key
Enter pass phrase for ca-key.pem:
# 生成后,可以安全地删除两个证书签名请求贺扩展配置文件
[root@master tls]# rm -rf client.csr server.csr extfile.cnf extfile-client.cnf
# 为了数据的安全,进行对密钥的权限更改
[root@master tls]# chmod -v 0400 ca-key.pem key.pem server-key.pem
[root@master tls]# chmod -v 0444 ca.pem server-cert.pem cert.pem
# 把密钥上传到client
[root@master tls]# scp ca.pem root@192.168.93.166:/etc/docker/
[root@master tls]# scp cert.pem root@192.168.93.166:/etc/docker/
[root@master tls]# scp key.pem root@192.168.93.166:/etc/docker/
# 重新启动docker开启TLS认证加密
## 方法1:
[root@master tls]# vim /lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd --tlsverify --tlscacert=/tls/ca.pem --tlscert=/tls
/server-cert.pem --tlskey=/tls/server-key.pem -H tcp://0.0.0.0:2376 -H unix:/
//var/run/docker.sock
#ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
[root@master tls]# systemctl daemon-reload
[root@master tls]# systemctl restart docker
## 方法2:
[root@master tls]# systemctl stop docker
[root@master tls]# dockerd --tlsverify --tlscacert=ca.pem --tlscert=server-cert.pem --tlskey=server-key.pem -H=0.0.0.0:2376
1.2、client连接
hostnamectl set-hostname client
[root@client ~]# vim /etc/hosts
192.168.93.165 master
[root@client ~]# cd /etc/docker/
# 使用密钥连接master并查看master的docker版本
[root@client docker]# docker --tlsverify --tlscacert=ca.pem --tlscert=cert.pem --tlskey=key.pem -H=master:2376 version
Client: Docker Engine - Community
Version: 26.1.2
API version: 1.45
Go version: go1.21.10
Git commit: 211e74b
Built: Wed May 8 14:01:02 2024
OS/Arch: linux/amd64
Context: default
Server: Docker Engine - Community
Engine:
Version: 26.1.2
API version: 1.45 (minimum version 1.24)
Go version: go1.21.10
Git commit: ef1912d
Built: Wed May 8 13:59:55 2024
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: 1.6.31
GitCommit: e377cd56a71523140ca6ae87e30244719194a521
runc:
Version: 1.1.12
GitCommit: v1.1.12-0-g51d5e94
docker-init:
Version: 0.19.0
GitCommit: de40ad0
二、容器最小化
- 如果仅在容器中运行必要的服务,像SSH等服务是不能轻易开启去连接容器的。通常使用以下方式来进入容器
[root@master ~]# docker exec -it 容器名称 bash
三、Docker RemoteAPI访问控制
- Docker的远程调用API接口存在未授权访问漏洞,至少应显示外网访问。建议使用Socket方式访问
# docker.scok是daemon监听的套接字,容器中的进程可以通过它与docker daemon通信
[root@master ~]# dockerd -H unix:///var/run/docker.sock
或
[root@master ~]# vim /usr/lib/systemd/system/docker.service
# 进行修改即可
ExecStart=/usr/bin/dockerd -H unix:///var/run/docker.sock -H tcp://192.168.93
.165:2375
[root@master ~]# systemctl daemon-reload
[root@master ~]# systemctl restart docker
[root@master ~]# netstat -anpt | grep docker
tcp 0 0 192.168.93.165:2375 0.0.0.0:* LISTEN 13281/dockerd
- 然后在宿主机的firewalld上做IP访问控制即可。(source address 是客户端地址)
[root@master ~]# systemctl start firewalld
# 添加防火墙富规则
[root@master ~]# firewall-cmd --permanent --add-rich-rule="rule family="ipv4" source address="192.168.93.166" port protocol="tcp" port="2375" accept"
success
# 刷新防火墙
[root@master ~]# firewall-cmd --reload
success
- 然后在客户端192.168.93.166上即授权访问控制
# 在客户端控制服务端拉去一个nginx镜像
[root@client ~]# docker -H=tcp://192.168.93.165:2375 pull nginx
# 在服务端查看是否有nginx镜像
[root@master ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest 4f67c83422ec 3 days ago 188MB
四、限制流量转向
- 使用防火墙过滤器限制Docker容器的源IP地址范围与外界通信
# 拒绝10.0网段的主机与服务器通信
[root@master ~]# firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.10.0/24" reject"
五、DockerBenchforSecurity介绍
- Docker Bench for Security是一个脚本,它是在生产环境中常见的检测检查部署Docker容器的最佳安全实现,测试都是自动化的,受CIS Docker 1.13基准的启发而来
- 要使用docker-slim,从Github下载其二进制文件。二进制文件可用于Linux和Mac。下载二进制文件后,将其添加到环境变量PATH中
[root@master ~]# yum -y install git
[root@master ~]# git clone https://github.com/docker/docker-bench-security.git
Cloning into 'docker-bench-security'...
remote: Enumerating objects: 2726, done.
remote: Counting objects: 100% (804/804), done.
remote: Compressing objects: 100% (242/242), done.
remote: Total 2726 (delta 611), reused 634 (delta 554), pack-reused 1922
Receiving objects: 100% (2726/2726), 4.46 MiB | 1.50 MiB/s, done.
Resolving deltas: 100% (1889/1889), done.
[root@master ~]# cd docker-bench-security/
[root@master docker-bench-security]# sh docker-bench-security.sh
##################################################################
# --------------------------------------------------------------------------------------------
# Docker Bench for Security v1.6.0
#
# Docker, Inc. (c) 2015-2024
#
# Checks for dozens of common best-practices around deploying Docker containers in production.
# Based on the CIS Docker Benchmark 1.6.0.
# --------------------------------------------------------------------------------------------
Initializing 2024-06-02T06:50:17-04:00
Section A - Check results
[INFO] 1 - Host Configuration
[INFO] 1.1 - Linux Hosts Specific Configuration
[DEPRECATION NOTICE]: API is accessible on http://192.168.93.165:2375 without encryption.
Access to the remote API is equivalent to root access on the host. Refer
to the 'Docker daemon attack surface' section in the documentation for
more information: https://docs.docker.com/go/attack-surface/
In future versions this will be a hard failure preventing the daemon from starting! Learn more at: https://docs.docker.com/go/api-security/
[WARN] 1.1.1 - Ensure a separate partition for containers has been created (Automated)
[INFO] 1.1.2 - Ensure only trusted users are allowed to control Docker daemon (Automated)
[INFO] * Users:
[WARN] 1.1.3 - Ensure auditing is configured for the Docker daemon (Automated)
Section C - Score
[INFO] Checks: 86
[INFO] Score: -2
# 部分内容省略
##################################################################
# 输出结果中,带有不同的级别,说明问题的严重程度,最后会给出整体检查结果和评分
1、标红[WARN]是需要调整
2、标绿[PASS]表示通过检测
3、[INFO]可根据实际需要确定是否进行调整
# 一般要尽量避免出现WARN或以上的问题
六、Cgroup资源配置方法
- Docker通过Cgroup来控制容器使用的资源配额,包括CPU、内存、磁盘三大方面,基本覆盖了常见的资源配额和使用量控制
- Cgroup是ControlGroups的缩写,是Linux内核提供的一种可以限制、记录、隔离进程组所使用的物理资源(如CPU、内存、磁盘IO等等)的机制,被LXC、docker等很多项目用于实现进程资源控制。Cgroup本身是提供将进程分组话管理的功能和接口的基础结构,I/O或内存的分配控制等具体的资源管理是通过该功能来实现的。这些具体的资源管理功能称为Cgroup子系统
6.1、子系统实现
- blkio:设置限制每个块设备的输入输出控制。例如:磁盘,光盘以及usb等等
- CPU:使用调度程序为cgroup任务提供CPU的访问
- cpuacct:产生cgroup任务的CPU资源报告
- cpuset:如果是多核心的CPU,这个子系统会为cgroup任务分配单独的CPU和内存
- devices:允许或拒绝cgroup任务对设备的访问
- freezer:暂停和恢复cgroup任务
- memory:设置每个cgroup的内存限制以及生产内存资源报告
- net_cls:标记每个网络包以供cgroup方便使用
- ns:命令空间子系统
- perf_event:增加了对每个group的监测跟踪的能力,可以监测属于某个特定的group的所有线程以及运行在特定CPU上的线程
6.2、使用Stress工具测试CPU和内存
- 使用Dockerfile来创建一个基于CentOS的stress工具镜像
root@master ~]# docker pull centos:7
[root@master ~]# mkdir /root/stress
[root@master ~]# cat /root/stress/Dockerfile
FROM centos:7
MAINTAINER Wzh
RUN yum -y install wget
RUN wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
RUN wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
RUN yum -y install stress
[root@master ~]# cd /root/stress/
[root@master stress]# docker build -t centos:stress .
- 使用如下命令创建容器,命令中的–cpu-shares参数值不能保证可以获得1个vcpu或者多少GHz的CPU资源,它仅是一个弹性的加权值,值越大或者分配的资源就越多
[root@master stress]# docker run -itd --cpu-shares 100 centos:stress
- Cgroups只在容器分配的资源紧缺时,即在需要对容器的资源进行限制时,才会生效。因此,无法单纯根据某个容器的CPU份额来确定有多少CPU资源分配给它,资源分配结果取决于同时运行的其他容器的CPU分配和容器中进程运行情况
- 可以通过cpushare可以设置容器使用CPU的优先级,比如启动了两个容器及运行查看CPU百分比
# stress -c 10向容器中开启10个进程用于测试
[root@master stress]# docker run -itd --name cpu512 --cpu-shares 512 centos:stress stress -c 10
# 进入容器使用top查看资源咱占用情况
[root@master ~]# docker exec -it cpu512 bash
[root@5a30bc38e2d9 /]# top
top - 11:26:33 up 10 min, 0 users, load average: 7.89, 2.69, 0.98
Tasks: 13 total, 11 running, 2 sleeping, 0 stopped, 0 zombie
%Cpu(s): 98.8 us, 1.2 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0
KiB Mem : 3861260 total, 2380572 free, 312972 used, 1167716 buff/cache
KiB Swap: 4063228 total, 4063228 free, 0 used. 3302036 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
9 root 20 0 7312 96 0 R 20.3 0.0 0:17.46 stress
12 root 20 0 7312 96 0 R 20.3 0.0 0:17.62 stress
13 root 20 0 7312 96 0 R 20.3 0.0 0:18.17 stress
6 root 20 0 7312 96 0 R 19.9 0.0 0:17.96 stress
7 root 20 0 7312 96 0 R 19.9 0.0 0:17.58 stress
8 root 20 0 7312 96 0 R 19.9 0.0 0:17.66 stress
15 root 20 0 7312 96 0 R 19.9 0.0 0:17.59 stress
10 root 20 0 7312 96 0 R 19.6 0.0 0:17.47 stress
11 root 20 0 7312 96 0 R 19.6 0.0 0:17.58 stress
14 root 20 0 7312 96 0 R 19.6 0.0 0:18.16 stress
1 root 20 0 7312 624 528 S 0.0 0.0 0:00.01 stress
16 root 20 0 11828 1896 1492 S 0.0 0.0 0:00.01 bash
30 root 20 0 56192 2012 1444 R 0.0 0.1 0:00.00 top
- 下面设置CPU资源份额翻倍
[root@master ~]# docker run -itd --name cpu1024 --cpu-shares 1024 centos:stress stress -c 10
[root@master ~]# docker exec -it cpu1024 bash
[root@dc64e7513c1f /]# top
top - 11:28:19 up 12 min, 0 users, load average: 13.22, 5.74, 2.24
Tasks: 13 total, 11 running, 2 sleeping, 0 stopped, 0 zombie
%Cpu(s):100.0 us, 0.0 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0
KiB Mem : 3861260 total, 2369580 free, 323532 used, 1168148 buff/cache
KiB Swap: 4063228 total, 4063228 free, 0 used. 3291300 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
7 root 20 0 7312 92 0 R 14.2 0.0 0:03.71 stress
13 root 20 0 7312 92 0 R 14.2 0.0 0:03.68 stress
15 root 20 0 7312 92 0 R 14.2 0.0 0:03.50 stress
14 root 20 0 7312 92 0 R 13.9 0.0 0:03.51 stress
9 root 20 0 7312 92 0 R 12.9 0.0 0:03.32 stress
10 root 20 0 7312 92 0 R 12.6 0.0 0:03.32 stress
12 root 20 0 7312 92 0 R 12.6 0.0 0:03.29 stress
11 root 20 0 7312 92 0 R 12.3 0.0 0:03.31 stress
16 root 20 0 7312 92 0 R 12.3 0.0 0:03.33 stress
8 root 20 0 7312 92 0 R 11.9 0.0 0:03.31 stress
1 root 20 0 7312 620 528 S 0.0 0.0 0:00.01 stress
17 root 20 0 11828 1904 1496 S 0.0 0.0 0:00.01 bash
31 root 20 0 56192 2012 1444 R 0.0 0.1 0:00.00 top
# 可以看容器512CPU占用率要比1024高
七、CPU周期限制
Docker提供了–cpu-period、–cpu-quota两个参数控制容器可以分配到CPU时钟周期
-
–cpu-period:是用来指定容器对CPU的使用要在多长事件内做一次重新分配
-
–cpu-quota:是用来指定在这个周期内,最多可以有多少时间跑这个容器。与–cpu-shares不同的是,这种配置是指定一个绝对值,容器对CPU资源的使用绝对不会超过配置的值
-
cpu-period和cpu-quota的单位为微秒(us)。cpu-period的最小值为1000微妙,最大值为1秒。默认值为0.1秒。cpu-quota的值默认为-1,表示不做控制。cpu-period和cpu-quota参数一般联合使用
# 例如:容器进程需要每1秒使用单个CPU的0.2秒时间,可以将cpu-period设置为1000000(即1秒),cpu-quota设置为200000(0.2秒)
[root@master ~]# docker run -itd --cpu-period 1000000 --cpu-quota 200000 centos:stress
[root@master ~]# docker exec -it condescending_spence bash
[root@3d0f9e29cc61 /]# cat /sys/fs/cgroup/cpu/cpu.cfs_period_us
1000000
[root@3d0f9e29cc61 /]# cat /sys/fs/cgroup/cpu/cpu.cfs_quota_us
200000
八、CPUCore控制
- 对于多核CPU的服务器,Docker还可以控制容器运行使用哪些CPU内核,即使用–cpuset-cpus参数,这对具有多CPU的服务器尤其有用,可以对需要高性能计算的容器进行性能最优的配置
# 只允许这个容器使用0、1两个内核
[root@master ~]# docker run -itd --name cpu1 --cpuset-cpus 0-1 centos:stress
[root@master ~]# docker exec -it cpu1 bash
[root@ea4cd6c80f5e /]# cat /sys/fs/cgroup/cpuset/cpuset.cpus
0-1
九、CPU配额控制参数的混合使用
- 通过cpuset-cpus参数指定容器A使用CPU内核0,容器B使用CPU内核1
[root@master ~]# docker run -itd --name cpu3 --cpuset-cpus 1 --cpu-shares 512 centos:stress stress -c 1
[root@master ~]# docker exec -it cpu3 bash
[root@3a197567bf58 /]# top
top - 11:52:58 up 37 min, 0 users, load average: 20.67, 20.14, 16.51
Tasks: 4 total, 2 running, 2 sleeping, 0 stopped, 0 zombie
%Cpu(s):100.0 us, 0.0 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0
KiB Mem : 3861260 total, 2333408 free, 357196 used, 1170656 buff/cache
KiB Swap: 4063228 total, 4063228 free, 0 used. 3256448 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
7 root 20 0 7312 96 0 R 54.8 0.0 0:32.37 stress
1 root 20 0 7312 424 344 S 0.0 0.0 0:00.00 stress
8 root 20 0 11828 1900 1496 S 0.0 0.0 0:00.01 bash
22 root 20 0 56192 2000 1444 R 0.0 0.1 0:00.00 top
[root@master ~]# docker run -itd --name cpu4 --cpuset-cpus 1 --cpu-shares 1024 centos:stress stress -c 1
[root@master ~]# docker exec -it cpu4 bash
[root@080ee5432922 /]# top
top - 11:56:33 up 40 min, 0 users, load average: 21.80, 20.81, 17.52
Tasks: 4 total, 2 running, 2 sleeping, 0 stopped, 0 zombie
%Cpu(s):100.0 us, 0.0 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0
KiB Mem : 3861260 total, 2325228 free, 364704 used, 1171328 buff/cache
KiB Swap: 4063228 total, 4063228 free, 0 used. 3248516 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
7 root 20 0 7312 96 0 R 66.7 0.0 0:16.50 stress
1 root 20 0 7312 424 344 S 0.0 0.0 0:00.01 stress
8 root 20 0 11828 1896 1496 S 0.0 0.0 0:00.01 bash
22 root 20 0 56192 1964 1428 R 0.0 0.1 0:00.00 top
# 上面的centos:stress镜像安装了stress工具,用来测试CPU和内存的负载。通过在两个容器上分别执行stress -c 1命令,将会给系统一个随机负载,产生1个进程,这个进程都反复不停的计算有rand()产生随机数的平方根,知道资源耗尽
十、内存限额
与操作系统类似,容器可使用的内存包括两部分:物理内存和Swap。Docker通过下面两组参数来控制容器内存的使用量
- -m或–memory:设置内存的使用限额,例如100M、1024M
- –memory-swap:设置内存+swap的使用限额
# 执行如下命令允许该容器最多使用200M的内存和不能超过300的swap(swap100内存)
[root@master ~]# docker run -it -m 200M --memory-swap=300M progrium/stress --vm 1 --vm-bytes 280M
stress: info: [1] dispatching hogs: 0 cpu, 0 io, 1 vm, 0 hdd
stress: dbug: [1] using backoff sleep of 3000us
stress: dbug: [1] --> hogvm worker 1 [7] forked
stress: dbug: [7] allocating 293601280 bytes ...
stress: dbug: [7] touching bytes in strides of 4096 bytes ...
stress: dbug: [7] freed 293601280 bytes
stress: dbug: [7] allocating 293601280 bytes ...
stress: dbug: [7] touching bytes in strides of 4096 bytes ...
stress: dbug: [7] freed 293601280 bytes
stress: dbug: [7] allocating 293601280 bytes ...
stress: dbug: [7] touching bytes in strides of 4096 bytes ...
stress: dbug: [7] freed 293601280 bytes
stress: dbug: [7] allocating 293601280 bytes ...
stress: dbug: [7] touching bytes in strides of 4096 bytes ...
--vm 1:启动1个内存工作线程
--vm-bytes 280M:每个线程分配280内存
# 默认情况下,容器可以使用主机上的所有空闲内存。与CPU的cgroups配置类似,Docker会自动为容器在目录/sys/fs/cgroup/memory/docker<容器的完整长度 ID>中创建相应cgroup配置文件
# 因为280M在可分配的范围(300M)内,所以工作线程能够正常工作,其工作过程是
分配280M内存
释放280M内存
再分配280M内存
再释放280M内存
一直循环
# 如果让工作线程分配的内存超过300M,分配的内存超过限制,stress线程报错,容器退出
[root@master ~]# docker run -it -m 200M --memory-swap=300M progrium/stress --vm 1 --vm-bytes 310M
stress: info: [1] dispatching hogs: 0 cpu, 0 io, 1 vm, 0 hdd
stress: dbug: [1] using backoff sleep of 3000us
stress: dbug: [1] --> hogvm worker 1 [7] forked
stress: dbug: [7] allocating 325058560 bytes ...
stress: dbug: [7] touching bytes in strides of 4096 bytes ...
stress: FAIL: [1] (416) <-- worker 7 got signal 9
stress: WARN: [1] (418) now reaping child worker processes
stress: FAIL: [1] (422) kill error: No such process
stress: FAIL: [1] (452) failed run completed in 0s
十一、Blocklo的限制
- 默认情况下,所有容器能平等地读写磁盘,可以通过设置–blkio-weight参数来改变容器的vlock IO的优先级
- –blkio-weigit与–cpu-shares类似,设置的是相对权重值,默认为500。在下面的例子中,容器A读写磁盘的宽带是容器B的两倍
[root@master ~]# docker run -it --name IO_A --blkio-weight 600 centos:stress [root@c3d24510ba18 /]# cat /sys/fs/cgroup/blkio/blkio.weight
600
[root@master ~]# docker run -it --name IO_B --blkio-weight 300 centos:stress
[root@5f98b4ad5a2a /]# cat /sys/fs/cgroup/blkio/blkio.weight
300
十二、bps和iops的限制
- bps是byte per second,每秒读写的数据量。iops是io per second,每秒的IO的次数
- 可以通过以下参数控制容器的bps和iops
--device-read-bps:限制读某个设备的bps
--device-write-bsp:限制写某个设备的bps
--device-read-iops:限制某个设备的iops
--device-write-iops:限制写某个设备的iops
# 下面的示例是显示容器写/dev/sda的速率为5MB/s
[root@master ~]# docker run -it --device-write-bps /dev/sda:5MB centos:stress
# 输出完时间为20秒左右
[root@4775b55a6f0b /]# dd if=/dev/zero of=test bs=1M count=100 oflag=direct
100+0 records in
100+0 records out
104857600 bytes (105 MB) copied, 20.0017 s, 5.2 MB/s
# 不限速,不限速时间还没1秒就输出完毕了
[root@master ~]# docker run -it centos:stress
[root@ee280332da35 /]# dd if=/dev/zero of=test bs=1M count=100 oflag=direct
100+0 records in
100+0 records out
104857600 bytes (105 MB) copied, 0.0775017 s, 1.4 GB/s
# 通过dd命令测试在容器中写磁盘的速度。因为容器的文件系统是在host/dev/sda上的,在容器中写文件相当于对host/dev/sda进行写操作。另外,oflag=direct指定用direct IO方式写文件,这样--device-weite-bps才能生效
更多推荐
所有评论(0)