MKOSI笔记
MKOSI-INITRD
mkosi-initrd是使用MKOSI进行initramfs构建的工具。
1  | mkosi-initrd [选项]  | 
可用选项有:
--kernel-version=:使用的内核版本,默认使用$(uname -r)。--format=|-t:输出格式,可选值有cpio或uki,默认使用cpio。-o|--output=:输出文件名前缀,默认为initrd。-O|--output-dir=:输出的目录,默认为工作目录。--debug:Debug输出。
它本质上是一个使用了特殊的默认配置的MKOSI Wrapper脚本(见mkosi.conf),在执行时,它会获取当前主机的内核版本(或用户指定的内核版本),并将当前内核的/usr/lib/modules/版本号目录映射到镜像中进行构建。
该命令行工具由MKOSI的Pypi包提供,对于发行版来说,它们也可以使用Kernel-install脚本进行集成(参考setup-mkosi)。
MKOSI-SANDBOX
mkosi-sandbox用于在沙箱中执行命令:
1  | mkosi-sandbox [选项] [命令] [参数]  | 
命令默认为bash。
接受的选项有:
--tmpfs 目录:沙箱中挂载的Tmpfs。--dev 目录:沙箱中创建的Devfs。--proc 目录:沙箱中创建的Procfs。--dir 目录:沙箱中递归创建的目录。--bind|--bind-try|--ro-bind|--ro-bind-try 主机目录 沙箱目录:(只读)绑定挂载到沙箱的目录。--symlink 路径 链接:在沙箱中创建软链接。--write 数据 路径:在沙箱中写入指定文件。--overlay-lowerdir 主机目录:设置下一个Overlayfs的下层目录。--overlay-upperdir 主机目录|tmpfs:设置下一个Overlayfs的上层目录。--overlay-workdir 主机目录:设置下一个Overlayfs挂载的工作目录。--overlay 沙箱目录:在沙箱中挂载Overlayfs。--unsetenv 变量名:在沙箱中去掉环境变量。--setenv 变量名 值:在沙箱中设置环境变量。--chdir 目录:启动沙箱时的工作目录。--same-dir:启动沙箱时的工作目录为当前宿主机所处的目录。--become-root:成为沙箱内的Root用户并获取CAP_SYS_ADMIN,默认为普通用户。--suppress-chown:禁止使用chown()系统调用。--unshare-net:隔离网络命名空间。--unshare-ipc:隔离IPC命名空间。
实例:
1  | mkosi-sandbox --bind / / --same-dir --become-root bash --login  | 
1  | mkosi-sandbox \  | 
MKOSI
Linux发行版 = Base Files(Base Rootfs) + Essential Packages + Package Manager:
- Debian/Ubuntu = 
debootstrap(base-files+base-passwd) +"Essential: yes" Packages+apt - Fedora/CentOS/RHEL = 
yum|dnf --installroot(setup+basesystem+filesystem) +@core Package Group+yum|dnf - Arch = 
pacstrap(base) +base Meta Package+pacman - Gentoo = 
stage 3 Image+@system Set+emerge 
mkosi是建立在dnf --installroot、debootstrap、pacstrap等工具之上的,快速构建客制化的系统镜像并进行测试的工具。
“镜像”在这里是一个通用概念,这意味着MKOSI可以生成以下类型的“镜像”:
- 使用GPT分区表的磁盘镜像,可以克隆到磁盘中。
 - CPIO归档,用于作为initramfs使用。
 - USI(Unified System Image,即将完整的操作系统打包进UKI的镜像)
 - Sysext、Confext、Portable Service Image镜像
 - 用于容器的目录树镜像
 
安装
mkosi在各大发行版的软件源中有提供:
1  | # Debian  | 
也可以使用pip安装:
1  | pipx install git+https://https://github.com/systemd/mkosi.git  | 
语法
1  | mkosi [选项] 子命令  | 
构建配置文件
mkosi的任何命令都基于特定的规则读取配置文件,优先级顺序分别是:
- 最优先:命令行选项。
 - 当前目录下的
mkosi.local.conf配置文件或mkosi.local目录下的配置文件。该文件仅用于本地配置,不应该共享。 -C|--directory=指定目录(默认为当前目录)下的mkosi.conf配置文件。--directory=指定目录(默认为当前目录)下的mkosi.conf.d/目录内的配置文件。- 用户指定的Profile对应的
mkosi.profiles/里面的子目录配置。 mkosi.images/里面的子镜像的配置。
子命令
mkosi由多种子命令组成,这些命令其实都是一些外部工具的简易接口:
summary:打印配置文件中定义的配置总结,这也反映了构建时会进行的操作。build:从配置文件中读取配置并开始构建镜像。sysupdate:执行systemd-sysupdate,其中,--transfer-source=设为输出目录(默认为mkosi.output/),--definition=设为SysupdateDirectory=的值(默认为mkosi.sysupdate/),任何子命令之后的参数都会被传递给systemd-sysupdate。- 要求:MKOSI使用的Sysupdate配置中,必须设置
PathRelativeTo=explicit和Path=/才能正常使用sysupdate子命令进行更新,这会使得配置中的Path=使用mkosi.output/(或OutputDirectory=指定的目录)作为根。 - 如果使用了ToolsTree,且存在文件系统中存在
/usr/share/factory,那么ToolsTree中必须也存在/usr/share/factory,否则会发生文件系统只读错误,这是因为ToolsTree的/usr在Sandbox中是被只读挂载的,无法在沙盒中创建/usr/share/factory挂载点。 - 这同时也意味着,
SplitArtifacts=partitions必须启用以对分区进行更新,而且更新内容(分区镜像文件、EFI程序、initramfs)文件名必须与Sysupdate配置中的MatchPattern=匹配。 
- 要求:MKOSI使用的Sysupdate配置中,必须设置
 shell:(如果还没有构建)先构建镜像,然后调用systemd-nspawnChroot到镜像内。- 仅适用于
QCow2=no且未压缩的镜像。 
- 仅适用于
 boot:(如果还没有构建)先构建镜像,然后调用systemd-nspawn以容器形式启动镜像。- 仅适用于
QCow2=no且未压缩的镜像。 
- 仅适用于
 qemu:(如果还没有构建)先构建镜像,然后调用qemu以虚拟机形式启动镜像。- 对于目录树,MKOSI使用
virtiofsd引导。 ssh:连接到镜像对应的虚拟机。genkey:创建SSH密钥。
- 对于目录树,MKOSI使用
 serve:(如果还没有构建)先构建镜像,然后调用内置的HTTP服务器在8081端口上暴露工作目录。- (仅用于
disk镜像)burn 块设备:(如果还没有构建)先构建镜像,然后将镜像扩展到目标块设备的大小,再烧录到指定的块设备上。 journalctl:获取镜像内的日志。coredumpctl:获取镜像内的内核转储文件。clean:清理之前的构建产物。bump:刷新mkosi.version文件中的镜像版本。genkey:生成安全启动密钥。
命令行选项
这里提到的命令行选项是和构建配置完全无关的:
-f|--force:进行指定操作前,不加分辨地重新构建镜像。-B--auto-bump:执行操作后自动刷新版本号。-C|--directory=:指定工作目录,默认为当前工作目录。--debug:启用Debug级输出。--debug-shell:当在镜像中执行命令失败时,启动一个额外的Debug Shell用于排错。--debug-workspace=:执行操作后,指定的临时文件目录内容不会删除。
构建配置
构建配置文件符合.ini格式,每一行都是Key=Value的形式,每一个配置项都有等价的命令行选项,转换方式是SomeSetting到some-setting。
配置中存在以下可用的占位符:
| 含义 | 占位符 | 
|---|---|
Distribution= | 
%d | 
Release= | 
%r | 
Architecture= | 
%a | 
Format= | 
%t | 
Output= | 
%o | 
OutputDirectory= | 
%O | 
ImageId= | 
%i | 
ImageVersion= | 
%v | 
Profiles= | 
%p | 
| 配置文件所在目录 | %C | 
| 工作目录 | %P | 
| MKOSI的执行目录 | %D | 
| 当前子镜像的镜像名 | %I | 
具体的构建配置有:
[Match]段与[TriggerMatch]段
匹配构建时包含当前配置文件的特定条件。每个配置项除了使用=连接键值对外,还可以使用=|连接键值对,多个使用=连接键值对的配置项之间是逻辑与关系,必须全部满足;多个使用=|连接键值对的配置项之间是逻辑或关系,满足一个即可。
可用配置项有:
Profiles=:使用的Profile。Distribution=:构建的发行版。Release=:构建的发行版版本。Architecture=:构建的架构。可用的值有alpha、arc、arm、arm64、ia64、loongarch64、mips64-le、mips-le、parisc、ppc、ppc64、ppc64-le、riscv32、riscv64、s390、s390x、tilegx、x86、x86-64。HostArchitecture=:主机的架构。ImageId=:构建的镜像名称。ImageVersion=:构建的镜像版本。Bootable=:构建的镜像是否可引导。Format=:构建的镜像格式。ToolsTreeDistribution=:使用的Tools Tree发行版。PathExists=:主机上存在指定目录。SystemdVersion=:主机上的systemd版本。
[Match]段之间是纯粹的AND关系,也就是说,不同的[Match]段必须全部满足。而[TriggerMatch]段之间是OR关系,也就是说,不同的[TriggerMatch]段中,只要有一个[TriggerMatch]段满足即可。
(v20以上版本)[Include]段
Include=:导入指定的额外配置文件。如果值为mkosi-initrd,那么会使用mkosi-initrd的配置生成initramfs。- 特殊值
mkosi-initrd表示mkosi-initrd的配置。 - 特殊值
mkosi-tools表示ToolsTree的配置。 - 特殊值
mkosi-vm表示运行虚拟机时的默认配置。 
- 特殊值
 
(v20以上版本)[Config]段
额外配置。
Profiles=:使用指定的Profile,Profile是mkosi.profiles/目录下保存的一个子工作目录,它支持的内容和MKOSI的主工作目录完全一致(除了不能有mkosi.profiles/目录),会覆盖主工作目录的对应部分。- Profile通常是让用户通过
--profile=命令行选项进行自选的。它可以用于匹配,因此适合保存相同镜像的不同口味。 - Profile并不能修改
mkosi.images/中的子镜像的配置。 
- Profile通常是让用户通过
 ConfigureScript=:在读取配置文件后立刻执行的脚本。默认为mkosi.configure。MinumumVersion=:要求的最小MKOSI版本号。PassEnvironment=:传递的环境变量,空格分隔。Dependencies=:依赖的子镜像,子镜像是mkosi.images/目录下保存的一个子工作目录,它支持的配置项和MKOSI的主工作目录相比会少一些,如果没有Dependencies=,那么所有子镜像都会在主镜像构建之前自动构建,即Dependencies=*,如果有Dependencies=,那么只构建依赖的镜像。- 子镜像不接受的配置项有:
 Architecture=BuildDirectory=BuildSources=BuildSourcesEphemeral=CacheDirectory=CacheOnly=Distribution=ExtraSearchPaths=Incremental=LocalMirror=Mirror=OutputDirectory=OutputMode=PackageCacheDirectory=PackageDirectories=Profiles=ProxyClientCertificate=ProxyClientKey=ProxyExclude=ProxyPeerCertificate=ProxyUrl=Release=RepartOffline=Repositories=RepositoryKeyCheck=SandboxTrees=SourceDateEpoch=ToolsTree=ToolsTreeCertificates=UseSubvolumes=VerityCertificate=VerityKey=VolatilePackageDirectories=WithNetwork=WithTestsWorkspaceDirectory=
[Distribution]段
发行版配置。
Distribution=:使用的发行版,目前支持fedora,debian,ubuntu,arch,opensuse,mageia,centos,centos_epel,openmandriva,rocky,rocky_epel,alma,alma_epel,gentoo,custom。默认使用主机的发行版。- 当
Distribution=custom时,无法自动构建Rootfs,需要自行提供。 
- 当
 Release=:使用的版本。默认使用主机的版本。Architecture=:使用的架构。默认使用主机的架构。Mirror=:使用的镜像源。- 在使用EPEL时,如果要为EPEL使用其他镜像,使用
$EPEL_MIRROR环境变量。 - Debian的Debug和Security源无法直接切换镜像,考虑使用
mkosi.pkgmngr,或是构建无Debug和Security仓库的sid|unstable版本。 
- 在使用EPEL时,如果要为EPEL使用其他镜像,使用
 LocalMirror=:在构建时使用的镜像源,但并不写入最终镜像内。RepositoryKeyCheck=:检查镜像源密钥。- (新版本)
RepositoryKeyFetch=:在安装时自动尝试获取软件源密钥,默认启用,如果禁用,将从宿主机传递软件源密钥,这需要安装对应的*-keyring软件包。 Repositories=:启用的Yum源名(例如epel),或是Apt源的分区(例如main)。使用逗号分隔。
[Output]段
输出方式。
Format=:导出格式,mkosi支持非常多种镜像,包括但不仅限于:disk(旧版本为gpt_ext4|gpt_ext4|gpt_xfs):GPT+UEFI磁盘镜像。使用systemd-repart生成。directory:纯目录形式的容器根文件系统。tar:Tar包。cpio:CPIO包。uki:UKI镜像。esp:类似于uki,但是转换为一个包含单个ESP的GPT分区表的磁盘镜像。oci:OCI容器镜像。sysext|confext|portable:系统扩展镜像。none:当前配置用于分组,不实际生成镜像。
ManifestFormat=:生成镜像大纲(保存安装的所有软件包列表)的格式,可选json或changelog,默认不生成。Output=:镜像文件/目录的前缀,默认为image。OutputDirectory=:构建产品的保存目录,默认为工作目录下的mkosi.output/。CompressOutput=:输出镜像的压缩方式,请注意,这会导致shell、boot、qemu命令在该镜像上不可用。仅可用于tar、cpio、uki、esp和oci镜像。可选值有布尔值和xz、zstd等压缩算法。默认使用zstd。CompressLevel=:(新版本)压缩等级。
SplitArtifacts=:分开导出的产品列表,使用逗号分隔,可选值有uki、kernel、initrd、partitions。- 默认值
no等价于uki,kernel,initrd。 uki会导出UKI。kernel和initrd会导出组成UKI的内核和initramfs。partitions在使用磁盘镜像时,会告诉systemd-repart针对每个分区分别进行导出。默认情况下,导出的分区文件会以镜像名.分区名命名。OutputSplitRoot=:(旧版本)导出根分区镜像的名称。OutputSplitVerify=:(旧版本)导出的校验分区的名称。OutputSplitKernel=:(旧版本)导出的ESP分区的名称。
- 默认值
 ImageVersion=:镜像的版本号。- 你也可以使用
mkosi.version指定版本号,此文件还可以是一个可执行的Shell脚本,使其输出作为版本号。 
- 你也可以使用
 ImageID=:镜像名称,会写入镜像的os-release文件中。- (新版本)
RepartDirectories=:systemd-repart的分区定义配置文件目录,默认为工作目录下的mkosi.repart/。- 注意,MKOSI的分区配置文件中的
CopyFiles=的源路径会使用镜像中的根文件系统。 
 - 注意,MKOSI的分区配置文件中的
 - (新版本)
SectorSize=:systemd-repart的块大小。 - (新版本)
Seed=:systemd-repart使用的UUID,也可以使用mkosi.seed文件保存,默认值为random。 - (新版本)
Overlay=:和BaseTrees=一起使用,是否仅仅保留相对于Base Tree发生改变的内容,用于构建系统扩展镜像。- 在构建系统扩展镜像时,可以使用该选项结合
BaseTree=指定的目录以获取增量部分,即扩展镜像的部分。 
 - 在构建系统扩展镜像时,可以使用该选项结合
 - (新版本)
CleanScripts=:用于构建的最后阶段进行清理的脚本,默认为mkosi.clean。 
(v20以上版本)[Build]段
ToolsTree=:在指定目录下搜索构建工具组,也可以使用mkosi.tools/目录保存,这有助于使用其他版本的构建工具组。- 如果值为
default,那么会从指定的发行版的软件源中自动获取Tools Tree。在目标发行版的systemd版本低于构建所需的最低要求时,会自动启用。在当前发行版低于构建所需的最低systemd版本时,该选项必须启用。 ToolsTreeDistribution=:用于自动获取ToolsTree=的目标发行版。ToolsTreeRelease=:用于自动获取ToolsTree=的目标发行版版本。ToolsTreeMirror=:用于自动获取ToolsTree=的目标发行版镜像源。ToolsTreeRepositories=:和Repositories=一样,但是用于构建ToolsTree=。ToolsTreeSandboxTrees=:和SandboxTrees=一样,但是用于构建ToolsTree=。ToolsTreePackages=:在ToolsTree=中包含的额外软件包。ToolsTreeCertificates=:是否使用Tools Tree中的证书,这包括/etc/pki、/etc/ssl、/etc/ca-certificates和/var/lib/ca-certificates,如果禁用,使用主机上的证书。
- 如果值为
 Incremental=:渐进构建,可选值为布尔值或strict。在执行mkosi.build脚本之前提供镜像缓存,这可以显著提高构建速度。如果为strict,那么如果缓存镜像不存在则会报错退出。CacheOnly=:纯缓存模式,可选值有auto、metadata、always或never,如果为always,那么包管理器不会联网,只使用本地缓存;如果为metadata,那么包管理器不会联网更新元数据;如果为auto,那么仅在不存在缓存镜像时更新元数据。SandboxTrees=:接受逗号分隔的,冒号绝对路径对。前者是主机上的路径,后者是MKOSI沙箱内的路径,表示在执行构建之前拷贝到沙箱的文件。也可以使用mkosi.sandbox/目录进行保存。WorkspaceDirectory=:临时文件的保存目录,默认为$XDG_CACHE_HOME或$HOME/.cache或/var/tmp。CacheDirectory=:构建时软件包管理器缓存的保存目录,默认使用工作目录下的mkosi.cache/。PackageCacheDirectory=:软件包管理器的缓存目录。BuildDirectory=:用于执行Out-of-Tree构建的构建目录,这使得构建产品可以在多次构建时共享。默认为mkosi.builddir/。UseSubvolumes=:是否使用Btrfs子卷,可选值有布尔值或auto。RepartOffline=:是否在不使用回环设备的情况下构建磁盘镜像,仅在以XFS为根文件系统且启用SELinux的情况下需要启用。History=:是否保存历史,历史会被保存在.mkosi-private目录下。ExtraSearchPaths=:用于搜索工具的额外目录,会在构建时被添加到$PATH中。ProxyUrl=:使用的代理地址。ProxyExclude=:不使用代理的主机名。ProxyPeerCertificate=:代理Peer的证书。ProxyClientCertificate=:代理客户端的证书。ProxyCientKey=:代理客户端的Key。
[Content]段
镜像配置:
Packages=:包含的包,使用逗号或是换行符分隔。会使用该发行版对应的包管理器进行安装。BuildPackages=:在构建的Overlayfs中安装包。这样的包应当用于mkosi.build脚本。PackageDirectories=:读取指定目录下的额外软件包并在构建时在镜像中进行安装。- (新版本)
WithRecommends=:是否安装弱依赖,仅适用于apt、dnf和zypper。默认禁用。 WithDocs=:是否在镜像内保留文档。默认启用。- (新版本)
MakeInitrd=:是否在镜像内创建/init和/etc/initrd-release文件。该配置项通常在MKOSI-INITRD内部使用。 - (新版本)
BaseTrees=:接受逗号分隔的,冒号绝对路径对。前者是主机上的路径,后者是镜像内的路径,表示在获取发行版基本根文件系统之前,将主机文件/目录拷贝到镜像内。这也是Overlay=yes参考的基础文件系统。如果没有指定镜像内的路径,那么默认为/。 SkeletonTrees=:接受逗号分隔的,冒号绝对路径对。前者是主机上的路径,后者是镜像内的路径,表示在已经构建基本根文件系统,开始安装软件包之前,将主机文件/目录拷贝到镜像内。mkosi.skeleton/目录下的文件总是会被拷贝到相同的目标位置下。
ExtraTrees=:接受逗号分隔的,冒号绝对路径对。前者是主机上的路径,后者是镜像内的路径,表示在安装软件包之后,将主机文件/目录拷贝到镜像内。mkosi.extra/目录下的文件总是会被拷贝到相同的目标位置下。
RemovePackages=:在构建后删除指定的包。RemoveFiles=:在构建后删除指定的文件,路径使用镜像内的根文件系统。CleanPackageMetadata=:是否在构建后清理镜像内包管理器的缓存。默认为是。Bootable=:镜像是否可引导(是否安装引导程序),可选值除了布尔值还有auto。默认为auto,即尽可能设置。如果设为yes,那么在Bootloader=设置的Bootloader软件包不存在时,构建会失败。- 镜像内必须安装对应架构的内核。
 - (新版本)
Bootloader=:使用的引导程序,可选none、systemd-boot或grub。默认为systemd-boot。- 如果
Bootable=no,那么该配置项无意义。 - 如果使用
none,那么和Bootable=no效果一致。 - 如果使用
grub,那么镜像中必须安装对应架构的grub软件包,确保存在/usr/lib/grub或/usr/share/grub2目录。 - 如果使用
systemd-boot,那么镜像中必须安装对应架构的grub软件包,确保存在bootctl程序。 
 - 如果
 - (新版本)
BiosBootloader=:是否安装BIOS引导,可选none或grub,如果启用,那么需要创建大小为1MB,类型为21686148-6449-6e6f-744e-656564454649的biosboot分区。默认为none。- 如果
Bootable=no,那么该配置项无意义。 - 如果使用
grub,那么镜像中必须安装对应架构的grub软件包。 
 - 如果
 - (新版本)
ShimBootLoader=:是否安装Shim,可选none、unsigned或signed。在SecureBoot=true的情况下,如果为unsigned,那么MKOSI会安装未签名的Shim,并自行对其进行签名,如果为signed,那么MKOSI会安装已签名的Shim。默认为none。- 如果设为
unsigned,那么镜像内必须安装shim-unsigned软件包。 - 如果设为
signed,那么镜像内必须安装shim-signed软件包。 - 在没有启用
SecureBoot=true的情况下,该选项没有意义。 
 - 如果设为
 
- (新版本)
KernelModulesInclude=:在镜像中包含的内核模块,格式为相对于/usr/lib/modules/内核版本/kernel目录的路径正则表达式,这对于initramfs特别有用。- 关键词
default表示包含MKOSI-INITRD的mkosi.conf中的所有默认配置,参见mkosi.conf。这也是未设置该配置项的默认值。 - 关键词
host表示包含宿主机当前加载的所有模块。 
 - 关键词
 - (新版本)
KernelModulesExclude=:在镜像中排除的内核模块。- 因为MKOSI默认会加载
mkosi-initrd的配置,因此如果希望重设模块,必须先设置KernelModulesExclude=.*。 
 - 因为MKOSI默认会加载
 
initramfs配置:
- (新版本)
KernelModulesInitrd=:是否在Bootable=true的镜像中使用MKOSI构建一个独立的,额外的initramfs,默认启用。- 这是推荐的行为,因为MKOSI开发组期望构建出的镜像使用与本地环境无关的initramfs。构建过程中会使用镜像内的安装的内核和固件(在安装时均会被MKOSI移动到
/usr/lib/modules/目录下)进行打包。 
 - 这是推荐的行为,因为MKOSI开发组期望构建出的镜像使用与本地环境无关的initramfs。构建过程中会使用镜像内的安装的内核和固件(在安装时均会被MKOSI移动到
 - (新版本)
KernelModulesInitrdInclude=:在initramfs中包含的模块。- 关键词
default表示包含MKOSI-INITRD的mkosi.conf中的所有默认配置,参见mkosi.conf。这也是未设置该配置项的默认值。 - 关键词
host表示包含宿主机当前加载的所有模块。 
 - 关键词
 - (新版本)
KernelModulesInitrdExclude=:在initramfs中排除的模块。 UnifiedKernelImages=:是否使用UKI而不是独立initramfs。默认为auto,即尽可能使用。- 如果启用了UKI:如果
systemd-repart发现了存在哈希值(即,启用了Verity)的根文件系统分区,那么会将其哈希值写入UKI的roothash=内核命令行参数中。否则,如果systemd-repart发现了存在哈希值(即,启用了Verity)的/usr/文件系统分区,那么会将其哈希值写入UKI的usrhash=内核命令行参数中。 - 如果未启用UKI,且使用
systemd-boot:如果systemd-repart发现了存在哈希值(即,启用了Verity)的根文件系统分区,那么会将其哈希值写入BLS引导条目的roothash=内核命令行参数中。否则,如果systemd-repart发现了存在哈希值(即,启用了Verity)的/usr/文件系统分区,那么会将其哈希值写入BLS引导条目的usrhash=内核命令行参数中。否则,如果找到了GPT PARTLABEL为root*的分区,那么会将其PARTUUID写入BLS引导条目的root=PARTUUID=内核命令行参数中。 - 如果未启用UKI,且使用GRUB:如果
systemd-repart发现了存在哈希值(即,启用了Verity)的根文件系统分区,那么会将其哈希值写入grub.cfg的roothash=内核命令行参数中。否则,如果systemd-repart发现了存在哈希值(即,启用了Verity)的/usr/文件系统分区,那么会将其哈希值写入grub.cfg的usrhash=内核命令行参数中。否则,如果找到了GPT PARTLABEL为root*的分区,那么会将其PARTUUID写入grub.cfg的root=PARTUUID=内核命令行参数中。否则,如果找到了GPT PARTLABEL为usr*的分区,那么会将其PARTUUID写入grub.cfg的mount.usr=PARTUUID=内核命令行参数中。 UnifiedKernelImageFormat=:UKI文件命名,默认为&e-&k,支持的占位符有:&&:&本身。&e:Token。&k:内核版本。&h:roothash=或usrhash=的值。&c:引导尝试次数。
UnifiedKernelImageProfiles=:构建额外的UKI配置,接受逗号分隔的UKI配置文件。也可以保存在mkosi.uki-profiles/目录下。UKI配置以.conf结尾,只有一个UKIProfile段,可用内容有:Profile=:配置信息,包括ID(必须)和TITLE。Cmdline=:内核命令行参数。
PeAddons=:(已被移除)构建额外的PE插件,接收逗号分隔的ukify配置文件,额外的PE插件会以配置文件名.addon.efi命名,也可以将ukify配置文件保存在mkosi.pe-addons/目录下。
- 如果启用了UKI:如果
 - (新版本)
MicrocodeHost=:是否在initramfs中仅仅包含主机的CPU微码。默认禁用。 - (新版本)
InitrdPackages=:在initramfs中额外安装的软件包。 - (新版本)
Initrds=:使用用户提供的指定initramfs,而不是自行构建。 KernelCommandLine=:封装在UKI或initramfs内的内核命令行参数。- 如果检测到使用了Verity的
root分区或usr分区,那么会自动填充roothash=分区Hash值或usrhash=分区Hash值。 - 内核命令行参数
root=PARTUUID和mount.usr=PARTUUID会被自动填充类型为root或/usr的分区的UUID。 
- 如果检测到使用了Verity的
 
镜像预设配置:
MachineID=:设置镜像内的机器ID,默认为random,也可以使用mkosi.machine-id文件保存。Locale=:镜像内的语言。Keymap=:镜像内的Keymap。Hostname=:设置镜像内的默认主机名。RootShell=:Root用户的默认Shell。RootPassword=(旧版本为Password=):设置镜像内Root用户的默认密码。- 也可以在工作目录下编写
mkosi.rootpw文件。 
- 也可以在工作目录下编写
 Autologin=:是否设置Root用户在/dev/pts/0、/dev/tty1和/dev/hvc0的自动登录。Ssh=:是否在镜像内创建SSH套接字以允许通过mkosi ssh连接,使用mkosi genkey创建密钥。SELinuxRelabel=:是否在镜像内进行Relabel。
为了实现更多功能,还可以在构建镜像的不同过程中执行脚本:
- (新版本)
SyncScripts=:在同步软件包管理器元数据后执行的脚本,默认为mkosi.sync。 PrepareScripts=:在安装软件包后立刻执行的脚本。默认为mkosi.prepare。BuildScripts=:在创建好根文件系统后立刻执行的脚本。默认为mkosi.build。BuildSources=:接受逗号分隔的,冒号绝对路径对。前者是主机上的路径,后者是镜像内的路径,进行构建时拷贝的代码树目录,镜像内的代码树目录总是会自动添加/work/src前缀。BuildSourcesEphemeral=:是否不保留对源码树的更改,默认禁用。
PostInstallationScripts=:在配置完Extra Tree后执行的脚本,默认为mkosi.postinst。FinalizeScripts=:在构建完全完成后的最后阶段执行的脚本,默认为mkosi.finalize。PostOutputScripts=:在输出产品后执行的脚本,默认为mkosi.postoutput。Environment=:给脚本传递的环境变量。EnvironmentFile=:从文件给脚本传递环境变量。WithTests=:设为假,则在执行mkosi.build脚本时,$WITH_TESTS变量为0。WithNetwork=:在执行脚本时提供网络。
[Validation]段
SecureBoot=:是否启用安全启动,这会影响是否对UKI进行签名。SecureBootAutoEnroll=:是否自动导入安全启动的Key。- 这仅对虚拟机生效,如果希望对物理机生效,在Extra Tree中包含
/efi/loader/loader.conf文件,并写入secure-boot-enroll force或secure-boot-enroll manual。 
- 这仅对虚拟机生效,如果希望对物理机生效,在Extra Tree中包含
 SecureBootKey=:使用的安全启动PEM密钥。默认使用mkosi.key。SecureBootCertificate=:使用的安全启动X509证书。默认使用mkosi.crt。SecureBootSignTool=:为PE文件进行安全启动签名的程序,可选systemd-sbsign、sbsign、pesign或auto。SignExpectedPcr=:使用systemd-measure在UKI中包含PCR(平台配置寄存器)的签名,可选布尔值或auto。Passphrase=:LUKS加密的密钥文件,必须是600权限位,它应当保存完整的LUKS密钥,以一个换行结尾(即/etc/crypttab文件的格式)。- 也可以选择在工作目录下创建
mkosi.passphrase文件。 
- 也可以选择在工作目录下创建
 VerityKey=:用于为Verity设备签名的PEM密钥。默认使用mkosi.key。VerityCertificate=:用于为Verity设备签名的X509证书。默认使用mkosi.crt。Checksum=:指定镜像的校验码。Sign=:是否用gpg给校验码签名。默认为否。Key=:给校验码签名的密钥。OpenPGPTool=:使用的OpenPGP实现,默认为gpg,可选值有sqop、rsop。
[Runtime]段(旧版本为[Host]段)
Credentials=:启动时传递给镜像中的systemd的系统凭据。
容器配置:
NSpawnSettings=:使用systemd-nspawn启动时,读取的.nspawn单元文件。- 默认使用
mkosi.nspawn文件。 
- 默认使用
 
所有虚拟机配置项都仅适用于使用qemu启动的虚拟机,即只适用于磁盘类型的镜像:
VirtualMachineMonitor=:使用的虚拟机超管,可选值有qemu或vmspawn。QemuGui=:若启用,会以图形界面形式启动Qemu。默认以Headless形式启动。- 旧版本下为
QemuHeadless=:若启用,会以Headless形式启动Qemu。默认以图形界面形式启动。 
- 旧版本下为
 QemuSmp=:设置Qemu的SMP。默认为2。QemuMem=:设置Qemu的内存。默认为2G。QemuKvm=:是否启用KVM加速,默认为auto。QemuVsock=:是否启用VSock,默认为auto。QemuVsockConnectionId=:VSock的连接ID,可选值有hash、auto或手动输入。QemuSwtpm=:是否启用TPM,默认为auto。QemuCdrom=:是否在Qemu中以CD形式读取镜像,默认禁用。QemuBoot=:使用的Qemu固件,可选uefi、linux。- 新版本下改为
QemuFirmware=:可选uefi、bios、linux、auto。 - 新版本下可以使用
QemuFirmwareVariables=设置UEFI固件中的变量。 - 新版本下可用
QemuKernel=,指定使用的Direct Boot Kernel。 
- 新版本下改为
 QemuDrives=:添加的驱动器,格式为ID:大小[:目录:选项]。RuntimeTrees=接受逗号分隔的,冒号绝对路径对。前者是主机上的路径,后者是虚拟机内的路径,如果没有后面的部分,则自动挂载在/root/src目录下。RuntimeSize=:将镜像在启动时扩大到指定大小。RuntimeNetwork=:使用的Qemu网络,可选值有user、interface或none。RuntimeBuildSources=:挂载指定的源代码目录到虚拟机内的/work目录下。RuntimeHome=:是否挂载主机的家目录到虚拟机的/root。RuntimeScratch=:是否在/var/tmp下挂载额外的空间。可选值为布尔值或auto。UnitProperties=:传递给NSPawn的Scope属性。KernelCommandLineExtra=:通过Qemu传递的额外内核命令行参数。- 在Qemu中硬编码的额外内核命令行参数为(mkosi/mkosi/qemu.py):
rwsystemd.wants=network.targetmodule_blacklist=vmw_vmci systemd.tty.term.hvc0=宿主机终端类型 systemd.tty.columns.hvc0=宿主机终端列数 systemd.tty.rows.hvc0=宿主机终端行数
 - 除非明确地手动进行设置,否则存在以下内核命令行参数的默认值:
ip=enc0:any ip=enp0s1:any ip=enp0s2:any ip=host0:any ip=noneloglevel=4SYSTEMD_SULOGIN_FORCE=1
 
- 在Qemu中硬编码的额外内核命令行参数为(mkosi/mkosi/qemu.py):
 QemuArgs:配置空格分隔的Qemu原生参数。Ephemeral=:是否将镜像设为不可变,所有操作在关闭之后都会撤销。SshKey=:使用的SSH私钥。SshCertificate=:使用的SSH证书。Machine=:机器名,用于SSH连接。ForwardJournal=:是否将容器或虚拟机的日志发送到宿主机。SysupdateDirectory=:mkosi sysupdate使用的配置目录,默认使用mkosi.sysupdate/。- MKOSI使用的Sysupdate配置必须设置
PathRelativeTo=explicit和Path=/才能正常使用sysupdate子命令进行更新,这会使得配置中的Path=使用mkosi.output/(或OutputDirectory=指定的目录)作为根。 - 这同时也意味着,
SplitArtifacts=必须启用以对分区进行更新,而且更新内容(分区镜像文件、EFI程序、initramfs)文件名必须与Sysupdate配置中的MatchPattern=匹配。 
- MKOSI使用的Sysupdate配置必须设置
 
分区
(旧版本,现已删除)在[Partitions]段内支持以下配置项:
RootSize=:根分区大小,默认为3G。ESPSize=:ESP大小,默认为256MB。仅在Bootable=yes时有效。SwapSize=:Swap分区大小,默认为0。HomeSize=:/home分区大小,默认为0。SrvSize=:/srv分区大小,默认为0。VarSize=:/var分区大小。默认为0。TmpSize=:/var/tmp分区大小。默认为0。BiosSize=:biosboot分区大小,默认为0。XbootldrSize=:XBOOTLDR分区大小。默认为0。UsrOnly=:仅仅保留/usr目录,很适合无状态的镜像。
MKOSI会从mkosi.repart/或RepartDirectories=指定的目录中读取systemd-repart的配置文件,并据此对磁盘镜像进行分区。文件命名应当为优先级-分区名.conf,格式为:
1  | [Partition]  | 
默认情况下,MKOSI使用以下内置配置:
00-esp.conf:
1  | [Partition]  | 
- 需要注意的是,
CopyFiles=的源路径的根是构建中的镜像的根。 
05-bios.conf:
1  | [Partition]  | 
10-root.conf:
1  | [Partition]  | 
资源目录
有以下相关的资源目录:
mkosi.conf.d/:额外的MKOSI配置,可以是文件,也可以是子工作目录,子工作目录支持的内容和MKOSI的主工作目录完全一致(必须包含mkosi.conf文件)。- 如果使用文件的话,那么文件中的
[Match]段仅对该文件生效。 - 如果使用子工作目录的话,那么子工作目录中的
mkosi.conf中的[Match]段对整个子工作目录生效。 
- 如果使用文件的话,那么文件中的
 mkosi.local/:额外的本地MKOSI配置,可以是文件,也可以是子工作目录。mkosi.skeleton/或mkosi.skeleton.tar:在已经构建基本根文件系统,开始安装软件包之前,将文件/目录拷贝到镜像内。与SkeletonTrees=配置项有关。mkosi.extra/或mkosi.extra.tar:在安装软件包之后,将额外的文件/目录拷贝到镜像内。与ExtraTrees=配置项有关。mkosi.pkgmngr/或mkosi.pkgmngr.tar:在构建时配置包管理器,但是不将文件写入镜像。这可以作为在构建时手动配置软件包管理器的手段,如果需要包含到镜像中,应该使用mkosi.skeleton/或mkosi.skeleton.tar。mkosi.nspawn:systemd-nspawn读取的容器单元文件。与NspawnSettings=配置项有关。mkosi.cache/:构建时软件包管理器缓存的保存目录。与CacheDirectory=配置项有关。mkosi.builddir/:用于执行Out-of-Tree构建的构建目录。与BuildDirectory=配置项有关。mkosi.rootpw:镜像中Root用户的密码。文件必须具有0600或更低的权限位。与RootPasswordFile=配置项有关。mkosi.passphrase:LUKS加密使用的密码。文件必须具有0600或更低的权限位。与PassphraseFile=配置项有关。mkosi.crt和mkosi.key:用于签名(UEFI SecureBoot、Verity等)的X.509证书和PEM私钥。与SecureBootCertificate=、SecureBootKey=、VerityCertificate=和VerityKey=配置项有关。mkosi.output/:用于保存所有的构建产品。与OutputDirectory=配置项有关。mkosi.credentials/:额外的系统凭据。目录中的每个文件名将用作凭据名,文件内容成为凭据值。与Credentials=配置项有关。mkosi.repart/:用于systemd-repart的分区定义文件,这些文件在构建磁盘镜像时传递给systemd-repart。如果存在mkosi.repart/或是使用了RepartDirectories=,那么就不会使用任何默认的分区定义。与RepartDirectories=配置项有关。mkosi.uki-profiles/:额外的UKI配置文件。与UnifiedKernelImageProfiles=配置项有关。mkosi.pe-addons/:额外的PE插件的ukify配置文件。与PeAddons=配置项有关。
钩子脚本
钩子脚本如果在末尾添加了.chroot后缀(例如,mkosi.postinst.chroot),那么会Chroot到镜像内部执行,否则会在工作环境中执行,脚本中有以下可用变量:
| Variable | 含义 | configure | 
sync | 
prepare | 
build | 
postinst | 
finalize | 
postoutput | 
clean | 
|---|---|---|---|---|---|---|---|---|---|
$ARCHITECTURE | 
镜像的架构 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | 
$QEMU_ARCHITECTURE | 
Qemu格式的架构,用于通过qemu-system-$QEMU_ARCHITECTURE获取Qemu程序 | 
✓ | |||||||
$DISTRIBUTION | 
镜像的发行版 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | 
$DISTRIBUTION_ARCHITECTURE | 
发行版格式的架构 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | 
$RELEASE | 
镜像的版本 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | 
$PROFILES | 
Profiles=中设置的配置文件,使用逗号分隔 | 
✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | |
$CACHED | 
如果有可用的缓存,为1 | 
✓ | |||||||
$CHROOT_SCRIPT | 
Chroot的目标路径,用于结合mkosi-chroot使用 | 
✓ | ✓ | ✓ | ✓ | ||||
$SRCDIR | 
执行Chroot前的路径 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | 
$CHROOT_SRCDIR | 
执行Chroot以后,原来的目录所在的路径 | ✓ | ✓ | ✓ | ✓ | ||||
$BUILDROOT | 
当前正在构建的镜像的根目录 | ✓ | ✓ | ✓ | ✓ | ||||
$BUILDDIR | 
树外构建目录的路径 | ✓ | ✓ | ✓ | ✓ | ||||
$CHROOT_BUILDDIR | 
Chroot以后,树外构建目录的路径 | ✓ | |||||||
$DESTDIR | 
构建脚本生成产品的保存目录 | ✓ | |||||||
$CHROOT_DESTDIR | 
Chroot以后,构建脚本生成产品的保存目录 | ✓ | |||||||
$OUTPUTDIR | 
构建产品的暂存目录 | ✓ | ✓ | ✓ | ✓ | ✓ | |||
$CHROOT_OUTPUTDIR | 
Chroot以后,构建产品的暂存目录 | ✓ | ✓ | ✓ | |||||
$PACKAGEDIR | 
本地包存储的目录 | ✓ | ✓ | ✓ | ✓ | ||||
$ARTIFACTDIR | 
构建产品的目录 | ✓ | ✓ | ✓ | ✓ | ||||
$WITH_DOCS | 
是否有文档 | ✓ | ✓ | ||||||
$WITH_TESTS | 
是否有测试 | ✓ | ✓ | ||||||
$WITH_NETWORK | 
是否有网络 | ✓ | ✓ | ✓ | ✓ | ||||
$SOURCE_DATE_EPOCH | 
如果设置了SourceDateEpoch=TIMESTAMP,那么会保存时间戳 | 
✓ | ✓ | ✓ | ✓ | ✓ | |||
$MKOSI_UID | 
调用mkosi的用户UID | 
✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | 
$MKOSI_GID | 
调用mkosi的用户GID | 
✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | 
$MKOSI_CONFIG | 
当前镜像配置的JSON | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | |
$IMAGE_ID | 
ImageID=的值 | 
✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | 
$IMAGE_VERSION | 
ImageVersion=的值 | 
✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | 
此外,以下命令可用:
mkosi-chroot:一个封装的chroot,会自动Chroot到镜像内执行命令。- 镜像的包管理器可用,你也可以使用
mkosi-install|remove|upgrade|reinstall封装工具。 git已经自动配置好safe.directory=*。useradd和groupadd已经自动配置好--root=$BUILDROOT。
执行流程
创建MKOSI沙箱:
- 解析命令行选项。
 - 解析配置文件。
 - 执行
mkosi.configure脚本。 - 检查当前用户是不是Root,如果当前用户不是Root,则尝试根据当前用户的SubUID和SubGID隔离用户命名空间。
 - 隔离挂载命名空间。
 - 只读化重新挂载各种目录,包括:
/usr/etc/opt/srv/boot/efi/media/mnt
 
开始构建镜像:
- (新版本)拷贝Sandbox Tree(
mkosi.sandbox/)中的文件到镜像中。 - 更新软件包元数据。
 - 执行Sync脚本(
mkosi.sync), - 拷贝Base Tree(
mkosi.base/)中的文件到镜像中。 - 检查并尝试复用缓存镜像。
 - 拷贝一份包管理器元数据到镜像内。
 - 拷贝Skeleton Tree(
mkosi.skeleton/)中的文件到镜像中。 - 安装发行版及其软件包。
 - 使用
final参数执行mkosi.prepare脚本。 - 如果存在
mkosi.build脚本的话,在Overlayfs中安装构建所需的软件包。 - 使用
build参数执行mkosi.prepare脚本。 - 如果存在对应的配置的话,缓存该镜像。
 - 执行
mkosi.build脚本。 - 结束构建。
 - 拷贝构建脚本的产物到镜像内。
 - 拷贝Extra Tree(
mkosi.extra/)中的文件到镜像中。 - 执行
mkosi.postinst脚本。 - 写入配置项中配置的其他杂项文件。例如
Ssh=、Autologin=和MakeInitrd=。 - 安装
systemd-boot,并按需配置安全启动。 - 执行
systemd-sysusers。 - 执行
systemd-tmpfiles。 - 执行
systemctl preset-all。 - 执行
depmod。 - 执行
systemd-firstboot。 - 执行
systemd-hwdb。 - 移除指定的软件包和文件。
 - 按需执行SELinux Relabel。
 - 执行
mkosi.finalize脚本。 - 如果存在对应的配置的话,生成UKI镜像。
 - 导出产物。
 - 执行
mkosi.postoutput脚本。 
最佳实践
- 创建工作目录,并使用
mkosi.conf和mkosi.conf.d/*.conf(或mkosi.conf.d/*/mkosi.conf)配置文件以固化构建信息。 - 使用
mkosi.postinst.chroot脚本在镜像中进行配置。 - 使用
mkosi.extra向镜像中传递额外文件。 - 使用
mkosi.build.chroot基本进行流水线构建。在脚本中使用$BUILDDIR和$SRCDIR获取目录。 - 缓存有两种方式:使用
mkosi.cache目录进行包缓存,或是使用Incremental=进行渐进构建。需要重建渐进缓存时,使用-ff选项。 - 要测试不同的内核命令行参数的效果,使用
KernelCommandLineExtra=而不是重建镜像,以提高效率。 - 可以在无特权的情况下构建磁盘镜像,但是容器文件系统仍然需要Root权限。
 - 在启用
SecureBoot=yes时,可以执行mkosi genkey直接生成证书和密钥,也可以自己创建mkosi.key和mkosi.crt。你还可以使用ShimBootloader=yes以安装Shim。 - 使用
BiosBootloader=grub以为BIOS引导安装GRUB。 - 使用
useradd -m -g $USER --password "$(openssl passwd -stdin -6 <<< '密码明文')"添加一个普通用户。 - 在Debian中
mkosi qemu不可用,解决方案为执行cp /usr/lib/tmpfiles.d/static-nodes-permissions.conf /etc/tmpfiles.d/static-nodes-permissions.conf,修改/dev/kvm的权限位为0666。 - 在非特权模式构建时,
chown()调用是被禁用的(钩子脚本中没有禁用,要禁用,设置环境变量MKOSI_CHROOT_SUPPRESS_CHOWN=1),要解决该问题,使用SubUID:unshare --map-auto --map-current-user --setuid 0 --setgid 0。 - 在你正式构建时,使用
WithRecommends=no以安装弱依赖。 - 在使用
dd克隆产品镜像前,执行truncate -s|--size=文件大小 镜像文件.img以调整磁盘镜像大小。 - MKOSI可以负责构建initramfs,因此一个没有initramfs构建工具的镜像是可能的。
- 不过需要注意的是,MKOSI构建的initramfs中会使用systemd作为
/init,这与使用MKOSI-INITRD构建的initramfs是一致的。 
 - 不过需要注意的是,MKOSI构建的initramfs中会使用systemd作为
 - 使用
mkosi.profiles/保存不同的镜像口味,使用mkosi.conf.d/保存不同情况下的镜像配置,对于多种子场景的情况,将情况相对少且固定的子场景放在父目录(例如,输出格式为容器或VM),将情况相对较多且不固定的子场景放在子目录(例如,版本)。 - 使用
Format=uki和MakeInitrd=no来创建一个USI(Unified System Image,单个UEFI PE形式的完整系统)。 
发行版最小化构建
一些发行版的最小化构建软件包如下:
Arch
1  | [Content]  | 
Fedora
1  | [Content]  | 
CentOS/Rocky
1  | [Content]  | 
Debian
1  | [Content]  | 
Ubuntu
1  | [Distribution]  | 
OpenSUSE
1  | [Content]  | 
实例
构建一个Fedora容器镜像
使用命令行:
1  | mkosi -d fedora -p kernel,systemd,systemd-udev,systemd-boot --format directory build  | 
使用配置文件:
1  | # mkosi.conf  | 
然后执行:
1  | mkosi build  | 
构建一个Debian可引导磁盘镜像
使用配置文件:
1  | # mkosi.conf  | 
然后执行:
1  | mkosi build  | 
构建initramfs
mkosi.conf:
1  | [Output]  | 
构建一个USI(UEFI PE程序形式的完整系统镜像)
具体的精简方式见Build USI。
mkosi.conf:
1  | [Distribution]  | 
构建一个系统扩展镜像
mkosi.conf:
1  | [Output]  | 
mkosi.images/base/mkosi.conf(扩展镜像相对的基础镜像):
1  | [Output]  | 
- 在启用了
Incremental=yes的情况下,子镜像不能是Bootable=yes,否则会导致Cache冲突。 
mkosi.images/btrfs/mkosi.conf
1  | [Config]  | 
构建一个不可变操作系统
首先创建一个如下分区的操作系统:
00-esp.conf:
1  | [Partition]  | 
10-root-verity-sig.conf:
1  | [Partition]  | 
11-root-verity.conf:
1  | [Partition]  | 
12-root.conf:
1  | [Partition]  | 
除此之外我们还需要构建一个initramfs,initramfs中的systemd-repart.service的启动时间需要进行些许修改:
mkosi.images/initrd/mkosi.conf
1  | [Include]  | 
mkosi.images/initrd/mkosi.extra/usr/lib/systemd/system/systemd-repart.service.d/sysroot.conf:
1  | [Unit]  | 
为了进行AB更新,我们还需要在镜像中包含一些预设的分区配置:
mkosi.extra/usr/lib/repart.d/00-esp.conf:
1  | [Partition]  | 
mkosi.extra/usr/lib/repart.d/10-root-verity-sig.conf:
1  | [Partition]  | 
mkosi.extra/usr/lib/repart.d/11-root-verity.conf:
1  | [Partition]  | 
mkosi.extra/usr/lib/repart.d/12-root.conf:
1  | [Partition]  | 
mkosi.extra/usr/lib/repart.d/20-root-verity-sig.conf:
1  | [Partition]  | 
mkosi.extra/usr/lib/repart.d/21-root-verity.conf:
1  | [Partition]  | 
mkosi.extra/usr/lib/repart.d/22-root.conf:
1  | [Partition]  | 
mkosi.extra/usr/lib/repart.d/30-swap.conf:
1  | [Partition]  | 
mkosi.extra/usr/lib/repart.d/40-var.conf:
1  | [Partition]  | 
因为/etc不可变,所以我们还需要在构建时提供Machine ID:
1  | systemd-id128 new > mkosi.machine-id  | 
最后为了未来镜像中的系统更新,我们还需要提供systemd-sysupdate的配置(你需要自行补充[Source]段):
mkosi.extra/usr/lib/sysupdate.d/10-root-verity-sig.transfer:
1  | [Transfer]  | 
mkosi.extra/usr/lib/sysupdate.d/11-root-verity.transfer:
1  | [Transfer]  | 
mkosi.extra/usr/lib/sysupdate.d/12-root.transfer:
1  | [Transfer]  | 
mkosi.extra/usr/lib/sysupdate.d/20-uki.transfer:
1  | [Transfer]  | 
构建一个不安全的/usr不可变操作系统
由于上文提到的原因(UKI必须使用Verity Hash对/usr/分区进行定位),我们无法让MKOSI在构建镜像时,自动向UKI中填充/usr/分区所在的位置,因此,我们必须手动在mkosi.conf中设置:
1  | [Content]  | 
systemd-repart配置如下:
00-esp.conf:
1  | [Partition]  | 
10-usr.conf:
1  | [Partition]  | 
此外,还需要在镜像内提供一些分区配置:
mkosi.extra/usr/lib/repart.d/00-esp.conf:
1  | [Partition]  | 
mkosi.extra/usr/lib/repart.d/10-usr-verA.conf:
1  | [Partition]  | 
mkosi.extra/usr/lib/repart.d/20-usr-verB.conf:
1  | [Partition]  | 
mkosi.extra/usr/lib/repart.d/30-swap.conf:
1  | [Partition]  | 
mkosi.extra/usr/lib/repart.d/40-root.conf:
1  | [Partition]  | 
mkosi.extra/usr/lib/repart.d/50-home.conf:
1  | [Partition]  | 
我们还需要确保/etc/目录在启动时动态生成,因此需要:
mkosi.extra/usr/lib/tmpfiles.d/etc.conf:
1  | # 仅作参考  | 
为了确保ldconfig.service在/etc/目录生成后再启动,我们还需要:
mkosi.extra/usr/lib/systemd/system/ldconfig.service.d/tmpfiles.conf:
1  | [Unit]  | 
最后,我们需要MKOSI的更新配置:
mkosi.sysupdate/10-usr.transfer:
1  | [Transfer]  | 
mkosi.sysupdate/20-uki.transfer:
1  | [Transfer]  |