Docker命名空間
- 2020 年 4 月 17 日
- 筆記
- docker, Docker命名空間
命名空間
命名空間( namespace )是 Linux 內核的一個強大特性,為容器虛擬化的實現帶來極大便利,利用這 特性,每個容器都可以擁有自己單獨的命名空間,運行在其中的應用都像是在獨立的作業系統環境中一樣 命名 間機制保證了容器之間彼此互不影響。
在作業系統中,包括內核、文件系統、網路、進程號( Process ID, PID )、用戶號( UserID, UID 進程間通訊( Inter Process Communication, IPC )等資源,所有的資源都是應用進程直接共享的 要想實現虛擬化,除了要實現對記憶體、 CPU 、網路 IO 、硬碟 IO 、存儲空間等的限制外,還要實現文件系統、網路、 PID UID IPC 等的相互隔離 前者相對容易實現一些,後者則需要宿主主機系統的深入支援。
隨著 Linux 系統對於命名空間功能的逐步完善,現在已經可以實現這些需求,讓進程在彼此隔離的命名空間中運行 雖然這些進程仍在共用同 個內核和某些運行時環境(runtime ,例如一些系統命令和系統庫),但是彼此是不可見的,並且認為自己是獨佔系統的
Docker 容器每次啟動時候,通過調用 func setNamespaces(daemon *Daemon, s *specs. Spec, c *container.Container) error 方法來完成對各個命名 間的配置
進程命名空間
Linux 通過進程命名 理進程號,對於同 進程(同 task struct ),在不同的命名空間中,看到的進程號不相同 個進程命名 間有一套 自己的進程號管理方法 進程命名空間是一個父子關係的結構,子空間中的進程對於父 間是可見的 fork 出的 個進程,在父命名空間和子命名空間將分別對應不同的進程號 例如,查看 Docker 服務主進程( dockerd )的進程號是 3393 ,它作為父進程啟動了 docker containerd 進程,進程號為 3398,
程式碼如下所示:
$ ps - ef lgrep docker
root 3393 1 0 Jan18 ? 00 43 02 /usr/bin/dockerd - H fd : // -H tcp://
127 . 0 . 0 . 1 : 2375 -H unix:///var/run/docker.sock
root 3398 3393 0 Jan18 ? 00 : 34 : 31 docker containerd config /var/ru口/
docker /conta nerd/conta nerd toml
新建一個 Ubuntu 容器,執行 sleep 命令 此時 docker containerd 進程作為父進程,會為每個容器啟動一個 docker containerd shim 程,作為該容器內所有進程的根進程
$ docker ru --name test d ubuntu :l6 . 04 sleep 9999
$ ps -ef lgrep docker
root 21535 3398 0 06 : 57 ? 00 : 00 : 00 docker-containerd-shim
從宿主機上查看新建容器的進程的父進程 ,正是 docker-containerd shim 進程:
$ ps -e f lgrep sleep
root 21569 21535 0 06 : 57 ? 00 : 00 : 00 sleep 9999
而在容器內的進程空 間中 則把 docker containerd-shim 進程作為 號根進程(類似宿主系統 號根進程 idle), while 進程的進程號則變為 (類似宿主系統中 號初始化進程/sbin/init 容器內只能看到 docker containerd iim 程往下的子進程空間,而無法獲知宿主機上的進程資訊:
$ docker exec -it 3a bash c 』 ps ef 』
UID PID PPID C STIME TTY TI ME CMD
root 1 0 0 06 : 57 ? 00 : 00 : 00 sleep 9999
IPC 命名空間
容器中的進程交互還是採用了 Linux 常見的進程間交互方法( Interprocess Communication, IPC ),包括訊號 、消息隊列和共 記憶體等方式PID 命名 間和 IPC 命名空間可以組合起來使用,同 IPC 命名 間內的進程可以彼此可見,允許進行交互;不同 間的進程則無法交互
網路命名空間
有了進程命名空間後,不同命名空間中的進 17-2 宿主機與容器內進程空間的關係 程號可以相互隔離,但是網路埠還是共享本地
系統的埠
通過網路命名空間,可以 現網路隔離。一個網路命名空間為進程提供了一個完全獨立的網路協議校的視圖 包括網路設備介面 1Pv4 1Pv6 協議械 IP路由 表、 防火牆規則 sockets 等, 這樣 容器的網路就能隔離開來
Docker 採用虛擬網路設備(Virtual Network Device, VND )的方式,將不同命名 間的網路設備連接到一起,默認情況下, Docker 在宿 機上創建多個虛機網橋(如 認的網橋 dockerO)容器中的虛擬網卡通過網橋進行連接。
使用 docker network ls 令可以查看 當前系統中的網橋:
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
337120b7e82e lO_ default bridge local
7b0bc9cdc8a0 bridge bridge local
8f57993d438b host host local
6d9342f43ffc none null local
使用 brctl 工具(需要 bridge utils 工具包 ,還可以 到連 到網橋 擬網口的資訊 默認分配一個網橋上的虛擬網口, 並將 dockerO IP 地址設 默認的網關, 容器發起的網路流 通過宿主機的 iptab es 規則進行轉發
$ brctl show
掛載命名空間
類似於 cbro 掛載 Mount MNT 空間可以將一個進 的根文件系 限制到
個特定的目錄下
掛載命名 間允許不同命名空 間的進程 到的 位於宿主機中不同路 ,每
個命名 間中的進程所看到的文件目 彼此是隔離的 例如, 同命名空間中的進程, 都認為自己獨佔了 個完 的根文件系統( rootfs 際上,不同命名空間中的文件彼此不受任何影響,同時也無法 響宿主機文件系統中的 他路徑
UTS 命名空間
UTS (UNIX T im e -sh aring System 命名 間允許 容器 有獨立的主機 和域 ,從而可以虛擬出一個有獨 主機 和網路空間的環境 就跟網 台獨 的主機一樣
如果沒有於動指定主機名稱 Docker 器的主機名就是返回的容器 ID 的前 節前綴,否則為指定的用戶名:
$docker run - -name testl -d ubuntu : l6 . 04 /bin/sh -c 」while t rue ; do echo h e llo
worl d ; sl eep l ; done "
alb7bdc9609ad52c6ca7cd39dl69d55ae32f8523lee22da063la20c94d7aa8db
$docker [contai ner] inspect -f {{ ". Config . Hostname 」 }} testl
alb7bdc9609a
$ docker run --hostname test2 --name test2 -d ubuntu: 16 . 04 /bin/sh c 」 while
true ; do echo hello world; sleep l; done 」
140573f8582584d8e 331368288a96a8838f4a7ed0ff7ee50824f8lbc0459677a
$docker [contai ner] inspect -f {{ .Config.Hostn ne 」 }} test2
test2
用戶命名空間
每個容器可以有不同的用戶和組 id 也就是說 可以在 器內使用特定的內部用戶執行程式,而非本地系統上存在的用戶
每個容器內部都可以有 高許可權的 root 帳號,但跟宿主主機不在一個命名 通過使用隔離的用戶命名 可以提高安全 ,避 容器內的進程獲取 外的許可權;同時通過使用不同用戶也可以進一步在容器內控制許可權
例如,下面的命令在容器內創建了 test 用戶,只有普通許可權,無法訪問更高許可權的資源:
$ docker run --rm --it ubuntu :l6 . 04 bash
root@6da1370b22a0: /# cat /pro c/1/enviro
PATH=/usr/local/sbin : /usr/local/bin: /usr/sbin: /usr/bin : /sb工口: lb nHOSTNAME=6dal37
Ob22a0TERM=xtermHOME=/root
root@6da1370b22a0 : /# useradd ms /bin/bash test
root@6da13 70b22a0 : /# su test
test@6da1370b22a0 : /$ cat /proc/1/environ
cat: /proc/1/environ: Pe ssion denied