Docker核心技术:Docker原理之Cgroups

云原生学习路线导航页(持续更新中)

本文是 Docker核心技术 系列文章:Docker原理之Cgroups,其他文章快捷链接如下:

  • 应用架构演进
  • 容器技术要解决哪些问题
  • Docker的基本使用
  • Docker是如何实现的
    • Docker核心技术:Docker原理之Namespace
    • Docker核心技术:Docker原理之Cgroups(本文)
    • Docker核心技术:Docker原理之Union文件系统

4.4.Cgroups:资源管控

4.4.1.Cgroups是什么

在这里插入图片描述

  • Cgroups是谷歌Borg系统内部做资源管控的,后来将之提供到了Linux Kernel中

  • Linux内核中,Cgroups实现

    • 在一个task中,还有另外一个属性 cgroups

    在这里插入图片描述

4.4.2.Cgroups工作机制

在这里插入图片描述

  • Cgroups实际上就是一个文件系统,在Linux的 /sys/fs/cgroup

  • Cgroup本身又有很多的子系统,包括cpu子系统 /sys/fs/cgroup/cpu、memory子系统 /sys/fs/cgroup/memory等等,每个子系统中又包括各种配置文件,配置子系统的参数

    • 比如cpu子系统中,包含多个配置文件,负责控制cpu绝对值、cpu相对值、cpu limit等等

    • 如果想要控制一个进程的cpu绝对值,就修改cgroup目录下相应的文件,就可以立即做到cpu的限额

      在这里插入图片描述

  • 如果是容器,每个容器都有自己的cgroup

  • 【🌟】cgroups的结构:树形结构

    • /sys/fs/cgroup
      • cpu子系统
        • 当前子系统的cpu配置文件
        • 每个目录:又是关联到cpu子系统 的 子系统,目录内部又会包含当前子系统的cpu配置文件
      • memory子系统

4.4.3.Cgroups包含哪些子系统

在这里插入图片描述

4.4.4.Cgroups CPU子系统

  • cpu子系统下,有很多配置,常用的配置文件如下:
    • cpu.shares:设置cpu的相对值
      • 假设一个主机有3个CPU,创建了2个cgroup
      • Cgroup1 中 cpu.shares 写512,cgroup2 中 cpu.shares写1024
      • 意味着,这两个cgroup,可以按照 512: 1024=1: 2 的比例分摊cpu的时间,即Cgroup1 会分到1个CPU、Cgroup2 会分到2个CPU
      • 不过1:2只是一个相对值,如果Cgroup2 中压根没有进程,则 Cgroup1中的进程,就可以使用超过1个CPU
    • cpu.cfs_period_us、:cpu.cfs_quota_us:相互配合,设置cpu的绝对值
      • cpu.cfs_period_us:控制cpu时间周期的长度,默认是10万,100000
      • cpu.cfs_quota_us:控制当前cgroup能拿到一个cpu时间周期的多少。
        • 默认是-1,即不限制当前cgroups下进程可使用的cpu绝对值
        • 可如果你设置 cpu.cfs_period_us为 10万,cpu.cfs_quota_us为 1万,则表示 当前cgroup中的进程,一共可以得到 1万/10万=0.1个CPU
        • 这是一个绝对值,当前cgroup下的 所有进程 占用cpu的总时间,不可超过0.1个CPU时间
    • cpuacct.usage:进行cgroup及其子cgroup下的,cpu使用情况的统计分析,可用做监控
      在这里插入图片描述

4.4.5.拓展:Linux中多个进程如何共享cpu时间片

4.4.5.1.Linux内核的调度器
  • Linux Kernel 2.6.23 以后,默认的是CFS(Completely Fair Scheduler)完全公平调度器

4.4.5.2.CFS调度器

4.4.5.3.vruntime红黑树
  • 进程初始化时,为进程初始化它的vruntime值,插入树中,最小值放在左边,最大值放右边
  • 每次进程调度,都拿最左边的那个进程去运行。
  • 每次调度之后,时钟周期会为被调度进程重新计算一遍vruntime,公式:vruntime=实际运行时间*1024/进程权重
    • 进程权重相当于cpu_share的那个比例值
    • 被调度的进程,vruntime会一直涨;未被调度的进程,vruntime就不会变
    • 当被调度的进程,vruntime不再是最小的了,红黑树结构就会发生变化,将下次应该调度的进程放在最左边
  • 按照这样的模式,就可以 按照进程权重的设置,为每个进程分配 公平的cpu时间

4.4.5.4.CFS进程调度在Linux Kernel中的实现
  • 感兴趣的可以深入

4.4.6.Cgroup Memory子系统

  • memory子系统下,有很多配置,常用的配置文件如下:

    • memory.soft_limit_in_bytes:内存软限制
    • memory.limit_in_bytes:内存硬限制,进程使用超过就会OOM
    • memory.oom_control:当发生OOM时,对进程执行什么操作,默认是 kill 进程。memory.oom_control中默认包含3个值:
      • oom_kill_disable 0:该参数表示是否禁用 OOM 杀死进程的功能。如果值为 0,则表示未禁用,即允许内核在 OOM 事件发生时杀死进程以释放内存。如果值为 1,则表示已禁用,即内核不会杀死进程
      • under_oom 0:该参数表示是否处于 OOM 状态。如果值为 0,则表示系统当前未处于 OOM 状态。如果值为 1,则表示系统当前处于 OOM 状态
      • oom_kill 0:该参数表示是否已经执行了 OOM 杀死进程的操作。如果值为 0,则表示尚未执行 OOM 杀死进程的操作。如果值为 1,则表示已经执行了 OOM 杀死进程的操作

4.4.7.Cgroup CPU 子系统练习

  • 练习:使用Cgroups控制进程的资源开销

  • 进入主机的 /sys/fs/cgroup/cpu目录下,mkdir cpudemo

    • 相当于我们创建了一个新的cgroup,并将其与 CPU 子系统相关联
    • linux会自动为cpudemo目录中,创建cpu的各种配置文件

    在这里插入图片描述

  • 准备一个死循环的程序,用来占用cpu资源

    • 该程序会吃掉两个cpu
    package mainfunc main(){// 协程1:死循环会吃掉一个cpugo func(){for {}}()// 主协程:死循环也会吃掉一个cpufor {}
    }
    
  • 将上面的程序写入一个main.go,然后build一下

    [root@VM-226-235-tencentos ~/zgy/code/test_cpu]# go build main.go 
    [root@VM-226-235-tencentos ~/zgy/code/test_cpu]# ls
    main  main.go
    
  • 在终端前台执行一下这个程序,终端会卡住,因为是死循环,没有任何输出

    在这里插入图片描述

  • 另外打开一个终端,使用top命令查看现在的cpu使用情况

    • 可以看到,main程序果然吃掉了2个CPU
    • main程序的pid为:19963

  • 现在我们去cpudemo cgroup下,为这个进程设置CPU限额

    [root@VM-226-235-tencentos /sys/fs/cgroup/cpu/cpudemo]# cd /sys/fs/cgroup/cpu/cpudemo# 将main程序的pid,写入cgroup.procs,表示将main进程加入这个cgroup控制
    [root@VM-226-235-tencentos /sys/fs/cgroup/cpu/cpudemo]# echo 19963 > cgroup.procs
    [root@VM-226-235-tencentos /sys/fs/cgroup/cpu/cpudemo]# cat cgroup.procs
    19963# 使用绝对值控制cpu使用额度,cpu.cfs_period_us默认是10万,向cpu.cfs_quota_us写入1万,则main进程的cpu额度将会被限制在0.1个CPU
    [root@VM-226-235-tencentos /sys/fs/cgroup/cpu/cpudemo]# echo 10000 > cpu.cfs_quota_us
    [root@VM-226-235-tencentos /sys/fs/cgroup/cpu/cpudemo]# cat cpu.cfs_period_us
    100000
    [root@VM-226-235-tencentos /sys/fs/cgroup/cpu/cpudemo]# cat cpu.cfs_quota_us
    10000
    
  • 再次top查看 main进程的cpu使用,果然被限制在0.1附近

    在这里插入图片描述

  • 可以用同样的方法,将cpu.cfs_quota_us值改成1.5万,则cpu将会被限制在0.15个

    在这里插入图片描述

  • 删除子系统

    • 注意,直接使用rm是删不掉cgroup子系统的

    • 需要先安装cgroup-tools的工具,然后执行cgdelete命令,才可以删除子系统

      # ubuntu下用apt,centos下用yum
      apt install cgroup-tools
      cd /sys/fs/cgroup/cpu
      cgdelete cpu:cpudemo
      

4.4.8.Cgroup Memory子系统练习

在这里插入图片描述

  • 进入主机的 /sys/fs/cgroup/memory目录下,mkdir memorydemo

    • 相当于我们创建了一个新的cgroup,并将其与 Memory 子系统相关联
    • linux会自动为memorydemo目录中,创建memory的各种配置文件
      在这里插入图片描述
  • 准备一个死循环的程序,用来占用memory资源。

    • 程序效果:

      • 该程序每隔1分钟就申请100MB内存,并将其填充为字符 ‘A’。共申请10次,最多申请1000MB。

      • 可以通过 watch 命令,定期执行给定的命令并显示其输出,监视内存使用情况

        watch 'ps -aux | grep malloc | grep -v grep'
        
        1. watch 命令:watch 是一个 Linux 命令,用于定期执行给定的命令并显示其输出。
        2. ps aux 命令:ps 是一个用于查看当前运行进程的命令。aux 选项用于显示所有用户的所有进程,并以紧凑的格式显示进程的信息。
        3. grep malloc 命令:grep 是一个用于在文本中搜索指定模式的命令。在这里,它用于过滤出包含 “malloc” 字符串的行,即查找正在运行的进程中使用 malloc 函数进行内存分配的进程。
        4. grep -v grep 命令:-v 选项用于反向匹配,即排除包含 “grep” 字符串的行。这是为了避免在结果中显示 grep 命令本身的进程。
      • 然后我们通过修改cgroup下的配置文件,将该进程的内存使用量,限制在100MB,超过时会OOM。

      在这里插入图片描述

    • 创建一个main.go文件

      package main//#cgo LDFLAGS:
      //char* allocMemory();
      import "C"
      import ("fmt""time"
      )func main() {// only loop 10 times to avoid exhausting the host memoryholder := []*C.char{}for i := 1; i <= 10; i++ {fmt.Printf("Allocating %dMb memory, raw memory is %d\n", i*100, i*100*1024*1025)// hold the memory, otherwise it will be freed by GCholder = append(holder, (*C.char)(C.allocMemory()))time.Sleep(time.Minute)}
      }
      
    • 创建一个 malloc.c 文件

      #include <stdlib.h>
      #include <stdio.h>
      #include <string.h>#define BLOCK_SIZE (100*1024*1024)
      char* allocMemory() {char* out = (char*)malloc(BLOCK_SIZE);memset(out, 'A', BLOCK_SIZE);return out;
      }
      
    • 创建一个Makefile

      build:CGO_ENABLED=1 GOOS=linux CGO_LDFLAGS="-static" go build
      
  • 程序写完,make build一下

    [root@VM-226-235-tencentos ~/zgy/code/test_mem]# go mod init example.com/memory-test
    [root@VM-226-235-tencentos ~/zgy/code/test_mem]# go mod tidy
    [root@VM-226-235-tencentos ~/zgy/code/test_mem]# make build
    [root@VM-226-235-tencentos ~/zgy/code/test_mem]# ls
    go.mod  main.go  Makefile  malloc.c  memory-test
    
  • 在终端前台执行一下这个程序,终端会卡住,因为进程每次循环都会sleep 1min

    在这里插入图片描述

  • 另外打开一个终端,使用 watch 'ps -aux | grep malloc | grep -v grep' 命令查看现在的 malloc 内部的进程情况

    • 可以看到,有一个进程memory-test,果然malloc了100MB的内存
    • memory-test进程的pid为:13433

    在这里插入图片描述

  • 现在我们去memorydemo cgroup下,为这个进程设置Memory限额

    [root@VM-226-235-tencentos /sys/fs/cgroup/memory/memorydemo]# cd /sys/fs/cgroup/memory/memorydemo# 将memory-test进程的pid,写入cgroup.procs,表示将 memory-test 进程加入这个cgroup控制
    [root@VM-226-235-tencentos /sys/fs/cgroup/cpu/cpudemo]# echo 13433 > cgroup.procs
    [root@VM-226-235-tencentos /sys/fs/cgroup/cpu/cpudemo]# cat cgroup.procs
    13433# 向 memory.limit_in_bytes 写入 104960000,大约是100MB
    [root@VM-226-235-tencentos /sys/fs/cgroup/cpu/cpudemo]# echo 104960000 > memory.limit_in_bytes
    [root@VM-226-235-tencentos /sys/fs/cgroup/cpu/cpudemo]# cat memory.limit_in_bytes
    104960000
    
  • 在程序执行的终端可以看到,进程已经被kill掉了,因为申请内存超过了100MB,被执行OOM了。默认的OOM策略就是kill process

    在这里插入图片描述

4.4.9.kubernetes Pod的cgroup怎么查看

  • 方法一:进入pod内部查看
    • 进入pod内部,在 /sys/fs/cgroup下面,可以看到当前pod的所有 cgroup设置
    • 比如 /sys/fs/cgroup/cpu 中,cpu.cfs_period_us、cpu.cfs_quota_us 就以绝对值的方式,设置了pod的 cpu limit
    • 再比如,在 /sys/fs/cgroup/memory 中,memory.limit_in_bytes 就设置了pod的 memory limit
  • 方法二:在pod所在主机上查看
    • 进入主机的 /sys/fs/cgroup,每一个子系统中,都有一个kubepods的目录,里面存储着所有pod的cgroup
    • kubepods里面,还有一个burstable目录,这就是所有pod cgroup的存储位置
    • 比如,查看一个pod的cpu cgroup,就应该进入:/sys/fs/cgroup/cpu/kubepods/burstable/podxxxx-xxxx/
      • 其中 podxxxx-xxxx 表示pod的uid,可以使用kubectl get pods podxxx -oyaml找到

4.4.10.kubelet启动时,报错cgroup driver不一致

在这里插入图片描述

  • 因此,启动kubelet时,有时会报错:cgroup driver不一致,kubelet启动失败。原因如下:

    • kubelet默认使用 systemd 作为 cgroup driver
    • 如果你本地还装了docker,且docker默认使用的是 cgroupfs 作为 cgroup driver。
    • 二者cgroup driver不同,kubelet出于保护,会禁止启动
  • 解决方法:将docker的cgroup driver改成和kubelet一样,比如将docker的cgroup driver改成systemd,操作如下:

    在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/382766.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Maven学习——Maven的下载、安装与配置(详细攻略!)

目录 前言 1.下载与安装 2.配置Maven的环境变量 3.配置Maven的本地仓库 4. 配置Maven的镜像远程仓库 前言 我在之前写了一篇博客&#xff0c;是介绍Maven的基本概念和下载安装&#xff0c;但是由于篇幅过长&#xff0c;Maven的下载与安装写的并不详细&#x1f436;&#x…

Windows系统设置暂停更新,暂停时间可达3000天,“永久”暂停更新,亲测有效

好多小伙伴被Windows系统的更新搞得很烦&#xff0c;经常在使用中自己下载更新包&#xff0c;占用网路资源&#xff0c;过段时间就要更新&#xff0c;特别讨厌 今天教你一招&#xff0c;可以暂停更新长达3000天&#xff0c;亲测有效 1、打开系统CMD命令执行窗口&#xff0c;输…

Ideal窗口中左右侧栏消失了

不知道大家在工作过程中有没有遇到过此类问题&#xff0c;不论是Maven项目还是Gradle项目&#xff0c;突然发现Ideal窗口右侧图标丢失了&#xff0c;同事今天突然说大象图标不见了&#xff0c;不知道怎样刷新gradle。 不要慌张&#xff0c;下面提供一些解决思路&#xff1a; 1…

超声波俱乐部:AI应用大爆发前夜,场景、闭环与LLM进化

7月13日&#xff0c;第十九期超声波俱乐部内部分享会在北京望京举行&#xff0c;本期的主题是&#xff1a;AI应用大爆发前夜&#xff0c;场景、闭环与LLM进化。 到场的嘉宾有&#xff1a;超声波创始人杨子超&#xff0c;超声波联合创始人、和牛商业创始人刘思雨&#xff0c;豆…

硅纪元视角 | 语音克隆突破:微软VALL-E 2,Deepfake新纪元!

在数字化浪潮的推动下&#xff0c;人工智能&#xff08;AI&#xff09;正成为塑造未来的关键力量。硅纪元视角栏目紧跟AI科技的最新发展&#xff0c;捕捉行业动态&#xff1b;提供深入的新闻解读&#xff0c;助您洞悉技术背后的逻辑&#xff1b;汇聚行业专家的见解&#xff0c;…

IP协议和路由转发

文章目录 IP协议IP报头网段划分特殊的IP私有IP和公有IP IP分片 路由 IP协议 IP协议提供了一种能力&#xff0c;将数据报从A主机送到B主机&#xff0c;TCP可以保证可靠性&#xff0c;所以TCP/IP协议可以将数据可靠的从A主机送到B主机。 IP报头 4位版本号(version): 指定IP协议…

Java 面试 | Redis

目录 1. 在项目中缓存是如何使用的&#xff1f;2. 为啥在项目中要用缓存&#xff1f;3. 缓存如果使用不当会造成什么后果&#xff1f;4. redis 和 memcached 有什么区别&#xff1f;5. redis 的线程模型是什么&#xff1f;6. 为什么单线程的 redis 比多线程的 memcached 效率要…

android13禁用某个usb设备

总纲 android13 rom 开发总纲说明 目录 1.前言 2.触摸设备查看 3.功能修改 3.1 禁用usb触摸 3.2 禁用usb键盘 3.3 禁用usb遥感 4.查看生效与否 5.彩蛋 1.前言 用户想要禁止使用某些usb设备,需要系统不能使用相关的usb设备,例如usb触摸屏,usb键盘,usb遥感等等usb…

Unity:PC包直接查看Log日志

PC端会输出Log日志&#xff0c;位置在&#xff1a; C:\Users\用户名\AppData\LocalLow\公司名\项目名 在这里可以找到类似的文件&#xff1a; 打开便可以看到打印。

C++ 设计模式(五)——状态模式

状态模式 序言理解源码 序言 设计模式只是一个抽象的设计模式方法&#xff0c;并不是一个固定使用的搭配&#xff0c;就算是普通switch语句&#xff0c;Map&#xff0c;乃至状态机都是状态模式的其中一种实现方法 状态模式看起来好像和策略模式差不多&#xff0c;主要是其的侧…

10道JVM经典面试题

1、 JVM中&#xff0c;new出来的对象是在哪个区&#xff1f; 2、 说说类加载有哪些步骤&#xff1f; 3、 JMM是什么&#xff1f; 4、 说说JVM内存结构&#xff1f; 5、 MinorGC和FullGC有什么区别&#xff1f; 6、 什么是STW? 7、 什么情况下会发生堆/栈溢出&#xff1f…

来参与“向日葵杯”全国教育仿真技术大赛~

可点击进行了解&#xff1a;“向日葵杯”全国教育仿真技术大赛 (sunmooc.cn) 本次大赛共分为四个赛道&#xff1a;自主命题赛道、教育知识图谱设计赛道、FPGA硬件扑克牌对抗赛道、EasyAR元宇宙空间设计赛道。 参赛对象 &#xff1a; 具有正式学籍的在校研究生&#xff0c;本科…

面试场景题系列--(1)如果系统的 QPS 突然提升 10 倍该怎么设计?--xunznux

1. 如果系统的 QPS 突然提升 10 倍该怎么设计&#xff1f; 1.1 硬件的扩展微服务的拆分 如果所有的业务包括交易系统、会员信息、库存、商品等等都夹杂在一起&#xff0c;当流量一旦起来之后&#xff0c;单体架构的问题就暴露出来了&#xff0c;机器挂了所有的业务就全部无法…

【Mysql】Docker下Mysql8数据备份与恢复

[TOC] 【Mysql】Docker下Mysql8数据备份与恢复 1 创建Mysql容器 格式 docker run -d --name容器名称 -p 宿主端口号:3306 -e MYSQL_ROOT_PASSWORDmysql密码 -e MYSQL_PASSWORDmysql密码 -e TZAsia/Shanghai -v 宿主目录-数据:/var/lib/mysql -v 宿主目录-备份数据:/back…

信息收集Part3-资产监控

Github监控 便于收集整理最新exp或poc 便于发现相关测试目标的资产 各种子域名查询 DNS,备案&#xff0c;证书 全球节点请求cdn 枚举爆破或解析子域名对应 便于发现管理员相关的注册信息 通过Server酱接口接收漏洞信息 https://sct.ftqq.com/ https://github.com/easych…

国内品牌推广全攻略:策略用对,成功翻倍!

在国内&#xff0c;推广品牌的常用策略多种多样&#xff0c;这些策略旨在提高品牌的知名度、美誉度和市场份额。 以下是一些常用的推广品牌策略&#xff1a; 码字不易&#xff0c;如果回答对您有所帮助&#xff0c;请不吝给一个三连哦&#xff01; 1. 社交媒体营销 策略说明…

计算机网络基础:3.DNS服务器、域名分类

一、DNS服务器 DNS服务器在网络中的作用类似于餐厅中的“顾客座位对照表”&#xff0c;它帮助前台&#xff08;路由器&#xff09;将顾客&#xff08;用户&#xff09;的请求转发到正确的餐桌&#xff08;目标设备&#xff09;。 (1)概念与原理 DNS的基本概念 DNS&…

攻防世界 re新手模式

Reversing-x64Elf-100 64位ida打开 看if语句&#xff0c;根据i的不同&#xff0c;选择不同的数组&#xff0c;后面的2*i/3选择数组中的某一个元素&#xff0c;我们输入的是a1 直接逆向得到就行 二维字符数组写法&#xff1a;前一个是代表有几个字符串&#xff0c;后一个是每…

深入浅出WebRTC—LossBasedBweV2

WebRTC 同时使用基于丢包的带宽估计算法和基于延迟的带宽估计算法那&#xff0c;能够实现更加全面和准确的带宽评估和控制。基于丢包的带宽估计算法主要依据网络中的丢包情况来动态调整带宽估计&#xff0c;以适应网络状况的变化。本文主要讲解最新 LossBasedBweV2 的实现。 1…

linux操作系统之线程

1.线程概念 线程是一个轻量级进程,每一个线程都属于一个进程 进程是操作系统资源分配的最小单位,而线程是CPU任务调度的最小单位 线程是一个任务执行的过程,包括创建,调度,消亡 创建:线程空间位于进程空间,进程中的线程,栈区独立,并共享进程中的数据区,文本区,堆区 调度:宏观…