Linux 有很多面孔:如何在任何發行版上工作

Linux 有很多面孔:如何在任何發行版上工作

創建適用於任何發行版的備份應用程式並不是一件容易的事。 為了確保 Veeam Agent for Linux 在從 Red Hat 6 和 Debian 6 到 OpenSUSE 15.1 和 Ubuntu 19.04 的發行版上運行,您必須解決一系列問題,特別是考慮到該軟體產品包含核心模組。

本文根據會議演講資料撰寫 Linux 彼得 2019.

Linux 不僅僅是最受歡迎的作業系統之一。 從本質上講,這是一個平台,您可以在此基礎上製作一些獨特的、屬於您自己的東西。 因此,Linux 有許多發行版,它們的軟體元件集各不相同。 這裡出現了一個問題:為了使軟體產品能夠在任何發行版上運行,您必須考慮每個發行版的功能。

包管理器。 .deb 與 .rpm

讓我們從不同發行版分發產品的明顯問題開始。
分發軟體產品的最典型方法是將軟體包放在儲存庫中,以便系統內建的軟體包管理器可以從那裡安裝它。
但是,我們有兩種流行的包格式: и DEB。 這意味著每個人都必須支持。

在 deb 軟體包的世界中,相容性水平是驚人的。 相同的軟體包在 Debian 6 和 Ubuntu 19.04 上安裝並運行得同樣好。 舊的 Debian 發行版中製定的構建軟體包和使用它們的過程標準在新穎的 Linux Mint 和elementary OS 中仍然適用。 因此,對於 Veeam Agent for Linux,每個硬體平台一個 deb 套件就足夠了。

但在 rpm 包的世界裡,差異是巨大的。 首先,由於Red Hat和SUSE這兩家完全獨立的發行商,完全不需要相容。 其次,這些分銷商有這些分銷商的分銷套件。 支持和實驗。 它們之間也不需要相容。 原來el6、el7、el8都有自己的包包。 Fedora 的單獨包。 SLES11 和 12 的軟體包以及 openSUSE 的單獨軟體包。 主要問題是依賴關係和套件名稱。

依賴問題

不幸的是,相同的套件通常在不同的發行版中以不同的名稱出現。 以下是 veeam 軟體包依賴項的部分清單。

對於 EL7:
對於 SLES 12:

  • libblkid
  • libstdc++ 函式庫
  • ncurses 庫
  • 保險絲庫
  • 文件庫
  • veeamsnap=3.0.2.1185
  • libblkid1
  • libgcc_s1
  • + + 6
  • libmagic1
  • 庫熔絲2
  • veeamsnap-kmp=3.0.2.1185

因此,依賴項清單對於該發行版來說是唯一的。

更糟的是,當更新的版本開始隱藏在舊的套件名稱下時。

示例:

該軟體包已在 Fedora 24 中更新 ncurses的 從版本 5 到版本 6。我們的產品是使用版本 5 建構的,以確保與舊版本的兼容性。 要在 Fedora 5 上使用舊的第 24 版庫,我必須使用該套件 ncurses 相容庫.

因此,Fedora 有兩個具有不同依賴項的軟體包。

進一步更有趣。 下一次發行版更新後,該軟體包 ncurses 相容庫 對於該庫的版本 5,它已不可用。 對於發行商來說,將舊庫拖入新版本的發行版的成本很高。 一段時間後,該問題在 SUSE 發行版中再次出現。

結果,有些發行版不得不放棄對 ncurses 庫,並修復該產品,使其可以與任何版本的庫一起使用。

順便說一句,在 Red Hat 8 版本中不再有元包 蟒蛇,它指的是好舊的 python 2.7。 有 python2 и 蟒蛇3.

套件管理器的替代方案

依賴關係的問題由來已久,而且長期以來一直很明顯。 只要記得依賴地獄即可。
將各種函式庫和應用程式結合起來,使它們都能穩定工作且不會發生衝突——事實上,這是任何 Linux 發行商都試圖解決的任務。

套件管理器試圖以完全不同的方式解決這個問題。 瞬間 來自規範。 主要想法:應用程式在與主系統隔離和保護的沙箱中運行。 如果應用程式需要庫,它們會隨應用程式本身一起提供。

Flatpak 還允許您使用 Linux 容器在沙箱中運行應用程式。 也使用了沙箱的思想 AppImage.

這些解決方案可讓您為任何發行版建立一個套件。 的情況下 Flatpak 即使管理員不知情,也可以安裝和啟動應用程式。

主要問題是並非所有應用程式都可以在沙箱中運行。 有些人需要直接訪問該平台。 我什至沒有談論內核模組,它們嚴格依賴內核並且不適合沙箱概念。

第二個問題是,企業環境中流行的 Red Hat 和 SUSE 發行版尚未包含對 Snappy 和 Flatpak 的支援。

在這方面,Veeam Agent for Linux 不可用 snapcraft.io 一點也不 flathub.org.

為了結束有關套件管理器的問題,我想指出,有一種選擇可以透過組合二進位檔案和用於將它們安裝到一個套件中的腳本來完全放棄套件管理器。

這樣的捆綁包可讓您為不同的發行版和平台建立一個通用包,執行互動式安裝過程,執行必要的自訂。 我只遇到過來自 VMware 的 Linux 的此類軟體包。

更新問題

Linux 有很多面孔:如何在任何發行版上工作
即使所有依賴性問題都已解決,程式在同一發行版上的運作方式也可能有所不同。 這是關於更新的。

有3種更新策略:

  • 最簡單的一種就是永遠不更新。 我設置了伺服器並忘記了它。 如果一切正常為什麼要更新? 當您第一次聯繫支援人員時,問題就開始出現。 發行版的創建者僅支援更新的版本。
  • 您可以信任經銷商並設定自動更新。 在這種情況下,更新不成功後可能會立即致電支援人員。
  • 僅在測試基礎設施上運行後進行手動更新的選項是最可靠的,但昂貴且耗時。 不是每個人都能負擔得起。

由於不同的使用者使用不同的更新策略,因此需要同時支援最新版本和所有先前發布的版本。 這使得開發和測試過程變得複雜,並給支援團隊帶來了麻煩。

多種硬體平台

不同的硬體平台是一個很大程度上特定於本機程式碼的問題。 至少,您必須為每個受支援的平台收集二進位檔案。

在 Veeam Agent for Linux 專案中,我們仍然無法支援像這樣的 RISC。

我不會詳細討論這個問題。 我只會概述主要問題:平台相關類型,例如 size_t、結構對齊和位元組順序。

靜態和/或動態鏈接

Linux 有很多面孔:如何在任何發行版上工作
但問題是“如何與庫連結——動態還是靜態?” 值得討論。

通常,Linux 下的 C/C++ 應用程式使用動態連結。 如果應用程式是專門為特定發行版構建的,那麼這非常有用。

如果任務是用一個二進位檔案覆蓋各種發行版,那麼您必須專注於最舊的支援發行版。 對我們來說,這是Red Hat 6。它包含gcc 4.4,連C++11標準都不支援 十分.

我們使用 gcc 6.3 建置項目,它完全支援 C++14。 當然,在這種情況下,在 Red Hat 6 上您必須隨身攜帶 libstdc++ 和 boost 函式庫。 最簡單的方法是靜態連結到它們。

但遺憾的是,並非所有函式庫都可以靜態連結。

首先是系統函式庫,例如 庫保險絲, libblkid 有必要動態連結以確保它們與核心及其模組的兼容性。

其次,許可證有一個微妙之處。

GPL 授權基本上允許您僅使用開源程式碼連結庫。 MIT 和 BSD 允許靜態連結並允許將庫包含在專案中。 但LGPL似乎並不矛盾靜態鏈接,而是要求共享鏈接所需的文件。

一般來說,使用動態連結將使您不必提供任何內容。

建構 C/C++ 應用程式

要為不同的平台和發行版建立C/C++應用程序,只需選擇或建立合適的gcc版本並使用針對特定體系結構的交叉編譯器並組裝整套庫就足夠了。 這份工作是比較可行的,但是比較麻煩。 並且不能保證所選的編譯器和函式庫將提供可行的版本。

一個明顯的優勢:基礎設施大大簡化,因為整個建造過程可以在一台機器上完成。 此外,為一種架構收集一組二進位檔案就足夠了,您可以將它們打包成不同發行版的套件。 這就是為 Veeam Agent for Linux 建立 veeam 軟體包的方式。

與此選項相反,您可以簡單地準備一個構建場,即多台用於組裝的機器。 每台這樣的機器將為特定的發行版和特定的架構提供應用程式編譯和套件組裝。 在這種情況下,使用發行者準備的手段進行編譯。 也就是說,消除了準備編譯器和選擇函式庫的階段。 此外,建置過程可以輕鬆並行化。

然而,這種方法有一個缺點:對於同一架構中的每個發行版,您都必須收集自己的二進位檔案集。 另一個缺點是需要維護如此大量的機器,並且必須分配大量的磁碟空間和RAM。

這就是為 Red Hat 發行版編譯 veeamsnap 核心模組的 KMOD 套件的方式。

開放建置服務

SUSE 的同事試圖以編譯應用程式和組裝套件的特殊服務的形式實現一些中間立場 - 開放建置服務.

本質上,它是一個虛擬機管理程序,用於創建虛擬機,在其中安裝所有必需的包,編譯應用程式並在這個隔離的環境中建置包,然後發布虛擬機。

Linux 有很多面孔:如何在任何發行版上工作

OpenBuildService 中實作的排程器將決定可以啟動多少虛擬機器以獲得最佳套件建置速度。 內建簽名機制將對包進行簽名並將其上傳到內建儲存庫。 內建的版本控制系統將保存變更和建置的歷史記錄。 剩下的就是簡單地將您的來源添加到該系統中。 您甚至不必自己設定伺服器;您可以使用開放的伺服器。

然而,存在一個問題:這種收割機很難適應現有的基礎設施。 例如,不需要版本控制;我們已經擁有自己的原始碼。 我們的簽章機制不同:我們使用特殊的伺服器。 也不需要儲存庫。

此外,對其他發行版(例如 Red Hat)的支援實施得相當差,這是可以理解的。

此類服務的優點是快速支援下一版的 SUSE 發行版。 在正式宣布發布之前,組裝所需的軟體包已發佈在公共儲存庫上。 OpenBuildService 上的可用發行版清單中會出現一個新發行版。 我們選中該框並將其新增至建置計劃。 因此,新增版本的發行版幾乎只需單擊即可完成。

在我們的基礎架構中,使用 OpenBuildService 組裝了 SUSE 發行版的 veeamsnap 核心模組的所有 KMP 套件。

接下來,我想詳細討論核心模組的具體問題。

內核ABI

Linux 核心模組歷來以原始碼形式分發。 事實上,核心的創建者並不需要擔心支援核心模組的穩定 API,特別是在二進位層級(進一步稱為 kABI)。

要為普通核心建立模組,您肯定需要該特定核心的標頭,並且它僅適用於該核心。

DKMS 可讓您在更新核心時自動執行建置模組的過程。 因此,Debian 儲存庫(及其許多相關版本)的使用者使用來自發行商儲存庫的核心模組或使用 DKMS 從原始碼編譯的核心模組。

然而,這種情況並不特別適合企業領域。 專有程式碼分發商希望將產品作為編譯的二進位檔案分發。

出於安全原因,管理員不希望將開發工具保留在生產伺服器上。 Red Hat 和 SUSE 等企業 Linux 發行商決定提供使用者穩定的 kABI。 結果是適用於 Red Hat 的 KMOD 軟體包和適用於 SUSE 的 KMP 軟體包。

這個解決方案的本質非常簡單。 對於特定版本的發行版,內核 API 被凍結。 分發者聲稱他使用的是3.10內核,並且只進行了不影響內核介面的修正和改進,並且為第一個內核收集的模組可以用於所有後續內核而無需重新編譯。

Red Hat 聲稱該發行版在其整個生命週期中都具有 kABI 相容性。 也就是說,rhel 6.0(2010 年 6.10 月發布)的組裝模組也應該適用於 2018 版本(8 年 XNUMX 月發布)。 而這一晃,已經快XNUMX年了。 當然,這個任務也是相當艱鉅的。
我們記錄了幾個由於 kABI 相容性問題導致 veeamsnap 模組停止運作的案例。

在為 RHEL 7.0 編譯的 veeamsnap 模組被證明與 RHEL 7.5 的核心不相容,但它加載並肯定會導致伺服器崩潰之後,我們完全放棄了對 RHEL 7 使用 kABI 相容性。

目前,RHEL 7 的 KMOD 套件包含每個發行版本的組件和載入模組的腳本。

SUSE 更仔細地處理了 kABI 相容性的任務。 它們僅在一個服務包內提供 kABI 相容性。

例如,SLES 12 的發布是在 2014 年 12 月。而 SLES 1 SP2015 已經是在 3.12 年 XNUMX 月,也就是過去了一年多一點。 儘管兩個版本都使用 XNUMX 內核,但它們與 kABI 不相容。 顯然,維持 kABI 相容性一年要容易得多。 每年的核心模組更新周期不應該為模組創建者帶來問題。

由於此 SUSE 政策,我們沒有在 veeamsnap 模組中記錄任何 kABI 相容性問題。 確實,SUSE 的軟體包數量幾乎增加了一個數量級。

補丁和向後移植

儘管發行商努力確保 kABI 相容性和內核穩定性,但他們也嘗試提高該穩定核心的效能並消除缺陷。

同時,除了他們自己的「修復錯誤」之外,企業 Linux 核心的開發人員還監視普通核心的變化,並將其轉移到他們的「穩定」核心中。

有時這會帶來新的結果 錯誤.

在最新版本的 Red Hat 6 中,其中一項小更新出現了錯誤。 導致了在快照發布的時候,veeamsnap模組肯定會導致系統崩潰。 比較了更新前後的核心原始碼後,我們發現向後移植是罪魁禍首。 在普通核心版本 4.19 中也進行了類似的修復。 只是這個修復在普通核心中運作良好,但是當將其轉移到「穩定」2.6.32 時,自旋鎖出現了問題。

當然,每個人總是會有錯誤,但是值得冒著穩定性的風險將代碼從 4.19 拖到 2.6.32 嗎?...我不確定...

最糟糕的是行銷陷入「穩定」與「現代化」的拉鋸戰。 行銷部門一方面需要更新後的發行版核心穩定,同時表現更好,有新功能。 這會導致奇怪的妥協。

當我嘗試在 SLES 4.4 SP12 的核心 3 上建立模組時,我驚訝地發現其中包含 vanilla 4.8 的功能。 在我看來,SLES 4.4 SP12 中的 3 核心的區塊 I/O 實作與 SLES4.8 SP4.4 中的先前版本的穩定 12 核心相比更類似於 2 核心。 我無法判斷 SP4.8 的程式碼從核心 4.4 轉移到 SLES 3 的百分比是多少,但我甚至無法將核心稱為相同的穩定版 4.4。

最令人不愉快的是,當編寫一個在不同核心上同樣工作的模組時,您不能再依賴核心版本。 您還必須考慮分佈。 有時您可以參與與新功能一起出現的定義,這是件好事,但這種機會並不總是出現。

結果,程式碼充滿了奇怪的條件編譯指令。

還有一些補丁可以更改已記錄的核心 API。
我遇到了分佈 KDE霓虹燈 5.16 中,非常驚訝地發現該核心版本中的lookup_bdev 呼叫更改了輸入參數清單。

為了將它們組合在一起,我必須在 makefile 中新增一個腳本來檢查 Lookup_bdev 函數是否具有遮罩參數。

簽署內核模組

但讓我們回到包包分發的問題。

穩定的 kABI 的優點之一是核心模組可以簽署為二進位檔案。 在這種情況下,開發人員可以確定模組沒有被意外損壞或故意修改。 您可以使用 modinfo 命令檢查這一點。

Red Hat 和 SUSE 發行版可讓您檢查模組的簽名,並且僅在相應的憑證在系統上註冊時才載入它。 憑證是用於對模組進行簽署的公鑰。 我們將其作為單獨的包分發。

這裡的問題是證書要么可以內置到核心中(發行商使用它們),要么必須使用實用程式寫入 EFI 非揮發性內存 莫庫蒂爾. 公用事業 莫庫蒂爾 安裝憑證時,它要求您重新啟動系統,甚至在載入作業系統核心之前,都會提示管理員允許載入新憑證。

因此,新增憑證需要實體管理員存取系統。 如果電腦位於雲端中的某個位置或只是位於遠端伺服器機房並且僅透過網路(例如透過 ssh)進行訪問,則無法新增憑證。

虛擬機器上的 EFI

儘管EFI早已被幾乎所有主機板廠商支持,但在安裝系統時,管理員可能沒有想到EFI的必要性,甚至可能將其停用。

並非所有虛擬機器管理程式都支援 EFI。 VMWare vSphere 從版本 5 開始支援 EFI。
Microsoft Hyper-V 也從 Windows Server 2012R2 的 Hyper-V 開始獲得了 EFI 支援。

但是,在預設配置中,Linux 電腦會停用此功能,這表示無法安裝憑證。

在 vSphere 6.5 中,設定選項 安全啟動 只能在透過 Flash 運行的舊版 Web 介面中實現。 HTML-5 上的 Web UI 仍然遠遠落後。

實驗分佈

最後,讓我們考慮一下實驗發行版和沒有官方支援的發行版的問題。 一方面,這樣的發行版不太可能在嚴肅組織的伺服器上找到。 此類發行版沒有官方支援。 因此,提供這些。 此類發行版不支援該產品。

然而,此類發行版成為嘗試新實驗解決方案的便利平台。 例如,Fedora、OpenSUSE Tumbleweed 或 Debian 的不穩定版本。 他們相當穩定。 他們總是有新版本的程式和新核心。 一年後,這個實驗性功能可能會出現在更新的 RHEL、SLES 或 Ubuntu 中。

因此,如果某些東西在實驗發行版上不起作用,這就是找出問題並解決它的原因。 您需要做好準備,因為此功能很快就會出現在使用者的生產伺服器上。

您可以研究 3.0 版當前官方支援的發行版列表 這裡。 但我們的產品可以運行的實際發行版清單要廣泛得多。

就我個人而言,我對 Elbrus 作業系統的實驗很感興趣。 完成 veeam 軟體包後,我們的產品已安裝並運行。 我在 Habré 上寫過這個實驗 文章.

嗯,對新發行版的支持仍在繼續。 我們正在等待4.0版本的發布。 Beta即將出現,敬請關注 什麼是新的!

來源: www.habr.com

添加評論