Docker资源隔离(namespace,cgroups)
nanshan 2024-10-30 02:54 31 浏览 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
相关推荐
- 使用nginx配置域名及禁止直接通过IP访问网站
-
前段时间刚搭建好这个网站,一直没有关注一个问题,那就是IP地址也可以访问我的网站,今天就专门研究了一下nginx配置问题,争取把这个问题研究透彻。1.nginx配置域名及禁止直接通过IP访问先来看n...
- 如何在 Linux 中使用 PID 号查找进程名称?
-
在Linux的复杂世界中,进程是系统运行的核心,每个进程都由一个唯一的「进程ID」(PID)标识。无论是系统管理员在排查失控进程,还是开发者在调试应用程序,知道如何将PID映射到对应的进程名称都是一项...
- Linux服务器硬件信息查询与日常运维命令总结
-
1.服务器硬件信息查询1.1CPU信息查询命令功能描述示例lscpu显示CPU架构、核心数、线程数等lscpucat/proc/cpuinfo详细CPU信息(型号、缓存、频率)cat/proc/c...
- Ubuntu 操作系统常用命令详解(ubuntu常用的50个命令)
-
UbuntuLinux是一款流行的开源操作系统,广泛应用于服务器、开发、学习等场景。命令行是Ubuntu的灵魂,也是高效、稳定管理系统的利器。本文按照各大常用领域,详细总结Ubuntu必学...
- 从 0 到 1:打造基于 Linux 的私有 API 网关平台
-
在当今微服务架构盛行的时代,API网关作为服务入口和安全屏障,其重要性日益凸显。你是否想过,不依赖商业方案,完全基于开源组件,在Linux上构建一个属于自己的私有API网关平台?今天就带你...
- Nginx搭建简单直播服务器(nginx 直播服务器搭建)
-
前言使用Nginx+Nginx-rtmp-module在Ubuntu中搭建简单的rtmp推流直播服务器。服务器环境Ubuntu16.04相关概念RTMP:RTMP协议是RealTi...
- Linux连不上网?远程卡?这篇网络管理指南你不能错过!
-
大家好!今天咱们聊个所有Linux用户都躲不开的“老大难”——网络管理。我猜你肯定遇到过这些崩溃时刻:新装的Linux系统连不上Wi-Fi,急得直拍桌子;远程服务器SSH连不上,提示“Connecti...
- 7天从0到上线!手把手教你用Python Flask打造爆款Web服务
-
一、为什么全网开发者都在疯学Flask?在当今Web开发的战场,Flask就像一把“瑞士军刀”——轻量级架构让新手3天速成,灵活扩展能力又能支撑百万级用户项目!对比Django的“重型装甲”,Flas...
- nginx配置文件详解(nginx反向代理配置详解)
-
Nginx是一个强大的免费开源的HTTP服务器和反向代理服务器。在Web开发项目中,nginx常用作为静态文件服务器处理静态文件,并负责将动态请求转发至应用服务器(如Django,Flask,et...
- 30 分钟搞定 Docker 安装与 Nginx 部署,轻松搭建高效 Web 服务
-
在云计算时代,利用容器技术快速部署应用已成为开发者必备技能。本文将手把手教你在阿里云轻量应用服务器上,通过Docker高效部署Nginx并发布静态网站,全程可视化操作,新手也能轻松上手!一、准...
- Nginx 配置实战:从摸鱼到部署,手把手教你搞定生产级配置
-
各位摸鱼搭子们!今天咱不聊代码里的NullPointerException,改聊点「摸鱼必备生存技能」——Nginx配置!先灵魂拷问一下:写了一堆接口却不会部署?服务器被恶意请求打崩过?静态资源加载...
- 如何使用 Daphne + Nginx + supervisor部署 Django
-
前言:从Django3.0开始支持ASGI应用程序运行,使Django完全具有异步功能。Django目前已经更新到5.0,对异步支持也越来越好。但是,异步功能将仅对在ASGI下运行的应用程序可用...
- Docker命令最全详解(39个最常用命令)
-
Docker是云原生的核心,也是大厂的必备技能,下面我就全面来详解Docker核心命令@mikechen本文作者:陈睿|mikechen文章来源:mikechen.cc一、Docker基本命令doc...
- ubuntu中如何查看是否已经安装了nginx
-
在Ubuntu系统中,可以通过以下几种方法检查是否已安装Nginx:方法1:使用dpkg命令(适用于Debian/Ubuntu)bashdpkg-l|grepnginx输出...
- OVN 概念与实践(德育概念的泛化在理论和实践中有什么弊端?)
-
今天我们来讲解OVN的概念和基础实践,要理解本篇博客的内容,需要前置学习:Linux网络设备-Bridge&VethPairLinux网络设备-Bridge详解OVS+Fa...
你 发表评论:
欢迎- 一周热门
-
-
UOS服务器操作系统防火墙设置(uos20关闭防火墙)
-
极空间如何无损移机,新Z4 Pro又有哪些升级?极空间Z4 Pro深度体验
-
手机如何设置与显示准确时间的详细指南
-
NAS:DS video/DS file/DS photo等群晖移动端APP远程访问的教程
-
如何在安装前及安装后修改黑群晖的Mac地址和Sn系列号
-
如何修复用户配置文件服务在 WINDOWS 上登录失败的问题
-
一加手机与电脑互传文件的便捷方法FileDash
-
日本海上自卫队的军衔制度(日本海上自卫队的军衔制度是什么)
-
10个免费文件中转服务站,分享文件简单方便,你知道几个?
-
爱折腾的特斯拉车主必看!手把手教你TESLAMATE的备份和恢复
-
- 最近发表
-
- 使用nginx配置域名及禁止直接通过IP访问网站
- 如何在 Linux 中使用 PID 号查找进程名称?
- Linux服务器硬件信息查询与日常运维命令总结
- Ubuntu 操作系统常用命令详解(ubuntu常用的50个命令)
- 从 0 到 1:打造基于 Linux 的私有 API 网关平台
- Nginx搭建简单直播服务器(nginx 直播服务器搭建)
- Linux连不上网?远程卡?这篇网络管理指南你不能错过!
- 7天从0到上线!手把手教你用Python Flask打造爆款Web服务
- nginx配置文件详解(nginx反向代理配置详解)
- 30 分钟搞定 Docker 安装与 Nginx 部署,轻松搭建高效 Web 服务
- 标签列表
-
- 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)