選單

Rust 中的容器執行時——第二部分

關注微信公眾號《雲原生CTO》更多雲原生乾貨等你來探索

專注於  分享

提供優質  影片技術培訓

,及技術疑難問題

Rust 中的容器執行時——第二部分

雲原生技術分享不僅僅侷限於、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、 和 等

Rust 中的容器執行時——第二部分

Rust 中的容器執行時——第二部分

Rust 中的容器執行時——第二部分

本系列的第一部分描述了檔案系統佈局以及執行時如何將容器程序囚禁在容器的根檔案系統中。

第二部分更深入地探討了實現,並展示了執行時如何建立子程序以及它們如何通訊,直到使用者定義的程序啟動。它還將描述如何設定偽終端並展示其重要性套接字。

到本部分結束時,我們應該有一個可與互操作的基本執行時。

Clone

第部分簡要解釋了系統呼叫。它就像,但有更多選項來控制子程序。實際上,的一些實現將呼叫傳播到。除了控制執行上下文的哪些部分從父程序共享之外,克隆呼叫為我們提供了為子堆疊建立單獨記憶體塊的可能性。的實現具有以下簽名:

如果指定了引數,將在子程序終止時傳送回父程序。下面是描述命令和父子關係的程式碼片段:

建立命令的基本佈局

從上面的觀點來看,一個問題是父母和孩子之間的溝通。在生成執行緒的情況下,可以說建立一個記憶體可以解決這個問題(對提供了出色的支援)。在我們的示例中,情況並非如此,因為它正在建立(或者更好地說是克隆)一個具有獨立記憶體空間的新程序。

說明 : https://doc。rust-lang。org/std/sync/mpsc/index。html

程序間通訊()是一組允許程序彼此通訊的技術。最廣泛使用的兩種是:

共享記憶體

套接字

在我們的示例中,我們將使用套接字()在父程序和子程序之間建立一個“Client——>Server端的”。容器程序將繫結到套接字,並偵聽來自父程序的傳入連線。當執行的不同部分透過或失敗時,兩個程序都將使用套接字連線來通知對方。當呼叫命令時,套接字連線也可以派上用場,通知容器程序啟動使用者定義的程式。下圖更好地描述了“協議”:

Rust 中的容器執行時——第二部分

執行時和容器程序通訊

Unix 套接字

對於那些不熟悉的人來說,這個特性有望令人興奮(至少對我來說是)。套接字是一種程序間通訊機制,它在執行在同一臺機器上的程序之間建立雙向資料交換通道。可以將它們視為不使用網路堆疊傳送和接收資料的套接字,而是檔案系統上的檔案。

在容器執行時的情況下,套接字為執行時父程序和子程序提供雙向資料交換。該交換通道對於容器執行時至關重要!如果子程序中出現問題怎麼辦?父程序如何繼續?或者孩子如何知道啟動命令何時被呼叫?

出於這些目的,容器執行時實現了通道。這些是使用域套接字的雙向通道。一個程序充當“端”,其他程序(稱為“端”)連線到伺服器程序。

簡而言之,這裡有一個關於程式碼外觀的粗略概念:

Unix (domain) Sockets解釋 : https://man7。org/linux/man-pages/man7/unix。7。html

在中使用套接字的通道

伺服器呼叫新方法並繫結到檔案。然後它呼叫並等待傳入的連線。另一方面,客戶端只是呼叫同一個檔案的,在此之後,伺服器和客戶端可以交換訊息。最後,兩個程序都呼叫,通訊就完成了。請注意,我使用了套接字,因為訊息是按順序排列的,它是基於連線的,並且訊息會立即全部重新整理(與相反)。

終端

為了在容器啟動後與容器進行良好的互動,如果使用者請求終端,執行時應該能夠提供終端介面。當執行這樣的命令時:

您將看到命令向谷歌的傳送請求的輸出。命令的輸出是透過管道傳輸的,但是當我們想要停止命令(使用)時,什麼也不會發生。這是因為當按下鍵組合時,訊號被髮送給,而不是將命令傳遞給實際的容器程序。

另一方面,執行時:

並按,命令立即終止,就像在主機上執行一樣。這是為什麼呢?

這是因為在第一個示例中,容器程序沒有例項化的終端,因此使用者和都無法透過將訊號轉發到容器。幸運的是,該選項在檔案中設定了標誌。之後,容器執行時有責任建立一個所謂的“偽終端”()。

為簡化起見,是一對(主從)通訊裝置,其行為類似於真正的終端。從文字輸入到處理訊號,任何傳送到主機的命令都會被轉發到從機端。是核心的一個非常重要且常用的特性(使用它!)。現在很簡單

SIGINT訊號: https://dsa。cs。tsinghua。edu。cn/oj/static/unix_signal。html

“偽終端”(pty):https://linux。die。net/man/7/pty

如果terminal: true容器執行時建立一個 PTY

從屬描述符進入子程序

主描述符進入呼叫程序(在本例中為 Docker)

但是子程序如何將主描述符傳送給呢?

嘆息……這是一個真正的需要找出解決方案超出了執行時規範的範圍。開發了一個解決方案,此處描述了其步驟。

PITA : https://www。allacronyms。com/PITA/Pain_In_The_Ass

runc解決方案 : https://github。com/opencontainers/runc/blob/master/docs/terminals。md#detached-new-terminal

我們的朋友套接字來幫忙了。建立一個域套接字並將其作為引數傳遞給容器執行時。在容器執行時建立後,它使用將主端傳送到同一個套接字。

SCM_RIGHTS : https://man7。org/linux/man-pages/man3/cmsg。3。html

結論

最後,我們有一個隨時可以測試的容器執行時!

這部分解釋了克隆系統呼叫以及它如何將執行上下文與父程序分離。它還具有靈活的,以便我們可以為程序指定新堆疊。

域套接字在這裡發揮著重要作用,因為它們同步整個父子通訊並在雙方出現錯誤時處理潛在場景。

第二部分總結了系列中的容器執行時。實驗性容器執行時的整個原始碼可以在這個上找到。隨意提出問題或指出實施中有趣的事情。

Github Repo: https://github。com/penumbra23/pura

5。3 參考資料

Clone man page[1]

Unix Domain Sockets[2]

runc terminal modes[3]

參考資料[1]

Clone man page:https://man7。org/linux/man-pages/man2/clone。2。html

[2]

Unix Domain Sockets:https://man7。org/linux/man-pages/man7/unix。7。html

[3]

runc terminal modes:https://github。com/opencontainers/runc/blob/master/docs/terminals。md