Linux中國

使用 mkosi 構建 RHEL 和 RHEL UBI 鏡像

mkosi 是一個輕量級工具,用於從發行版軟體包構建鏡像。本文介紹如何使用 mkosi 從 RHEL 和 RHEL 通用基礎鏡像 Universal Base Image (UBI)的軟體包構建鏡像。RHEL UBI 是 RHEL 的一個子集,可以在沒有訂閱的情況下免費使用。

mkosi 特性

mkosi 支持一些輸出格式,但最重要的是 可發現磁碟鏡像 Discoverable Disk Images (DDI)。同一個 DDI 可用於引導容器、或運行在虛擬機、抑或是複製到 U 盤以引導真實物理機,然後從 U 盤複製到磁碟以引導系統。該鏡像具有標準化的布局和描述其用途的元數據。

mkosi 依賴其他工具來完成大部分工作:使用 systemd-repart 在磁碟鏡像上創建分區,使用 mkfs.btrfs / mkfs.ext4 / mkfs.xfs 等創建文件系統,並使用 dnf / apt / pacman / zypper 下載和解壓包。

mkosi 支持一系列發行版:Debian 和 Ubuntu、Arch Linux、openSUSE,當然還包括 Fedora、CentOS Stream 及其衍生版本,以及最近的 RHEL UBI 和 RHEL 。由於實際的「重活」是由其他工具完成的,mkosi 可以進行交叉構建。這意味著可以使用一個發行版構建各種其他發行版的鏡像。唯一的要求是主機上安裝了相應的工具。Fedora 有原生的 aptpacmanzypper,因此它為使用 mkosi 構建任何其他發行版提供了良好的基礎。

它還有一些有趣的功能:鏡像可以由非特權用戶創建,或者在沒有設備文件的容器中創建,特別是沒有對迴環設備的訪問許可權。它還可以在沒有特權的情況下將這些鏡像啟動為虛擬機(使用 qemu)。

配置是聲明性的,非常容易創建。使用 systemd-repart 創建磁碟分區,並使用 repart.d 配置文件定義應該如何完成此操作。

有關更多詳細信息,請參見 Daan DeMeyer 在 All Systems Go 大會上的兩個演講:《systemd-repart: Building Discoverable Disk Images》 和 《mkosi: Building Bespoke Operating System Images》。

項目目標

mkosi 的一個目標是允許對軟體項目進行針對不同發行版的測試。它將為一個發行版創建一個鏡像(使用該發行版的軟體包),然後將軟體項目編譯並安裝到該鏡像中,插入不屬於軟體包的額外文件。但是,首個階段,即從軟體包創建鏡像的過程,本身就是有用的。這是我們將首先展示的內容。

我們 [1] 最近添加了對 RHEL 和 RHEL UBI 的支持。讓我們從 RHEL UBI 開始,利用發行版軟體包創建鏡像。

請注意,下面的示例要求 mkosi 19,而且不適用於更早的版本。

帶有 Shell 的基本 RHEL UBI 鏡像

$ mkdir -p mkosi.cache
$ mkosi 
    -d rhel-ubi 
    -t directory 
    -p bash,coreutils,util-linux,systemd,rpm 
    --autologin

上面的命令指定了發行版 rhel-ubi,輸出格式 directory,並請求安裝軟體包 bashcoreutils、…、rpmrpm 通常不需要放到鏡像內部,但在這裡用於內省會很有用。我們還啟用了以 root 用戶自動登錄。

在啟動構建之前,我們創建了緩存目錄 mkosi.cache。當存在緩存目錄時,mkosi 會自動使用它來持久化下載的 RPM 包。這將使相同軟體包集合的後續調用速度更快。

然後,我們可以使用 systemd-nspawn 將此鏡像作為容器啟動:

$ sudo mkosi 
    -d rhel-ubi 
    -t directory 
    boot
systemd 252-14.el9_2.3 running in system mode (+PAM +AUDIT +SELINUX -APPARMOR +IMA +SMACK +SECCOMP +GCRYPT +GNUTLS +OPENSSL +ACL +BLKID +CURL +ELFUTILS -FIDO2 +IDN2 -IDN -IPTC +KMOD +LIBCRYPTSETUP +LIBFDISK +PCRE2 -PWQUALITY +P11KIT -QRENCODE +TPM2 +BZIP2 +LZ4 +XZ +ZLIB +ZSTD -BPF_FRAMEWORK +XKBCOMMON +UTMP +SYSVINIT default-hierarchy=unified)
Detected virtualization systemd-nspawn.
Detected architecture x86-64.
Detected first boot.

Red Hat Enterprise Linux 9.2 (Plow)
...
[ OK ] Created slice Slice /system/getty.
[ OK ] Created slice Slice /system/modprobe.
[ OK ] Created slice User and Session Slice.
...
[ OK ] Started User Login Management.
[ OK ] Reached target Multi-User System.

Red Hat Enterprise Linux 9.2 (Plow)
Kernel 6.5.6-300.fc39.x86_64 on an x86_64

image login: root (automatic login)

[root@image ~]# rpm -q rpm systemd
rpm-4.16.1.3-22.el9.x86_64
systemd-252-14.el9_2.3.x86_64

正如前面提到的,此鏡像可以用於啟動虛擬機。但在此設置下,這是不可能的 —— 我們的鏡像沒有內核。事實上,RHEL UBI 根本不提供內核,因此我們無法使用它進行引導(無論是在虛擬機上還是在裸機上)。

創建鏡像

我一開始說是要創建鏡像,但到目前為止我們只有一個目錄。讓我們開始實際創建一個鏡像:

$ mkosi 
    -d rhel-ubi 
    -t disk 
    -p bash,coreutils,util-linux,systemd,rpm 
    --autologin

這將生成 image.raw,一個帶有 GPT 分區表和單個根分區(用於本機架構)的磁碟鏡像。

$ sudo systemd-dissect image.raw
Name: image.raw
Size: 301.0M
Sec. Size: 512
Arch.: x86-64

Image UUID: dcbd6499-409e-4b62-b251-e0dd15e446d5
OS Release: NAME=Red Hat Enterprise Linux
VERSION=9.2 (Plow)
ID=rhel
ID_LIKE=fedora
VERSION_ID=9.2
PLATFORM_ID=platform:el9
PRETTY_NAME=Red Hat Enterprise Linux 9.2 (Plow)
ANSI_COLOR=0;31
LOGO=fedora-logo-icon
CPE_NAME=cpe:/o:redhat:enterprise_linux:9::baseos
HOME_URL=https://www.redhat.com/
DOCUMENTATION_URL=https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/9
BUG_REPORT_URL=https://bugzilla.redhat.com/
REDHAT_BUGZILLA_PRODUCT=Red Hat Enterprise Linux 9
REDHAT_BUGZILLA_PRODUCT_VERSION=9.2
REDHAT_SUPPORT_PRODUCT=Red Hat Enterprise Linux
REDHAT_SUPPORT_PRODUCT_VERSION=9.2

Use As: ✗ bootable system for UEFI
        ✓ bootable system for container
        ✗ portable service
        ✗ initrd
        ✗ sysext extension for system
        ✗ sysext extension for initrd
        ✗ sysext extension for portable service

RW DESIGNATOR PARTITION UUID PARTITION LABEL FSTYPE ARCHITECTURE VERITY GROWFS NODE PARTNO
rw root 1236e211-4729-4561-a6fc-9ef8f18b828f root-x86-64 xfs x86-64 no yes /dev/loop0p1 1

好的,我們現在有一個鏡像,鏡像中包含了一些來自 RHEL UBI 軟體包的內容。我們如何在其上加點我們自己的東西呢?

使用自己的文件擴展鏡像

有幾種方法可以擴展鏡像,包括從頭開始編譯某些東西。但在那之前,讓我們做一些更簡單的事情,將一個現成的文件系統注入到鏡像中:

$ mkdir -p mkosi.extra/srv/www/content
$ cat >mkosi.extra/srv/www/content/index.html <<&apos;EOF&apos;
<h1>Hello, World!</h1>
EOF

現在,該鏡像將包含 /srv/www/content/index.html

這種方法用於注入額外的配置或簡單的程序。

從源代碼構建

現在讓我們過一遍完整流程,從源代碼構建一些東西。例如,一個簡單的 Meson 項目,有一個單獨的 C 文件:

$ cat >hello.c <<&apos;EOF&apos;
#include <stdio.h>

int main(int argc, char **argv) {
    char buf[1024];

    FILE *f = fopen("/srv/www/content/index.html", "re");
    size_t n = fread(buf, 1, sizeof buf, f);

    fwrite(buf, 1, n, stdout);
    fclose(f);
    return 0;
}
EOF

$ cat >meson.build <<&apos;EOF&apos;
project(&apos;hello&apos;, &apos;c&apos;)
executable(&apos;hello&apos;, &apos;hello.c&apos;,
            install: true)
EOF
$ cat >mkosi.build <<&apos;EOF&apos;
set -ex

mkosi-as-caller rm -rf "$BUILDDIR/build"
mkosi-as-caller meson setup "$BUILDDIR/build" "$SRCDIR"
mkosi-as-caller meson compile -C "$BUILDDIR/build"
meson install -C "$BUILDDIR/build" --no-rebuild
EOF
$ chmod +x mkosi.build

總結一下:我們有一些源代碼(hello.c),一個構建系統配置文件(meson.build),以及一個由 mkosi 調用的膠水腳本(mkosi.build)。對於實際的項目,也會有相同的元素,只是更加複雜。

這個腳本需要一些解釋。mkosi 在創建鏡像時使用用戶命名空間。這允許包管理器(例如 dnf)安裝由不同用戶擁有的文件,即使它是由一個普通非特權用戶調用的。我們使用 mkosi-as-caller 切換回調用者以進行編譯。這樣,在 $BUILDDIR 下編譯期間創建的文件將由調用者擁有。

現在讓我們使用我們的程序構建鏡像。與之前的調用相比,我們需要額外的軟體包:mesongcc。由於我們現在有了構建腳本,mkosi 將執行兩個構建階段:首先創建一個構建鏡像,並在其中調用構建腳本,將安裝產物存儲在一個臨時目錄中,然後構建最終鏡像,並將安裝產物注入其中。(mkosi 設置 $DESTDIRmeson install 自動使用 $DESTDIR,因此並不需要我們明確指定。)

$ mkosi 
    -d rhel-ubi 
    -t disk 
    -p bash,coreutils,util-linux,systemd,rpm 
    --autologin 
    --build-package=meson,gcc 
    --build-dir=mkosi.builddir 
    --build-script=mkosi.build 
    -f

此時,我們有了帶有自定義載荷的鏡像 image.raw。我們可以啟動我們新創建的可執行文件作為 shell 命令:

$ sudo mkosi -d rhel-ubi -t directory shell hello
<h1>Hello, World!</h1>

獲取 RHEL 的開發者訂閱

RHEL UBI 主要用作容器構建的基礎層。它提供了有限的軟體包(約 1500 個)。現在讓我們切換到完整的 RHEL 安裝。

獲取 RHEL 的最簡單方法是使用 開發者許可證。它提供了許可權註冊 16 個運行 RHEL 的物理或虛擬節點,並提供自助式支持。

首先,創建一個賬戶。然後,轉到 管理頁面 並確保啟用了「用於 Red Hat 訂閱管理的簡化內容訪問」。接下來,創建一個新的激活密鑰,選擇 「Red Hat 個人開發者訂閱」。記下顯示的組織 ID。在下面,我們將使用密鑰名稱和組織 ID 分別表示為 $KEY_NAME$ORGANIZATION_ID

現在,我們準備使用 RHEL 內容:

$ sudo dnf install subscription-manager
$ sudo subscription-manager register 
    --org $ORGANIZATION_ID --activationkey $KEY_NAME

使用 RHEL 構建鏡像

在之前的示例中,我們通過參數開關指定了所有配置。這對於快速開發很友好,但可能在情況複雜時變得難以處理。RHEL 是一個嚴肅的發行版,所以讓我們改為使用配置文件:

$ cat >mkosi.conf <<&apos;EOF&apos;
[Output]
Format=directory
Output=rhel-directory

[Distribution]
Distribution=rhel

[Content]
Packages=
bash
coreutils
util-linux
systemd
systemd-boot
systemd-udev
kernel-core

Bootable=yes
Bootloader=uki
Autologin=yes
WithDocs=no
EOF

首先,讓我們檢查一下一切是否正常:

$ mkosi summary

現在讓我們構建鏡像(呃,或者說,目錄):

$ mkosi build
$ mkosi qemu
Welcome to Red Hat Enterprise Linux 9.2 (Plow)!

[ OK ] Created slice Slice /system/modprobe.
[ OK ] Reached target Initrd Root Device.
[ OK ] Reached target Initrd /usr File System.
[ OK ] Reached target Local Integrity Protected Volumes.
[ OK ] Reached target Local File Systems.
[ OK ] Reached target Path Units.
[ OK ] Reached target Remote Encrypted Volumes.
[ OK ] Reached target Remote Verity Protected Volumes.
[ OK ] Reached target Slice Units.
[ OK ] Reached target Swaps.
...
[ OK ] Listening on Journal Socket.
[ OK ] Listening on udev Control Socket.
[ OK ] Listening on udev Kernel Socket.
...
Red Hat Enterprise Linux 9.2 (Plow)
Kernel 5.14.0-284.30.1.el9_2.x86_64 on an x86_64

localhost login: root (automatic login)
[root@localhost ~]#

很好,我們將「鏡像」構建為一個帶有文件系統樹的目錄,並在虛擬機中引導了它。

在引導的虛擬機中,findmnt / 顯示根文件系統是 virtiofs。這是一個虛擬文件系統,將主機的目錄暴露給客戶機。我們其實也可以構建一個更傳統的鏡像,其中包含文件系統和文件內的分區表,但「目錄 + virtiofs」 對於開發來說更快且更友好。

我們剛剛引導的鏡像未註冊。要允許從鏡像「內部」下載更新,我們必須將 yumsubscription-managerNetworkManager 添加到軟體包列表,並在下載任何更新之前以與上述相同的方式調用 subscription-manager。在這之後,我們在基本倉庫中就有大約 4500 個軟體包可用,並且還有一些包含更多專業軟體包的額外倉庫。

最後

今天就是這些了。如果您有問題,可以在 Matrix 上找到我們,地址為 #mkosi:matrix.org,或者在 systemd 郵件列表 上找到我們。

(題圖:MJ/a6e60316-ed03-4e23-b8b4-22332a0f5bfa)

  1. Daan DeMeyer、Lukáš Nykrýn、Michal Sekletár、Zbigiew Jędrzejewski-Szmek ↩︎

via: https://fedoramagazine.org/create-images-directly-from-rhel-and-rhel-ubi-package-using-mkosi/

作者:Zbigniew Jędrzejewski-Szmek 選題:lujun9972 譯者:GlassFoxowo 校對:wxy

本文由 LCTT 原創編譯,Linux中國 榮譽推出


本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive

對這篇文章感覺如何?

太棒了
0
不錯
0
愛死了
0
不太好
0
感覺很糟
0
雨落清風。心向陽

    You may also like

    Leave a reply

    您的郵箱地址不會被公開。 必填項已用 * 標註

    此站點使用Akismet來減少垃圾評論。了解我們如何處理您的評論數據

    More in:Linux中國