docker對哪些資源進行隔離

2022-01-28 16:00:16

docker進行隔離的資源:1、檔案系統;2、網路(Network);3、程序間的通訊;4、針對許可權的使用者和使用者組;5、程序內的PID和宿主機的PID;6、主機名與域名等。

本教學操作環境:linux5.9.8系統、docker-1.13.1版、Dell G3電腦。

Docker容器的本質

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

UTS namespace

UTS (UNIX TIme-sharing System) namespace 提供了主機和域名的隔離,這樣每個Docker容器就可以擁有獨立的主機名和域名,在網路上可以被視作一個獨立的節點,而不是宿主機上的一個程序。
Docker中,每個映象基本都以自身提供的服務名稱來命名hostname,且不會對宿主機產生任何影響。

IPC namespace

程序間通訊(Inter-Process Communication,IPC)設計的IPC資源包括常見的號誌、訊息佇列和共用記憶體。
申請IPC資源就申請了一個全域性唯一的32位元ID。
IPCnamespace中包含了系統IPC識別符號以及實現POSIX訊息佇列的檔案系統。
在同一個IPC namespace中的程序彼此可見,不同的namespace中的程序則互不可見。

PID namespace

PID namespace的隔離非常實用,他對程序PID重新編號,即兩個不同namespace下的程序可以擁有相同的PID,每個PID namespace都有自己的計數程式。
核心為所有的PID namespace維護了一個樹狀結構,最頂層的是系統初始時建立的,被稱為root namespace。新建立的PIDnamespace被稱為child namespace,而原先的PID namespace就是新建立的PID namespace的child namespace,而原來的PID namespace就是新建立的PID namespace的 parent namespace。
通過這種方式,不同的PID namespace會形成=一個層級體系,所屬的父節點可以看到子節點中的程序,並可以通過訊號等方式對子節點中的程序產生影響。但是子節點確看不到父節點PID namespace中的任何內容。

mount namespace

mount namespace通過隔離檔案系統掛載點對隔離檔案系統提供支援。
隔離後,不同的mount namespace中的檔案結構發生變化也互不影響。

network namespace

network namespace主要提供了關於網路資源的隔離,包括網路裝置,IPv4,IPv6協定棧、IP路由表、防火牆、/proc/net目錄、/sys/class/net目錄、通訊端等。

user namespace

user namespace隔離了安裝相關的識別符號和屬性

namespace的操作

namespace的API包括clone() setns() unshare() 還有/proc下的部分檔案
為了確定隔離的是那些namespace,需要指定以下6個引數的一個或多個 | 進行分隔。6個引數就是上面表中提到的CLONE_NEWUTS、CLONE_NEWIPC、CLONE_NEWPID、CLONE_NEWNET、CLONE_NEWUSER

clone()

使用clone() 來建立一個獨立namespace的程序,是最常見的做法,也是Docker使用namespace最基本的方法。

int clone(int(*child_func)(void *),void *child_stack,int flags, void *arg);

clone() 是 Linux 系統呼叫fork() 的一種更通用的實現方式,可以通過flags來控制使用多少功能。
共有20多種CLONE_*的flag,控制clone程序的方方面面。

  1. child_func 傳入子程序執行的程式主函數
  2. child_stack 傳入子程序使用的棧空間
  3. flags 標識使用哪些CLONE_*標誌位,與namespace相關的主要是上面提到的6種。
  4. args 用於傳入使用者引數

/proc/[pid]/ns

使用者可以在/proc/[pid]/ns檔案下看到指向不同namespace好的檔案。

ls -l /proc/10/ns

在這裡插入圖片描述

中括號內的為namespace號

如果兩個程序指向的namespace號相同,那麼說明他們在同一個namespace

設定link的作用是,即便該namespace下的所有程序都已經結束,這個namespace也會一直存在,後續的程序可以加入進來。
把/proc/[pid]/ns目錄檔案使用 --bind方式掛載也可以達到link的作用

touch ~/utsmount --bind /proc/10/ns/uts ~/uts

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並接受引數

unshare()

通過unshare() 在原先的程序上namespace隔離
unshare與clone很像,unshare不需要新啟動一個程序,在原有的程序上就可以進行使用。
docker並沒有使用

fork() 系統呼叫

fork並不屬於namespace的API

強大核心工具cgroups

cgroups是Linux核心提供的一種機制,這種機制可以根據需求把一系列系統任務及其子任務整合(或分隔)到按資源分等級的不同組內,從而為系統資源管理提供一個統一的框架。

cgroups是Linux的另外一個強大的核心工具,有了cgroups,不僅可以限制被namespace隔離起來的資源,還可以為資源設定權重、計算使用量、操控任務(程序或縣城)啟停等。說白了就是:cgroups可以限制、記錄任務組所使用的物理資源(包括CPU,Memory,IO等),是構建Docker等一系列虛擬化管理工具的基石。

cgroups 的作用

cgroups 為不同使用者層面的資源管理提供了一個統一介面,從單個的資源控制到作業系統層面的虛擬化,cgroups提供了4大功能。

  • 資源限制
    • cgroups可以對任務使用的資源總額進行限制。
      • 如 設定應用執行時使用的記憶體上限,一旦超過配額就發出OOM提示
  • 優先順序分配
    • 通過分配的CPU時間片數量以及磁碟IO頻寬大小,實際上就相當於控制了任務執行的優先順序
  • 資源統計
    • cgroups可以統計系統的資源使用量
      • 如CPU使用時長,記憶體用量等,這個功能非常適用於計費
  • 任務控制
    • cgroups 可以對任務進行掛起、恢復等操作

推薦學習:《》

以上就是docker對哪些資源進行隔離的詳細內容,更多請關注TW511.COM其它相關文章!