1. 程式人生 > 實用技巧 >Kubernetes實戰(第二版)----第2章 理解容器(續4)

Kubernetes實戰(第二版)----第2章 理解容器(續4)

2.3 理解:什麼使容器成為可能

您應該在本地計算機上使容器保持執行,以便在以下練習中使用它,在這些練習中,將研究容器如何在不使用虛擬機器的情況下實現程序隔離。Linux核心的幾個特性使這成為可能,現在是瞭解它們的時候了。

2.3.1 使用Namespaces定製程序環境

第一個特性稱為Linux名稱空間( Linux Namespaces ),它確保每個程序都有自己的系統檢視。這意味著在容器中執行的程序將只看到系統上的一些檔案、程序和網路介面,以及不同的系統主機名,就像它在單獨的虛擬機器中執行一樣。

預設情況下,Linux OS中可用的所有系統資源,如檔案系統、程序id、使用者id、網路介面和其他資源,都在所有程序可看到和使用的相同bucket(桶)中。但是核心允許建立稱為名稱空間的額外bucket,並將資源移入其中,以便將它們組織成較小的資源集合。可以使每個資源集合僅對一個程序或一組程序可見。建立新程序時,可以指定它應該使用的名稱空間。此時程序只看到這個名稱空間中的資源,而看不到其他名稱空間中的資源。

引入可用的名稱空間型別

更具體地說,並不是只有單一型別的名稱空間。實際上有幾種型別—每種名稱空間對應一種資源型別。因此,程序不僅使用一個名稱空間,而且對每種型別都使用一個名稱空間。

名稱空間存在以下型別:

  • 掛載名稱空間(mnt)隔離掛載點(檔案系統)。

  • 程序ID名稱空間(pid)隔離程序ID。

  • 網路名稱空間(net)隔離網路裝置、堆疊、埠等。

  • 程序間通訊名稱空間(ipc)隔離程序間的通訊(這包括隔離訊息佇列、共享記憶體和其他)。

  • UNIX分時系統(UTS)名稱空間隔離系統主機名和網路資訊服務(NIS)域名。

  • 使用者ID名稱空間(User)隔離使用者和組ID。

  • Cgroup名稱空間隔離控制組的根目錄。你將在本章後面瞭解cgroups。

使用網路名稱空間為程序提供一組專用的網路介面

程序執行的網路名稱空間決定了程序可以看到哪些網路介面。每個網路介面完全屬於一個名稱空間,但是可以從一個名稱空間移動到另一個名稱空間。如果每個容器使用自己的網路名稱空間,那麼每個容器將看到自己的一組網路介面。

檢視圖2.13,瞭解如何使用網路名稱空間建立容器。假設您希望執行一個容器化的程序,併為其提供一組專用的網路介面,該網路介面只能由該程序使用。

圖2.13 網路名稱空間限制了程序使用的網路介面

最初,只有預設的網路名稱空間存在。然後為容器建立兩個新的網路介面和一個新的網路名稱空間。然後可以將網路介面從預設名稱空間移到新的名稱空間。一旦到了那裡,就可以重新命名它們,因為名稱必須在每個名稱空間中唯一。最後,程序可以在這個網路名稱空間中啟動,這允許它只看到為它建立的兩個網路介面。

如果只檢視可用的網路介面,程序無法分辨它是在容器、VM還是直接執行在裸機上的作業系統中。

使用UTS名稱空間為程序提供專用主機名

要使程序看起來像在自己的主機上執行,另一個示例是使用UTS名稱空間。它決定了在此名稱空間內執行的程序所看到的主機名和域名。通過給兩個不同的程序分配兩個不同的UTS名稱空間,可以使它們看到不同的系統主機名。對於這兩個程序來說,它們似乎執行在兩臺不同的計算機上。

理解名稱空間如何隔離程序

通過為所有可用的名稱空間型別建立一個專用的名稱空間例項並將其分配給程序,可以使程序相信它在自己的作業系統中執行。這樣做的主要原因是每個程序都有自己的環境。程序只能在自己的名稱空間中檢視和使用資源。它不能在其他名稱空間中使用。同樣地,其他程序也不能使用它的資源。容器就是這樣隔離在其中執行的程序的環境的。

在多個程序之間共享名稱空間

在下一章中,您將瞭解到,並不總是希望將容器彼此完全隔離。相關容器可能想要共享某些資源。下圖顯示了共享相同網路介面、主機和系統域名(但不共享檔案系統)的兩個程序的示例。

圖2.14 每個程序都與多個名稱空間型別相關聯,其中一些可以共享。

首先關注共享的網路裝置。這兩個程序看到並使用相同的兩個裝置(eth0和lo),因為它們使用相同的網路名稱空間。這允許它們繫結到相同的IP地址並通過環回裝置進行通訊,就像它們在不使用容器的機器上執行時一樣。這兩個程序還使用相同的UTS名稱空間,因此看到相同的系統主機名。但是,它們各自使用自己的掛載名稱空間,這意味著它們有各自的檔案系統。

總之,程序可能希望共享某些資源,而不是共享所有資源。這是可能的,因為存在不同的名稱空間型別。程序為每種型別都有一個關聯的名稱空間。

考慮到這些,有人可能會問,容器到底是什麼?一個“在容器中”執行的程序不會執行在一個類似於虛擬機器的實際封閉環境中。它只是一個程序,為它分配了七個名稱空間(每個名稱空間對應一個型別)。有些名稱空間與其他程序共享,而有些名稱空間則不共享。這意味著程序之間的邊界並不都在同一條線上。

在後面的章節中,您將瞭解如何通過使用現有容器的網路名稱空間直接在主機作業系統上執行新程序來除錯容器,同時對其他所有內容使用主機的預設名稱空間。這將允許您使用主機上可用的工具來除錯容器的網路系統,而這些工具在容器中可能不可用。

2.3.2 探索正在執行的容器的環境

如果您想看看容器內的環境是什麼樣子的呢?系統主機名是什麼,本地IP地址是什麼,檔案系統上有哪些二進位制檔案和庫可用,等等?

要在VM的情況下研究這些特性,通常需要通過ssh遠端連線到VM,並使用shell執行命令。這個過程與容器非常相似。您在容器中執行一個shell。

提示:shell的可執行檔案必須在容器的檔案系統中可用。在生產環境中執行的容器並不總是如此。

在現有容器中執行shell

你的映象所基於的Node.js映象提供了bash shell,這意味著你可以在容器中執行以下命令:


$ dockerexec-itkubia-containerbash
#這是shell的命令提示符
[email protected]:/#

這個命令在kubia-container容器中作為附加程序執行bash。該程序與主容器程序(執行的Node.js伺服器)具有相同的Linux名稱空間。通過這種方式,您可以從內部探索容器,檢視Node.js和您的應用程式在容器中執行時是如何檢視系統的。-it選項是兩個選項的簡寫:

  • -i 告訴Docker在互動模式下執行命令。

  • -t 告訴Docker分配一個偽終端(TTY),這樣您就可以正確地使用shell。

如果您想按照您習慣的方式使用shell,則需要這兩個選項。如果省略第一個,就不能執行任何命令,如果省略第二個,就不會出現命令提示符,一些命令可能會抱怨沒有設定TERM變數。

列出容器中正在執行的程序

讓我們通過在容器中執行的shell中執行ps aux命令來列出在容器中執行的程序。下面的清單顯示了該命令的輸出。


Listing2.8 Listing processes runninginthe container
[email protected]:/# ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 10.0 0.167638016504? Sl 12:310:00nodeapp.js
root 100.0 0.0 202161924? Ss 12:310:00bash
root 190.0 0.0 174921136? R+12:380:00psaux

該列表只顯示了三個程序。它們是在容器中執行的僅有的三個程序。您無法看到在主機OS或其他容器中執行的其他程序,因為容器在自己的程序ID名稱空間中執行。

在主機程序列表中檢視容器程序

如果您現在開啟另一個終端並列出主機OS本身中的程序,您還將看到在容器中執行的程序。這確認了容器中的程序實際上是在主機OS中執行的常規程序,如下面的清單所示。


#清單2.9 容器的程序在主機作業系統中執行
$ psaux |grepapp.js
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 3820.0 0.167638016504? Sl 12:310:00nodeapp.js

提示:如果使用macOS或Windows,則必須列出駐留Docker守護程序的VM中的程序,因為容器在那裡執行。在Docker Desktop中,可以使用以下命令進入VM:


docker run--net=host--ipc=host--uts=host--pid=host-it--security-opt=seccomp=unconfined--privileged--rm-v/:/host alpinechroot/host

如果您有敏銳的眼光,您可能會注意到容器中的程序id與主機上的不同。因為容器使用自己的程序ID名稱空間,所以它有自己的程序樹和自己的ID號序列。如圖所示,樹是主機的完整程序樹的一個子樹。因此,每個程序都有兩個id。

圖2.15 PID名稱空間使程序子樹顯示為具有自己編號序列的單獨程序樹

容器的檔案系統與主機和其他容器隔離

與隔離的程序樹一樣,每個容器也有一個隔離的檔案系統。如果列出容器根目錄的內容,則只顯示容器中的檔案。這包括來自容器映像的檔案和在容器操作期間建立的檔案,比如日誌檔案。下一個清單顯示了kubia container中的檔案。


#清單2.10容器有自己的檔案系統
[email protected]:/# ls /
app.js boot etc lib media opt root sbin sys usr
bin dev home lib64 mnt proc run srv tmp var

它包含app.js檔案和其他系統目錄,它們是node:12基本映象的一部分。歡迎您瀏覽容器的檔案系統。您將看到,無法從主機的檔案系統檢視檔案。這很好,因為它阻止了潛在的攻擊者通過Node.js伺服器中的漏洞訪問它們。

要離開容器,請通過執行exit命令或按Control-D離開shell,您將返回到您的主機計算機(類似於從ssh會話中登出)。

提示:在除錯容器中執行的應用程式時,像這樣進入一個正在執行的容器非常有用。當出現故障時,首先要調查的是應用程式看到的系統的實際狀態。

2.3.3 通過Linux控制組(Linux Control Groups)限制程序的資源

Linux名稱空間使得程序可以只訪問主機的一些資源,但是它們沒有限制每個程序可以消耗多少單個資源。例如,可以使用名稱空間只允許程序訪問特定的網路介面,但是不能限制程序消耗的網路頻寬。同樣,也不能使用名稱空間來限制程序可用的CPU時間或記憶體。您可能希望這樣做,以防止某個程序消耗所有CPU時間,影響關鍵的系統程序正常執行。為此,我們需要Linux核心的另一個特性。

(未完待續......) 歡迎關注公眾號,及時獲得最新翻譯內容: