本文會介紹 Bazel 中的沙箱機制、安裝 sandboxfs
及偵錯
實作沙箱環境
沙箱機制是一種權限限制策略,可將處理程序與系統中的其他處理程序或資源隔離。對於 Bazel,這表示限制檔案系統存取權。
Bazel 的檔案系統沙箱會在僅工作目錄中執行處理程序 包含已知的輸入內容,因此編譯器和其他工具不會看到來源 使用者不得存取這些檔案,除非他們知道這些檔案的絕對路徑。
沙箱不會以任何方式隱藏主機環境。程序可自由地 存取檔案系統中的所有檔案。不過,在支援使用者命名空間的平台上,程序無法修改工作目錄以外的任何檔案。這可確保建構圖表沒有隱藏的依附元件,以免影響建構的可複製性。
具體來說,Bazel 會為每個動作建構 execroot/
目錄,並在執行時充當動作的工作目錄。execroot/
包含動作的所有輸入檔案,並做為任何產生的輸出內容的容器。接著,Bazel 會使用作業系統提供的技術 (Linux 上的容器和 macOS 上的 sandbox-exec
),限制 execroot/
中的動作。
沙盒化的原因
如未宣告動作沙箱,Bazel 無法得知工具是否使用未宣告的 (在該檔案的依附元件中,沒有明確列出的檔案) 動作)。當其中一個未宣告的輸入檔案發生變更時,Bazel 仍會認為版本為最新狀態,因此不會重新建構動作。這可能會導致增量建構作業不正確。
若是以不正確的方式重複使用快取項目,將會在遠端快取期間發生問題。A 罩杯 如果共用快取中有錯誤的快取項目,會影響專案的每位開發人員, 並清除整個遠端快取並非可行的解決方案。
沙箱機制會模仿遠端執行的行為 (如果建構能順利運作) 也支援遠端執行藉由 遠端執行上傳所有必要檔案 (包括本機工具),您可以 相較於 2018 年 不必在每次安裝時 來試用新的編譯器,或變更現有工具。
採用哪種沙箱策略
利用
策略標記。使用 sandboxed
策略可讓 Bazel 選取下列所列的其中一個沙箱實作,並優先採用特定作業系統的沙箱,而非較不密封的通用沙箱。永久工作站會在您通過測試時,在一般沙箱中執行
--worker_sandboxing
旗標。
local
(又稱為 standalone
) 策略不執行任何類型的沙箱作業。
它只會執行動作的指令列,並將工作目錄設定為
工作區的執行者
processwrapper-sandbox
是不需要任何測試機制的沙箱策略
「進階」功能 - 立即適用於任何現成的 POSIX 系統,這項服務
會建立沙箱目錄,包含指向原始版本的符號連結
來源檔案,使用工作目錄集執行動作的指令列
遷移至這個目錄 (而非 execroot),再移動已知的輸出構件
並刪除沙箱。這樣一來,
操作,導致使用者不小心透過
釋放的 execroot 以及未知的輸出檔案
linux-sandbox
則進一步在 processwrapper-sandbox
上方建構。與 Docker 在幕後執行的操作類似,它會使用 Linux 命名空間 (使用者、掛載、PID、網路和 IPC 命名空間) 將動作與主機隔離。也就是說,除了沙箱目錄之外,整個檔案系統都會設為唯讀,因此動作不會意外修改主機檔案系統中的任何內容。這可避免錯誤測試等情況意外觸發
-rf 是您的 $HOME 目錄。或者,您也可以防止動作
存取網路linux-sandbox
會使用 PID 命名空間,避免動作看到任何其他程序,並可靠在結尾處終止所有程序 (甚至是動作產生的守護進程)。
darwin-sandbox
很類似,但適用於 macOS。它使用 Apple 的 sandbox-exec
工具,大致達到與 Linux 沙箱相同的效果。
linux-sandbox
和 darwin-sandbox
都不適用於「巢狀」
因作業平台所提供機制的限制
有些人會將 Cloud Storage 視為檔案系統
但實際上不是由於 Docker 也會使用 Linux 命名空間來執行容器魔法,因此您無法輕易在 Docker 容器中執行 linux-sandbox
,除非您使用 docker run --privileged
。在 macOS 上,您無法在 sandbox-exec
已加上沙箱的處理程序因此,在這類情況下
會自動改回使用 processwrapper-sandbox
這樣會發生建構錯誤,例如避免不小心使用
執行策略較不嚴格的執行策略 — 明確修改執行清單
Bazel 嘗試使用的策略 (例如 bazel build
--spawn_strategy=worker,linux-sandbox
)。
動態執行通常需要沙箱才能在本機執行。如要選擇不採用,請傳遞 --experimental_local_lockfree_output
標記。動態執行作業會在背景靜默沙箱化持續性工作站。
採用沙箱機制的缺點
沙箱作業需要額外的設定及拆解成本。這筆費用有多大 實際速度取決於許多因素,包括構建形狀 也能確保主機 OS 的效能對於 Linux,沙箱建構作業的速度通常只會慢上幾個百分點。設定
--reuse_sandbox_directories
可降低設定和拆除成本。沙箱機制實際上會有效停用工具的所有快取。您可以使用持續性工作站來緩解這個問題,但代價是沙箱保證較弱。
多重工作站需要明確的工作站支援才能進行沙箱處理。不支援多工沙箱的工作站將 動態執行下的單面工作站,可能會耗用額外的記憶體。
sandboxfs
sandboxfs
是 FUSE 檔案系統,可在不犧牲時間效率的情況下,提供基礎檔案系統的任意檢視畫面。Bazel 會使用 sandboxfs
為每個動作立即產生 execroot/
,避免發出數千個系統呼叫的成本。請注意,execroot/
內之後的 I/O 可能會
但由於 FUSE 負擔,因此速度較慢。
安裝 Sandboxf
請按照下列步驟安裝 sandboxfs
,並使用
它:
下載
下載並安裝
sandboxfs
後,sandboxfs
二進位檔就會位於 PATH
中。
執行 sandboxfs
- (僅限 macOS) 安裝 OSXFUSE。
(僅限 macOS) 執行:
sudo sysctl -w vfs.generic.osxfuse.tunables.allow_other=1
請在安裝完成後和每次重新啟動後完成這項操作,以便確保 核心 macOS 系統服務可透過沙箱運作。
使用
--experimental_use_sandboxfs
執行 Bazel 建構作業。bazel build target --experimental_use_sandboxfs
疑難排解
如果您看到 local
而非 darwin-sandbox
或 linux-sandbox
做為執行動作的註解,這可能表示已停用沙箱功能。傳遞 --genrule_strategy=sandboxed --spawn_strategy=sandboxed
即可啟用。
偵錯
請按照下列策略,對沙箱相關問題進行偵錯。
已停用的命名空間
在某些平台上,例如
Google Kubernetes Engine
叢集節點或 Debian,使用者命名空間會預設為停用,這是因為
安全疑慮。如果 /proc/sys/kernel/unprivileged_userns_clone
檔案存在且包含 0,您可以執行以下命令來啟用使用者命名空間:
sudo sysctl kernel.unprivileged_userns_clone=1
規則執行失敗
由於系統設定,沙箱可能會無法執行規則。如果您看到 namespace-sandbox.c:633: execvp(argv[0], argv): No such file or
directory
之類的訊息,請嘗試使用 --strategy=Genrule=local
停用 genrules 的沙箱,並使用 --spawn_strategy=local
停用其他規則。
建構失敗的詳細偵錯資訊
如果建構失敗,請使用 --verbose_failures
和 --sandbox_debug
Bazel 會顯示建構失敗時的確切執行指令,包括
用來設定沙箱
錯誤訊息示例:
ERROR: path/to/your/project/BUILD:1:1: compilation of rule
'//path/to/your/project:all' failed:
Sandboxed execution failed, which may be legitimate (such as a compiler error),
or due to missing dependencies. To enter the sandbox environment for easier
debugging, run the following command in parentheses. On command failure, a bash
shell running inside the sandbox will then automatically be spawned
namespace-sandbox failed: error executing command
(cd /some/path && \
exec env - \
LANG=en_US \
PATH=/some/path/bin:/bin:/usr/bin \
PYTHONPATH=/usr/local/some/path \
/some/path/namespace-sandbox @/sandbox/root/path/this-sandbox-name.params --
/some/path/to/your/some-compiler --some-params some-target)
您現在可以檢查產生的沙箱目錄,查看 Bazel 建立了哪些檔案,然後再次執行指令,查看其行為。
請注意,使用 Bazel 並不會刪除沙箱目錄
--sandbox_debug
。除非您正在主動偵錯,否則應停用
--sandbox_debug
,因為它會隨著時間填滿磁碟。