日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

Docker之Linux Cgroups

發布時間:2024/9/21 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Docker之Linux Cgroups 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Linux Cgroups介紹

上面是構建Linux容器的namespace技術,它幫進程隔離出自己單獨的空間,但Docker又是怎么限制每個空間的大小,保證他們不會互相爭搶呢?那么就要用到Linux的Cgroups技術。

概念

Linux Cgroups(Control Groups) 提供了對一組進程及將來的子進程的資源的限制,控制和統計的能力,這些資源包括CPU,內存,存儲,網絡等。通過Cgroups,可以方便的限制某個進程的資源占用,并且可以實時的監控進程的監控和統計信息。?

Cgroups中的三個組件:

  • cgroup
    cgroup 是對進程分組管理的一種機制,一個cgroup包含一組進程,并可以在這個cgroup上增加Linux subsystem的各種參數的配置,將一組進程和一組subsystem的系統參數關聯起來。
  • subsystem
    subsystem 是一組資源控制的模塊,一般包含有:

    • blkio 設置對塊設備(比如硬盤)的輸入輸出的訪問控制
    • cpu 設置cgroup中的進程的CPU被調度的策略
    • cpuacct 可以統計cgroup中的進程的CPU占用
    • cpuset 在多核機器上設置cgroup中的進程可以使用的CPU和內存(此處內存僅使用于NUMA架構)
    • devices 控制cgroup中進程對設備的訪問
    • freezer 用于掛起(suspends)和恢復(resumes) cgroup中的進程
    • memory 用于控制cgroup中進程的內存占用
    • net_cls 用于將cgroup中進程產生的網絡包分類(classify),以便Linux的tc(traffic controller) 可以根據分類(classid)區分出來自某個cgroup的包并做限流或監控。
    • net_prio 設置cgroup中進程產生的網絡流量的優先級
    • ns 這個subsystem比較特殊,它的作用是cgroup中進程在新的namespace fork新進程(NEWNS)時,創建出一個新的cgroup,這個cgroup包含新的namespace中進程。

    每個subsystem會關聯到定義了相應限制的cgroup上,并對這個cgroup中的進程做相應的限制和控制,這些subsystem是逐步合并到內核中的,如何看到當前的內核支持哪些subsystem呢?可以安裝cgroup的命令行工具(apt-get install cgroup-bin),然后通過lssubsys看到kernel支持的subsystem。?

    # / lssubsys -a cpuset cpu,cpuacct blkio memory devices freezer net_cls,net_prio perf_event hugetlb pids
  • hierarchy
    hierarchy 的功能是把一組cgroup串成一個樹狀的結構,一個這樣的樹便是一個hierarchy,通過這種樹狀的結構,Cgroups可以做到繼承。比如我的系統對一組定時的任務進程通過cgroup1限制了CPU的使用率,然后其中有一個定時dump日志的進程還需要限制磁盤IO,為了避免限制了影響到其他進程,就可以創建cgroup2繼承于cgroup1并限制磁盤的IO,這樣cgroup2便繼承了cgroup1中的CPU的限制,并且又增加了磁盤IO的限制而不影響到cgroup1中的其他進程。

三個組件相互的關系:

通過上面的組件的描述我們就不難看出,Cgroups的是靠這三個組件的相互協作實現的,那么這三個組件是什么關系呢??

  • 系統在創建新的hierarchy之后,系統中所有的進程都會加入到這個hierarchy的根cgroup節點中,這個cgroup根節點是hierarchy默認創建,后面在這個hierarchy中創建cgroup都是這個根cgroup節點的子節點。
  • 一個subsystem只能附加到一個hierarchy上面
  • 一個hierarchy可以附加多個subsystem
  • 一個進程可以作為多個cgroup的成員,但是這些cgroup必須是在不同的hierarchy中
  • 一個進程fork出子進程的時候,子進程是和父進程在同一個cgroup中的,也可以根據需要將其移動到其他的cgroup中。

這幾句話現在不理解暫時沒關系,后面我們實際使用過程中會逐漸的了解到他們之間的聯系的。

kernel接口:

上面介紹了那么多的Cgroups的結構,那到底要怎么調用kernel才能配置Cgroups呢?上面了解到Cgroups中的hierarchy是一種樹狀的組織結構,Kernel為了讓對Cgroups的配置更直觀,Cgroups通過一個虛擬的樹狀文件系統去做配置的,通過層級的目錄虛擬出cgroup樹,下面我們就以一個配置的例子來了解下如何操作Cgroups。?

  • 首先,我們要創建并掛載一個hierarchy(cgroup樹):

    ~ mkdir cgroup-test # 創建一個hierarchy掛載點~ sudo mount -t cgroup -o none,name=cgroup-test cgroup-test ./cgroup-test # 掛載一個hierarchy~ ls ./cgroup-test # 掛載后我們就可以看到系統在這個目錄下生成了一些默認文件 cgroup.clone_children cgroup.procs cgroup.sane_behavior notify_on_release release_agent tasks

    這些文件就是這個hierarchy中根節點cgroup配置項了,上面這些文件分別的意思是:

    • cgroup.clone_children?cpuset的subsystem會讀取這個配置文件,如果這個的值是1(默認是0),子cgroup才會繼承父cgroup的cpuset的配置。
    • cgroup.procs是樹中當前節點的cgroup中的進程組ID,現在我們在根節點,這個文件中是會有現在系統中所有進程組ID。
    • notify_on_release和release_agent會一起使用,notify_on_release表示當這個cgroup最后一個進程退出的時候是否執行release_agent,release_agent則是一個路徑,通常用作進程退出之后自動清理掉不再使用的cgroup。
    • tasks也是表示該cgroup下面的進程ID,如果把一個進程ID寫到tasks文件中,便會將這個進程加入到這個cgroup中。
  • 然后,我們創建在剛才創建的hierarchy的根cgroup中擴展出兩個子cgroup:

    cgroup-test sudo mkdir cgroup-1 # 創建子cgroup "cgroup-1"cgroup-test sudo mkdir cgroup-2 # 創建子cgroup "cgroup-1"cgroup-test tree . |-- cgroup-1 | |-- cgroup.clone_children | |-- cgroup.procs | |-- notify_on_release | `-- tasks |-- cgroup-2 | |-- cgroup.clone_children | |-- cgroup.procs | |-- notify_on_release | `-- tasks |-- cgroup.clone_children |-- cgroup.procs |-- cgroup.sane_behavior |-- notify_on_release |-- release_agent `-- tasks

    可以看到在一個cgroup的目錄下創建文件夾,kernel就會把文件夾標記會這個cgroup的子cgroup,他們會繼承父cgroup的屬性。

  • 在cgroup中添加和移動進程:
    一個進程在一個Cgroups的hierarchy中只能存在在一個cgroup節點上,系統的所有進程默認都會在根節點,可以將進程在cgroup節點間移動,只需要將進程ID寫到移動到的cgroup節點的tasks文件中。

    cgroup-1 echo $$ 7475cgroup-1 sudo sh -c "echo $$ >> tasks" # 將我所在的終端的進程移動到cgroup-1中cgroup-1 cat /proc/7475/cgroup 13:name=cgroup-test:/cgroup-1 11:perf_event:/ 10:cpu,cpuacct:/user.slice 9:freezer:/ 8:blkio:/user.slice 7:devices:/user.slice 6:cpuset:/ 5:hugetlb:/ 4:pids:/user.slice/user-1000.slice 3:memory:/user.slice 2:net_cls,net_prio:/ 1:name=systemd:/user.slice/user-1000.slice/session-19.scope

    可以看到我們當前的7475進程已經被加到了cgroup-test:/cgroup-1中。

  • 通過subsystem限制cgroup中進程的資源
    上面我們創建hierarchy的時候,但這個hierarchy并沒有關聯到任何subsystem,所以沒辦法通過那個hierarchy中的cgroup限制進程的資源占用,其實系統默認就已經把每個subsystem創建了一個默認的hierarchy,比如memory的hierarchy:

    ~ mount | grep memory cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory,nsroot=/)

    可以看到,在/sys/fs/cgroup/memory目錄便是掛在了memory subsystem的hierarchy。下面我們就通過在這個hierarchy中創建cgroup,限制下占用的進程占用的內存:

    memory stress --vm-bytes 200m --vm-keep -m 1 # 首先,我們不做限制啟動一個占用內存的stress進程memory sudo mkdir test-limit-memory && cd test-limit-memory # 創建一個cgrouptest-limit-memory sudo sh -c "echo "100m" > memory.limit_in_bytes" sudo sh -c "echo "100m" > memory.limit_in_bytes" # 設置最大cgroup最大內存占用為100mtest-limit-memory sudo sh -c "echo $$ > tasks" # 將當前進程移動到這個cgroup中test-limit-memory stress --vm-bytes 200m --vm-keep -m 1 # 再次運行占用內存200m的的stress進程

    運行結果如下(通過top監控):

    PID PPID TIME+ %CPU %MEM PR NI S VIRT RES UID COMMAND 8336 8335 0:08.23 99.0 10.0 20 0 R 212284 205060 1000 stress 8335 7475 0:00.00 0.0 0.0 20 0 S 7480 876 1000 stressPID PPID TIME+ %CPU %MEM PR NI S VIRT RES UID COMMAND 8310 8309 0:01.17 7.6 5.0 20 0 R 212284 102056 1000 stress 8309 7475 0:00.00 0.0 0.0 20 0 S 7480 796 1000 stress

    可以看到通過cgroup,我們成功的將stress進程的最大內存占用限制到了100m。?

    Docker是如何使用Cgroups的:

    我們知道Docker是通過Cgroups去做的容器的資源限制和監控,我們下面就以一個實際的容器實例來看下Docker是如何配置Cgroups的:

    ~ # docker run -m 設置內存限制~ sudo docker run -itd -m 128m ubuntu 957459145e9092618837cf94a1cb356e206f2f0da560b40cb31035e442d3df11~ # docker會為每個容器在系統的hierarchy中創建cgroup~ cd /sys/fs/cgroup/memory/docker/957459145e9092618837cf94a1cb356e206f2f0da560b40cb31035e442d3df11 957459145e9092618837cf94a1cb356e206f2f0da560b40cb31035e442d3df11 # 查看cgroup的內存限制957459145e9092618837cf94a1cb356e206f2f0da560b40cb31035e442d3df11 cat memory.limit_in_bytes 134217728957459145e9092618837cf94a1cb356e206f2f0da560b40cb31035e442d3df11 # 查看cgroup中進程所使用的內存大小957459145e9092618837cf94a1cb356e206f2f0da560b40cb31035e442d3df11 cat memory.usage_in_bytes 430080

    可以看到Docker通過為每個容器創建Cgroup并通過Cgroup去配置的資源限制和資源監控。

用go語言實現通過cgroup限制容器的資源

下面我們在上一節的容器的基礎上加上cgroup的限制,下面這個demo實現了限制容器的內存的功能:

package mainimport ("os/exec""path""os""fmt""io/ioutil""syscall""strconv" )const cgroupMemoryHierarchyMount = "/sys/fs/cgroup/memory"func main() {if os.Args[0] == "/proc/self/exe" {//容器進程fmt.Printf("current pid %d", syscall.Getpid())fmt.Println()cmd := exec.Command("sh", "-c", `stress --vm-bytes 200m --vm-keep -m 1`)cmd.SysProcAttr = &syscall.SysProcAttr{}cmd.Stdin = os.Stdincmd.Stdout = os.Stdoutcmd.Stderr = os.Stderrif err := cmd.Run(); err != nil {fmt.Println(err)os.Exit(1)}}cmd := exec.Command("/proc/self/exe")cmd.SysProcAttr = &syscall.SysProcAttr{Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWPID | syscall.CLONE_NEWNS,}cmd.Stdin = os.Stdincmd.Stdout = os.Stdoutcmd.Stderr = os.Stderrif err := cmd.Start(); err != nil {fmt.Println("ERROR", err)os.Exit(1)} else {//得到fork出來進程映射在外部命名空間的pidfmt.Printf("%v", cmd.Process.Pid)// 在系統默認創建掛載了memory subsystem的Hierarchy上創建cgroupos.Mkdir(path.Join(cgroupMemoryHierarchyMount, "testmemorylimit"), 0755)// 將容器進程加入到這個cgroup中ioutil.WriteFile(path.Join(cgroupMemoryHierarchyMount, "testmemorylimit", "tasks") , []byte(strconv.Itoa(cmd.Process.Pid)), 0644)// 限制cgroup進程使用ioutil.WriteFile(path.Join(cgroupMemoryHierarchyMount, "testmemorylimit", "memory.limit_in_bytes") , []byte("100m"), 0644)}cmd.Process.Wait() }

通過對Cgroups虛擬文件系統的配置,我們讓容器中的把stress進程的內存占用限制到了100m。

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 10861 root 20 0 212284 102464 212 R 6.2 5.0 0:01.13 stress

總結

以上是生活随笔為你收集整理的Docker之Linux Cgroups的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。