Namespaces in operation, part 1: namespaces overview

Linux 3.8 合併窗口接受了 Eric Biederman 的大量用戶命名空間及相關的補丁。儘管仍有一些細節待完成,例如,許多 Linux 文件系統還不知道用戶命名空間,但用戶命名空間的實現已經在功能上完成了。
用戶命名空間的完成是一個里程碑。首先,這項工作代表了迄今爲止命名空間中最複雜實現之一的完成,因爲自從用戶命名空間實現首次實現(在Linux2.6.23中)以來,已經有五年左右的時間了。其次,命名空間工作目前處於“穩定點”的狀態,大多數現有命名空間的實現基本是完整的。但這並不代表命名空間的工作已經完成了:將來可能會添加其他命名空間,並且可能會進一步擴展現有的命名空間,例如爲內核日誌添加命名空間隔離。最後,就命名空間的使用方式而言,最近在用戶命名空間實現方面的變化是一個規則的改變:從 Linux3.8 開始,沒有特權的進程可以創建具有全部特權的用戶名稱空間,從而允許在用戶名稱空間內創建任何其他類型的命名空間。
因此,現在比較適合對名稱空間進行概述,並查看命名空間 API。這是本系列文章的第一篇:在本文中,我們概述了當前可用的命名空間;在後續文章中,我們將展示如何在程序中使用命名空間 API。
命名空間
目前,Linux 實現了六種命名空間。每種命名空間的目的是將特定的全局系統資源包裝在一個抽象中,使命名空間中的進程認爲它們擁有全局資源的獨立實例。命名空間的目標之一是支持容器的實現,容器是一種用於輕量級虛擬化(以及其他目的)的工具,它爲一組進程提供了一種錯覺,即它們是系統上唯一的進程。
接下來,我們按照命名空間實現的順序(或者至少按照實現完成的順序)來呈現命名空間。括號中列出的 CLONE_NEW* 標識符用於識別命名空間類型的常量的名稱,在使用與命名空間相關的API(clone(),unshare() 和 setns())時用到,我們將在後續文章中進行描述。
Mount namespaces(CLONE_NEWNS, Linux 2.4.19)隔離一組進程看到的文件系統掛載點集。因此,不同掛載命名空間中的進程可具有不同的文件系統層次結構視圖。隨着掛載命名空間的添加,mount() 和 umount() 系統調用不再對系統上所有進程可見的全局掛載點集的進行操作,而僅操作與調用進程相關的掛載命名空間。
掛載命名空間的用途之一是創建類似於 chroot 的限制環境。然而,與使用 chroot() 系統調用相比,掛載命名空間更安全、靈活。掛載命名空間還可用於更復雜的用途。例如,可以在主從關係中單獨設置一個掛載命名空間,以便掛載事件自動從一個命名空間傳播到另一個命名空間;例如,允許掛載在一個命名空間中的光盤設備自動出現在其它命名空間中。
掛載命名空間是第一種在 Linux 上實現的命名空間,出現在 2002 年。這解釋了相當通用的“NEWNS”名(簡稱“new namespace”):好像當時人們認爲將來不會需要其他類型的命名空間了。
UTS namespaces(CLONE_NEWUTS, Linux 2.6.19)隔離兩種系統標識符 —nodename 和 domainname — 由 uname() 返回;使用 sethostname() 和 setdomainname() 設置。在容器的上下文中,UTS 命名空間允許每個容器有自己的主機名和 NIS 域名。這有助於基於這些名稱進行初始化操作和配置腳本。術語“UTS”來源於傳遞給 uname() 的結構體的名稱:struct utsname。該結構體的名稱來源於“UNIX 時分系統”。
IPC namespaces (CLONE_NEWIPC, Linux 2.6.19) 隔離特定的進程間通信(IPC)資源,即 System V IPC 對象和(從 Linux 2.6.30 開始)POSIX 消息隊列。這些 IPC 機制的共同特點是 IPC 對象並不通過文件系統路徑名標識。每個 IPC 命名空間都有自己的 System V IPC 標識符集和 POSIX 消息隊列文件系統。
PID namespaces (CLONE_NEWPID, Linux 2.6.24) 隔離進程的 ID 號空間。換句話說,不同 PID 命名空間中的進程可以具有相同的 PID。PID 命名空間的主要好處之一是,可以在主機之間遷移容器,同時保持容器內進程的進程 ID 不變。PID 命名空間還允許每個容器有自己的 init(PID 1),它是“所有進程的祖先”,管理各種系統初始化任務,並在孤兒進程終止時獲取它們。
站在每個 PID 命名空間實例的角度來看,進程有兩個 PID:命名空間內的 PID 和主機系統上命名空間外的 PID。可以嵌套 PID 命名空間:一個進程可從其所在的PID 命名空間開始,一直到根 PID 命名空間,每層命名空間都有一個 PID。一個進程只能看到(例如,通過 /proc/pid 查看並使用 kill() 發送信號)它自己的 PID 命名空間中包含的進程以及該 PID 命名空間下面嵌套的命名空間。
Network namespaces (CLONE_NEWNET,始於 Linux 2.6.24,大部分由Linux 2.6.29 完成)隔離網絡相關的系統資源。因此,每個網絡命名空間都有自己的網絡設備、IP地址、IP路由表、/proc/net 目錄、端口號等。
從網絡的角度,網絡命名空間使得容器很有用:每個容器可以有自己的(虛擬)網絡設備和綁定到命名空間中的端口號的應用程序;主機系統中合適的路由規則可以將網絡數據包定向到與特定容器關聯的網絡設備。因此,例如,可以在同一主機系統上有多個容器化 web 服務器,每個服務器可綁定到其(每個容器)網絡命名空間中的端口 80。
User namespaces (CLONE_NEWUSER, 始於 Linux 2.6.23,完成於 Linux 3.8) 隔離用戶和組 ID 數字空間。換句話說,進程的用戶和組 ID 在用戶命名空間內外可以不同。最有趣的是,一個進程可以在用戶命名空間外有一個普通的無特權用戶 ID,同時在命名空間內有一個值 爲 0 的用戶 ID。這意味着進程對用戶命名空間內的操作具有完全的 root 權限,但對命名空間外的操作沒有權限。
從 Linux 3.8 開始,無特權的進程可以創建用戶命名空間,這爲應用程序添加了許多有趣的可能性:因爲在其他情況下,無特權的進程可以在用戶命名空間中擁有 root 權限,所以無特權的應用程序現在可以訪問之前僅限於 root 的功能。Eric Biederman 在保證用戶命名空間實現的安全性和正確性方面做了大量的工作。然而,這項工作所帶來的變化是微妙和廣泛的。因此,可能在用戶命名空間會有一些尚未發現的安全問題,這些問題有待發現和修復。
結束語
自從第一個 Linux 命名空間的實現到現在已經有十年了。從那時起,命名空間的概念擴展到了一個更通用的框架中,用於隔離一系列系統全局資源。因此,命名空間現在以容器的形式爲一個完整的輕量級虛擬化系統奠定了基礎。隨着名稱空間概念的擴展,相關 API 已經從一個系統調用(clone())和一個或兩個 /proc 文件發展到更多系統調用和 /proc 下的更多文件。這些 API 的細節將構成本文後續內容的主題。

原文:https://lwn.net/Articles/531114/
公衆號:Geek樂園
雲+社區:https://cloud.tencent.com/developer/column/4124

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章