1. 程式人生 > 其它 >聊聊最近很火的eBPF

聊聊最近很火的eBPF

如果非要說當前計算機領域最有前途的兩個基礎軟體技術,那非eBPF和wasm莫屬了。

什麼是eBPF?
Linux核心一直是實現監視/可觀察性,網路和安全性的理想場所。不幸的是,這通常是不切實際的,因為它需要更改核心原始碼或載入核心模組,並導致彼此堆疊的抽象層。 eBPF是一項革命性的技術,可以在Linux核心中執行沙盒程式,而無需更改核心原始碼或載入核心模組。通過使Linux核心可程式設計,基礎架構軟體可以利用現有的層,從而使它們更加智慧和功能豐富,而無需繼續為系統增加額外的複雜性層。

eBPF導致了網路,安全性,應用程式配置/跟蹤和效能故障排除等領域的新一代工具的開發,這些工具不再依賴現有的核心功能,而是在不影響執行效率或安全性的情況下主動重新程式設計執行時行為。

如果直接解釋eBPF,有點不明所以。那我們就看看有哪些基於eBPF的工程,這些工程或許你已經知道,或是已經經常使用,也許你會明白eBPF距離我們並不遙遠。

基於eBPF的專案
1:bcc

BCC是用於建立基於eBPF的高效核心跟蹤和操作程式的工具包,其中包括一些有用的命令列工具和示例。 BCC簡化了用C進行核心檢測的eBPF程式的編寫,包括LLVM的包裝器以及Python和Lua的前端。它還提供了用於直接整合到應用程式中的高階庫。

2:bpftrace

bpftrace是Linux eBPF的高階跟蹤語言。它的語言受awk和C以及DTrace和SystemTap等以前的跟蹤程式的啟發。 bpftrace使用LLVM作為後端將指令碼編譯為eBPF位元組碼,並利用BCC作為與Linux eBPF子系統以及現有Linux跟蹤功能和連線點進行互動的庫。

3:Cilium

Cilium是一個開源專案,提供基於eBPF的聯網,安全性和可觀察性。它是從頭開始專門設計的,旨在將eBPF的優勢帶入Kubernetes的世界,並滿足容器工作負載的新可伸縮性,安全性和可見性要求。

4:Falco

Falco是一種行為活動監視器,旨在檢測應用程式中的異常活動。 Falco在eBPF的幫助下稽核Linux核心層的系統。它使用其他輸入流(例如容器執行時度量標準和Kubernetes度量標準)豐富了收集的資料,並允許連續監視和檢測容器,應用程式,主機和網路活動。

5:Katran

Katran是一個C ++庫和eBPF程式,用於構建高效能的第4層負載平衡轉發平面。 Katran利用Linux核心中的XDP基礎結構來提供用於快速資料包處理的核心功能。它的效能與NIC接收佇列的數量成線性比例,並且使用RSS友好的封裝轉發到L7負載平衡器。

6:Sysdig

Sysdig是提供深層系統可見性的簡單工具,並具有對容器的原生支援。

其他基於eBPF技術的專案還有很多,比如kubectl-trace ,ply 等,這裡不再贅述。

如何編寫一個eBPF程式?
在很多情況下,不是直接使用eBPF,而是通過Cilium,bcc或bpftrace等專案間接使用eBPF,這些專案在eBPF之上提供了抽象,並且不需要直接編寫程式,而是提供了指定基於意圖的定義的功能,然後使用eBPF實施。

如果不存在更高級別的抽象,則需要直接編寫程式。 Linux核心希望eBPF程式以位元組碼的形式載入。雖然當然可以直接編寫位元組碼,但更常見的開發實踐是利用LLVM之類的編譯器套件將偽C程式碼編譯為eBPF位元組碼。

在編寫eBPF程式之前,需要簡單瞭解幾個概念。

1)map(對映) :BPF最令人著迷的方面之一是,核心上執行的程式碼和載入了該程式碼的程式可以在執行時使用訊息傳遞相互通訊。

BPF對映是駐留在核心中的鍵/值儲存。任何BPF程式都可以訪問它們。在使用者態中執行的程式也可以使用檔案描述符訪問這些對映。只要事先正確指定資料大小,就可以在對映中儲存任何型別的資料。核心將鍵和值視為二進位制 blobs,它並不關心您在對映中保留的內容。

BPF驗證程式包括多種保護措施,以確保您建立和訪問對映的方式是安全的。當我們解釋如何訪問這些對映中的資料時,我們也將解釋這些保護措施。

當然BPF對映型別有很多,比如雜湊表對映,陣列對映,Cgroup 陣列對映等,分別滿足不同的場景。

2)驗證器

BPF驗證程式也是在您的系統上執行的程式,因此,對其進行嚴格審查是確保其正確執行工作的目標。

驗證程式執行的第一項檢查是對VM即將載入的程式碼的靜態分析。第一次檢查的目的是確保程式有預期的結果。為此,驗證程式將使用程式碼建立有向迴圈圖(DAG)。驗證程式分析的每個指令將成為圖中的一個節點,並且每個節點都連結到下一條指令。驗證程式生成此圖後,它將執行深度優先搜尋(DFS),以確保程式完成並且程式碼不包含危險路徑。這意味著它將遍歷圖的每個分支,一直到分支的底部,以確保沒有遞迴迴圈。

這些是驗證器在第一次檢查期間可能拒絕您的程式碼的情形,要求有以下幾個方面:

該程式不包含控制迴圈。為確保程式不會陷入無限迴圈,驗證程式會拒絕任何型別的控制迴圈。已經提出了在BPF程式中允許迴圈的建議,但是截至撰寫本文時,沒有一個被採用。
該程式不會嘗試執行超過核心允許的最大指令數的指令。此時,可執行的最大指令數為4,096。此限制是為了防止BPF永遠執行。在第3章,我們討論如何巢狀不同的BPF程式,以安全的方式解決此限制。
該程式不包含任何無法訪問的指令,例如從未執行過的條件或功能。這樣可以防止在VM中載入無效程式碼,這也會延遲BPF程式的終止。
該程式不會嘗試越界。
驗證者執行的第二項檢查是BPF程式的空執行。這意味著驗證者將嘗試分析程式將要執行的每條指令,以確保它不會執行任何無效的指令。此執行還將檢查所有記憶體指標是否均已正確訪問和取消引用。最後,空執行向驗證程式通知程式中的控制流,以確保無論程式採用哪個控制路徑,它都會到達BPF_EXIT指令。為此,驗證程式會跟蹤堆疊中所有訪問過的分支路徑,並在採用新路徑之前對其進行評估,以確保它不會多次訪問特定路徑。經過這兩項檢查後,驗證者認為程式可以安全執行。

  1. hook : 由於eBPF是事件驅動的,所以ebpf是作用於具體的hook的。根據不同的作用,常用的有XDP,trace,套接字等。

4)幫助函式:eBPF程式無法呼叫任意核心功能。允許這樣做會將eBPF程式繫結到特定的核心版本,並使程式的相容性複雜化。取而代之的是,eBPF程式可以呼叫幫助函式,該函式是核心提供的眾所周知且穩定的API。

總結
安全,網路,負載均衡,故障分析,追蹤等領域都是eBPF的主戰場。

對於雲原生領域,Cilium 已經使用eBPF 實現了無kube-proxy的容器網路。利用eBPF解決iptables帶來的效能問題。

整個eBPF生態發展比較好,社群已經提供了諸多工具方便大家編寫自己的eBPF程式。