Docker资源隔离(namespace,cgroups)
nanshan 2024-10-30 02:54 30 浏览 0 评论
一、概述
Docker容器的本质是宿主机上的一个进程。Docker通过namespace实现了资源隔离,通过cgroups实现了资源限制,通过写时复制机制(copy-on-write)实现了高效的文件操作。
二、Linux内核的namespace机制
- namespace 机制提供一种资源隔离方案。
- PID,IPC,Network等系统资源不再是全局性的,而是属于某个特定的Namespace.
- 每个namespace下的资源对于其它的namespace下的资源是透明的,不可见的。
- Linux内核实现namespace的一个主要目的就是实现轻量级虚拟化(容器)服务,在同一个namespace下的进程可以感知彼此的变化,而对外界的进程一无所知,以达到独立和隔离的目的。
三、namespace(命名空间)可以隔离哪些?
- 文件系统需要是被隔离的
- 网络也是需要被隔离的
- 进程间的通信也要被隔离
- 针对权限,用户和用户组也需要隔离
- 进程内的PID也需要与宿主机中的PID进行隔离
- 容器也要有自己的主机名
有了以上的隔离,我们认为一个容器可以与宿主机和其他容器是隔离开的。 恰巧Linux 的namespace可以做到这些。
namespace | 隔离内容 | 系统调用参数 |
UTS | 主机名与域名 | CLONE_NEWUTS |
IPC | 信号量、消息队列和共享内存 | CLONE_NEWIPC |
Network | 网络设备、网络栈、端口等 | CLONE_NEWNET |
PID | 进程编号 | CLONE_NEWPID |
Mount | 挂载点(文件系统) | CLONE_NEWNS |
User | 用户和用户组 | CLONE_NEWUSER |
3.1、namespace的操作
- namespace的API包括clone() setns() unshare() 还有/proc下的部分文件
- 为了确定隔离的是那些namespace,需要指定以下6个参数的一个或多个 |进行分隔。6个参数就是上面表中提到的CLONE_NEWUTS、CLONE_NEWIPC、CLONE_NEWPID、CLONE_NEWNET、CLONE_NEWUSER
3.2、clone()
- 使用clone() 来创建一个独立namespace的进程,是最常见的做法,也是Docker使用namespace最基本的方法。
- clone() 是 Linux 系统调用fork() 的一种更通用的实现方式,可以通过flags来控制使用多少功能。
3.3、/proc/[pid]/ns
用户可以在/proc/[pid]/ns文件下看到指向不同namespace的文件。
$ docker ps
$ docker exec -it host2-c10 hostname
# f057b4b03eb8就是docker ID
$ ps -ef|grep f057b4b03eb8
$ ls -l /proc/3571/ns
中括号内的为namespace号。如果两个进程指向的namespace号相同,那么说明它们在同一个namespace。
设置link的作用是,即便该namespace下的所有进程都已经结束,这个namespace也会一直存在,后续的进程可以加入进来。
3.4、setns()
- Docker中 使用 docker exec命令在已经运行着的命令执行一个新的命令就需要使用setns() 。
- 通过setns()系统调用,进程从原来的的namespace加入某个已经存在的namespace
- 通常为了不影响进程的调用者,也为了使新加入的pid namespace生效,会在setns()函数执行后使用clone()创建子进程继续执行命令,让原先的进程结束运行。
int setns(int fd, in nstype);
#fd 表示要加入namespace的文件描述符。是一个指向/proc/[pid]/ns目录的文件描述符,打开目录链接可以获得
#nstype 调用者可以检查fd指向的namespace类型是否符合实际要求,该参数为0则不检查
为了把新加入的namespace利用起来,需要引入execve()系列函数,该函数可以执行用户命令,常用的就是调用/bin/bash并接受参数。
3.5、unshare()
- 通过unshare() 在原先的进程上namespace隔离
- unshare与clone很像,unshare不需要新启动一个进程,在原有的进程上就可以进行使用。但是docker并没有使用
3.6、fork() 系统调用
fork并不属于namespace的API
3.7、使用Namespace进行容器的隔离有什么缺点呢?
- 最大的缺点就是隔离不彻底,其它进程会跟docker抢占资源,虽然可以通过cgroups限制docker使用的资源,但是限制不了其它进程使用docker的资源。
- 在Linux内核中,有很多资源和对象是不能被Namespace化的,最典型的例子是:时间即如果某个容器修改了时间,那整个宿主机的时间都会随之修改
四、通过Linux的 cgroups控制docker进程资源
1)cgroups简介
cgroups是Linux的另外一个强大的内核工具,有了cgroups,不仅可以限制被namespace隔离起来的资源,还可以为资源设置权重、计算使用量、操控任务(进程或县城)启停等。说白了就是:cgroups可以限制、记录任务组所使用的物理资源(包括CPU,Memory,IO等),是构建Docker等一系列虚拟化管理工具的基石。
2)查看docker cgroups
$ ls -l /sys/fs/cgroup/*/docker -d
3)cgroups子系统介绍
cpu 子系统,主要限制进程的 cpu 使用率。
cpuacct 子系统,可以统计 cgroups 中的进程的 cpu 使用报告。
cpuset 子系统,可以为 cgroups 中的进程分配单独的 cpu 节点或者内存节点。
memory 子系统,可以限制进程的 memory 使用量。
blkio 子系统,可以限制进程的块设备 io。
devices 子系统,可以控制进程能够访问某些设备。
net_cls 子系统,可以标记 cgroups 中进程的网络数据包,然后可以使用 tc 模块(traffic control)对数据包进行控制。
freezer 子系统,可以挂起或者恢复 cgroups 中的进程。
ns 子系统,可以使不同 cgroups 下面的进程使用不同的 namespace。
4)cgroups 的作用
1、资源限制
cgroups可以对任务使用的资源(内存,CPU,磁盘等资源)总额进行限制。
如 设定应用运行时使用的内存上限,一旦超过配额就发出OOM提示
2、优先级分配
通过分配的CPU时间片数量以及磁盘IO带宽大小,实际上就相当于控制了任务运行的优先级
3、资源统计
cgroups可以统计系统的资源使用量
如CPU使用时长,内存用量等,这个功能非常适用于计费
4、任务控制
cgroups 可以对任务进行挂起、恢复等操作
5)使用stress工具压测CPU和内存
使用Dockerfile来创建一个基于Centos的stress工具镜像
$ mkdir -p /opt/stress
$ vi /opt/stress/Dockerfile
FROM centos:7
MAINTAINER chen "liugp@tom.com"
RUN yum install -y wget
RUN wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
RUN yum install -y stress
新建镜像
$ cd /opt/stress/
$ docker build -t centos:stress .
1、内存限制
CPU 限制相关参数
选项 | 描述 |
--cpuset-cpus="" | 允许使用的 CPU 集,值可以为 0-3,0,1 |
-c,--cpu-shares=0 | CPU 共享权值(相对权重) |
cpu-period=0 | 限制 CPU CFS 的周期,范围从 100ms~1s,即[1000, 1000000] |
--cpu-quota=0 | 限制 CPU CFS 配额,必须不小于1ms,即 >= 1000 |
--cpuset-mems="" | 允许在上执行的内存节点(MEMs),只对 NUMA 系统有效 |
其中--cpuset-cpus用于设置容器可以使用的 vCPU 核。-c,--cpu-shares用于设置多个容器竞争 CPU 时,各个容器相对能分配到的 CPU 时间比例。--cpu-period和--cpu-quata用于绝对设置容器能使用 CPU 时间。
1)创建容器的CPU权重控制
- 默认情况下,每个docker容器的cpu份额都是1024,单独一个容器的份额是没有意义的,只有在同时运行多个容器时,容器cpu的加权效果才能体现出现。
- cgroups只在容器分配的资源紧缺时,即需要对容器使用的资源进行限制时,才会生效。因此,无法单纯的根据某个容器的cpu份额来确定有多少cpu资源分配给它,可以通过cpu share参数可以设置容器使用cpu的优先级,比如启动了两个容器及运行查看cpu的cpu的使用百分比
创建两个容器,分别制定不同的权重比
# --cpu-shares 指定使用cpu的权重
# stress -c 指定产生子进程的个数
$ docker run -itd --name cpu512 --cpu-shares 512 centos:stress stress -c 10
$ docker run -itd --name cpu1024 --cpu-shares 1024 centos:stress stress -c 10
# 查看
$ docker exec -it cpu512 top
$ docker exec -it cpu1024 top
分别进入cpu512和cpu1024之后可以看到,%cpu的比例是1:2,符合我们设置的–cpu-shares参数。
2)cpu core控制
对于多核cpu的服务器,docker还可以控制容器运行使用那些cpu内核,以及使用–cpuset-cpus参数,这对于具有多cpu服务器尤其有用,可以对需要高性能计算的容器进行性能最优的配置。
执行以下命令需要宿主机为双核,表示创建的容器只能使用两个内核/使用哪几个CPU,最终生成cgroup的cpu内核配置如下:
$ docker run -itd --name cpu1 --cpus=2 centos:stress
# 指定使用哪几个cpu(0和3)
$ docker run -itd --name cpu1 --cpuset-cpus="0,3" centos:stress
# 指定使用哪几个cpu(0,1,2),只执行这个行
$ docker run -itd --name cpu1 --cpuset-cpus="0-2" centos:stress
查看
$ docker exec -it cpu1 bash
$ cat /sys/fs/cgroup/cpuset/cpuset.cpus
# 上面是登录到容器上查,其实也可以在宿主机上查,找到容器对应的容器ID
$ docker ps --no-trunc
$ cat /sys/fs/cgroup/cpuset/docker/7ca231149ecb0e06cbabda944697c0787c9a9e1f77565fd001aa978f4b3adede/cpuset.cpus
2、内存限制
与操作系统类似,容器可使用的内存包括两部分:物理内存和swap;Docker 默认容器交换分区的大小和内存相同;若没有设置memory和memory-swap选项,则该容器可以使用主机的所有内存,没有限制。
内存限制相关的参数
选项 | 描述 |
-m,--memory | 内存限制,格式是数字加单位,单位可以为 b,k,m,g。最小为 4M |
--memory-swap | 内存+交换分区大小总限制。格式同上。必须必-m设置的大 |
--memory-reservation | 内存的软性限制。格式同上 |
--oom-kill-disable | 是否阻止 OOM killer 杀死容器,默认没设置 |
--oom-score-adj | 容器被 OOM killer 杀死的优先级,范围是[-1000, 1000],默认为 0 |
--memory-swappiness | 用于设置容器的虚拟内存控制行为。值为 0~100 之间的整数 |
--kernel-memory | 核心内存限制。格式同上,最小为 4M |
1)允许容器最多使用200M的内存和300M的swap
$ docker run -it -m 200M --memory-swap=300M progrium/stress --vm 1 --vm-bytes 280M
#--vm 1 ,代表启动一个内存工作线程
#--vm-bytes 280 M ,代表每个线程可以分配280M内存
2)容器中的进程最多能使用 500M 内存,在这 500M 中,最多只有 50M 核心内存。
docker run -it -m 500M --kernel-memory 50M ubuntu:16.04 /bin/bash
核心内存
核心内存和用户内存不同的地方在于核心内存不能被交换出。不能交换出去的特性使得容器可以通过消耗太多内存来堵塞一些系统服务。
3、磁盘IO配额控制
相对于CPU和内存的配额控制,docker对磁盘IO的控制相对不成熟,大多数都必须在有宿主机设备的情况下使用。主要包括以下参数:
选项 | 描述 |
–device-read-bps | 限制此设备上的读速度(bytes per second),单位可以是kb、mb或者gb。 |
–device-read-iops | 通过每秒读IO次数来限制指定设备的读速度。 |
–device-write-bps | 限制此设备上的写速度(bytes per second),单位可以是kb、mb或者gb。 |
–device-write-iops | 通过每秒写IO次数来限制指定设备的写速度。 |
–blkio-weight | 容器默认磁盘IO的加权值,有效值范围为10-100。 |
–blkio-weight-device | 针对特定设备的IO加权控制。其格式为DEVICE_NAME:WEIGHT |
1)Block IO的限制
默认情况下,所有容器平等地读写磁盘,可以通过设置–blkio-weight参数来改变容器block IO的优先级。
$ docker run -it --name container_A --blkio-weight 600 centos:stress
$ cat /sys/fs/cgroup/blkio/blkio.weight
相关推荐
- Let’s Encrypt免费搭建HTTPS网站
-
HTTPS(全称:HyperTextTransferProtocoloverSecureSocketLayer),是以安全为目标的HTTP通道,简单讲是HTTP的安全版。即HTTP下加入...
- 使用Nginx配置TCP负载均衡(nginx tcp负载)
-
假设Kubernetes集群已经配置好,我们将基于CentOS为Nginx创建一个虚拟机。以下是实验种设置的详细信息:Nginx(CenOS8Minimal)-192.168.1.50Kube...
- Nginx负载均衡及支持HTTPS与申请免费SSL证书
-
背景有两台minio文件服务器已做好集群配置,一台是192.168.56.41:9000;另一台是192.168.56.42:9000。应用程序通过Nginx负载均衡调用这两台minio服务,减轻单点...
- HTTPS配置实战(https配置文件)
-
原因现在网站使用HTTPS是规范操作之一,前些日子买了腾讯云服务,同时申请了域名http://www.asap2me.top/,目前该域名只支持HTTP,想升级为HTTPS。关于HTTPS的链接过程大...
- 只有IP地址没有域名实现HTTPS访问方法
-
一般来说,要实现HTTPS,得有个注册好的域名才行。但有时候呢,咱只有服务器的IP地址,没注册域名,这种特殊情况下,也能照样实现HTTPS安全访问,按下面这些步骤来就行:第一步,先确认公网...
- 超详解:HTTPS及配置Django+HTTPS开发环境
-
众所周知HTTP协议是以TCP协议为基石诞生的一个用于传输Web内容的一个网络协议,在“网络分层模型”中属于“应用层协议”的一种。在这里我们并不研究该协议标准本身,而是从安全角度去探究使用该协议传输数...
- Godaddy购买SSL之后Nginx配置流程以及各种错误的解决
-
完整流程:参考地址:https://sg.godaddy.com/zh/help/nginx-generate-csrs-certificate-signing-requests-3601生成NGI...
- Nginx从安装到高可用,一篇搞定(nginx安装与配置详解)
-
一、Nginx安装1、去官网http://nginx.org/下载对应的nginx包,推荐使用稳定版本2、上传nginx到linux系统3、安装依赖环境(1)安装gcc环境yuminstallgc...
- 阿里云免费证书申请,配置安装,使用tomcat,支持http/https访问
-
参数说明商品类型默认已选择云盾证书服务(无需修改)。云盾证书服务类型SSL证书服务的类型。默认已选择云盾SSL证书(无需修改),表示付费版SSL证书。如果您需要免费领取或付费扩容DV单域名证书【免费试...
- 你试过两步实现Nginx的规范配置吗?极速生成Nginx配置小工具
-
NGINX是一款轻量级的Web服务器,最强大的功能之一是能够有效地提供HTML和媒体文件等静态内容。NGINX使用异步事件驱动模型,在负载下提供可预测的性能。是当下最受欢迎的高性能的Web...
- 从零开始搭建HTTPS服务(搭建https网站)
-
搭建HTTPS服务的最初目的是为了开发微信小程序,因为wx.request只允许发起HTTPS请求,并且还必须和指定的域名进行网络通信。要从零开始搭建一个HTTPS的服务需要下面4...
- 群晖NAS使用官网域名和自己的域名配置SSL实现HTTPS访问
-
安全第一步,群晖NAS使用官网域名和自己的域名配置SSL实现HTTPS访问【新手导向】NAS本质还是一个可以随时随地访问的个人数据存储中心,我们在外网访问的时候,特别是在公网IP下,其实会面临着很多安...
- 让网站快速升级HTTPS协议提高安全性
-
为什么用HTTPS网络安全越来越受到重视,很多互联网服务网站,都已经升级改造为https协议。https协议下数据包是ssl/tcl加密的,而http包是明文传输。如果请求一旦被拦截,数据就会泄露产生...
- 用Https方式访问Harbor-1.9版本(https访问流程)
-
我上周在头条号写过一篇原创文章《Docker-Harbor&Docker-kitematic史上最详细双系统配置手册》,这篇算是它的姊妹篇吧。这篇文章也将用到我在头条写的另一篇原创文章的...
- 如何启用 HTTPS 并配置免费的 SSL 证书
-
在Linux服务器上启用HTTPS并配置免费的SSL证书(以Let'sEncrypt为例)可以通过以下步骤完成:---###**一、准备工作**1.**确保域名已解析**...
你 发表评论:
欢迎- 一周热门
-
-
极空间如何无损移机,新Z4 Pro又有哪些升级?极空间Z4 Pro深度体验
-
如何在安装前及安装后修改黑群晖的Mac地址和Sn系列号
-
爱折腾的特斯拉车主必看!手把手教你TESLAMATE的备份和恢复
-
10个免费文件中转服务站,分享文件简单方便,你知道几个?
-
[常用工具] OpenCV_contrib库在windows下编译使用指南
-
日本海上自卫队的军衔制度(日本海上自卫队的军衔制度是什么)
-
Ubuntu系统Daphne + Nginx + supervisor部署Django项目
-
【系统配置】信创终端挂载NAS共享全攻略:一步到位!
-
WindowsServer2022|配置NTP服务器的命令
-
UOS服务器操作系统防火墙设置(uos20关闭防火墙)
-
- 最近发表
- 标签列表
-
- linux 查询端口号 (58)
- docker映射容器目录到宿主机 (66)
- 杀端口 (60)
- yum更换阿里源 (62)
- internet explorer 增强的安全配置已启用 (65)
- linux自动挂载 (56)
- 禁用selinux (55)
- sysv-rc-conf (69)
- ubuntu防火墙状态查看 (64)
- windows server 2022激活密钥 (56)
- 无法与服务器建立安全连接是什么意思 (74)
- 443/80端口被占用怎么解决 (56)
- ping无法访问目标主机怎么解决 (58)
- fdatasync (59)
- 405 not allowed (56)
- 免备案虚拟主机zxhost (55)
- linux根据pid查看进程 (60)
- dhcp工具 (62)
- mysql 1045 (57)
- 宝塔远程工具 (56)
- ssh服务器拒绝了密码 请再试一次 (56)
- ubuntu卸载docker (56)
- linux查看nginx状态 (63)
- tomcat 乱码 (76)
- 2008r2激活序列号 (65)