CoreOS rpm-ostree简介

CoreOS rpm-ostree简介

荣涛
2021年11月12日

文档修改日志

日期修改内容修改人备注
2021年11月12日创建荣涛

1. 引言

rpm-ostree 是一个混合镜像/包系统。它结合了libostree作为基础镜像格式,在客户端和服务器端都接受RPM,与dnf项目共享代码;特别是libdnf。从而将两者的许多好处结合在一起。

                         +-----------------------------------------+
                         |                                         |
                         |       rpm-ostree (daemon + CLI)         |
                  +------>                                         <---------+
                  |      |     status, upgrade, rollback,          |         |
                  |      |     pkg layering, initramfs --enable    |         |
                  |      |                                         |         |
                  |      +-----------------------------------------+         |
                  |                                                          |
                  |                                                          |
                  |                                                          |
+-----------------|-------------------------+        +-----------------------|-----------------+
|                                           |        |                                         |
|         libostree (image system)          |        |            libdnf (pkg system)          |
|                                           |        |                                         |
|   C API, hardlink fs trees, system repo,  |        |    ties together libsolv (SAT solver)   |
|   commits, atomic bootloader swap         |        |    with librepo (RPM repo downloads)    |
|                                           |        |                                         |
+-------------------------------------------+        +-----------------------------------------+

特征:

  • 事务性、基于背景image(版本化/校验和)的升级
  • 通过 libostree 在不影响用户数据(/usr/etc但不影响/var)的情况下回滚操作系统
  • 客户端包分层(和覆盖)
  • 轻松制作自己的衍生品

1.1. 使用 rpm-ostree 的项目

OSTree 项目独立于发行版,与内容的交付和管理方式无关;它今天被 Debian、Fedora 和 OpenEmbedded 派生系统等使用。OSTree github中有一些示例。

相比之下,rpm-ostree 旨在与 Fedora 生态系统紧密集成。今天它是Fedora CoreOS及其衍生的RHEL CoreOS的底层更新机制。Fedora IoTFedora Silverblue也使用它。

最初,它是作为Project Atomic 的一部分进行生产的。

1.2. 入门

如果您想以用户身份试用该系统,请查看Fedora主网站,该网站有多个使用 rpm-ostree 的版本,包括 Silverblue、IoT 和 CoreOS。如果您对组装自己的系统感兴趣,请参阅compose server

1.3. 为什么使用rpm-ostree

aptyum 等软件包系统在基于 Linux 的操作系统中非常流行。它们提供了很大的灵活性,但有许多故障模式。

rpm-ostree 的核心前提是离线事务性基于镜像的更新应该是默认的。这提供了高度的可预测性和弹性。操作系统供应商可以将大量精力集中在测试作为一个单元的“基本映像”上。

此外,基于图像的更新在规模上运行得更好。对于“物联网”风格的设备,让每台机器执行依赖解析、运行包脚本等是非常低效的。许多服务器数据中心用例也是如此。

rpm-ostree 在生态系统中相当独特的地方是支持客户端包分层和覆盖将 RPM 深度集成为 OSTree 之上的(可选)层。

考虑包分层的一个好方法是将 RPM 重铸为“操作系统扩展”,类似于浏览器扩展的工作方式(尽管在沙盒之前)。可以对不容易容器化的组件使用包分层,例如 PAM 模块、自定义 shell 等。

此外,人们可以轻松地使用rpm-ostree override replace与传统系统相同的 RPM 来覆盖内核或用户空间组件。例如,Fedora 项目仍然只有一个内核构建。

分层和覆盖仍然建立在默认的 OSTree 引擎之上。安装和更新客户端包构建一个新的文件系统根,默认情况下它不会影响你引导的根。这保留了系统的“image”性质。

rpm-ostree 作为混合镜像/包系统的性质,旨在涵盖当前包系统和镜像系统的几乎所有用例。

rpm-ostree 相对于传统包管理的一项主要功能是原子升级/回滚。它支持操作系统供应商(例如CentOSFedora)可以提供预先组装的“基本操作系统映像”的模型,并且客户端系统可以复制这些,并且可能在附加包上分层。

1.4. 为什么不在现有的包管理器中实现这些更改?

OSTree相关项目部分涵盖这在一定程度上。一旦开始拍摄“快照”或跟踪多个根源,就会发现许多问题。例如,具体向前或向后滚动哪些内容?如果包管理器没有深入了解快照工具,则很容易失去一致性。

1.4.1. 文件系统布局

一个具体的例子是 rpm-ostree 将 RPM 数据库移动到/usr/share/rpm,因为我们想要每个 root 一个/usr。相比之下,甲鱼工具使用了一些努力,包括/var/lib/rpm在快照,但要避免滚滚向前/返回登录文件/var/log

OSTree 需要围绕升级/usr/var跨升级等目录的语义制定明确的规则,虽然这需要更改一些软件,但我们相信结果比将两个独立的系统(如 yum 和snapper粘在一起,或 apt-get 和 BTRFS 等)可靠得多.

1.4.2. 用户体验

此外,除了文件系统布局等机制之外,实施的升级模型还会影响整个用户体验。

例如,基本系统 OSTree 承诺从远程服务器复制的一个可以分配版本号。它们作为连贯的整体发布,一起测试。如果只是在客户端执行快照,则每台客户端机器都可以有不同版本的组件。

与此相关的是 rpm-ostree 清楚地区分您已分层的包,并且很容易删除它们,回到原始的已知状态。许多包管理器只是实现了一个没有明确基础或分层的“包包”模型。随着操作系统随着时间的推移而发展,“包漂移”发生在您可能有旧的、未使用的包散布的地方。

1.5. 前瞻性

另一方面,rpm-ostree 在其他方面是非常前卫的。已经发明了很多不同的包管理器——为什么不采用或建立在上面的其中之一之上呢?

这里的答案是在包格式之上构建工具需要很长时间——比如镜像服务器。另一个例子是源格式表示——有很多工具知道如何构建源 RPM。

从构建了所有生态系统的发行版的角度来看,rpm-ostree 确实引入了一种新的二进制格式 (ostree),但除此之外还包括一个 RPM 数据库,并且还对包进行操作。它也不是一种新的源格式。

有许多Project Atomic演讲可供使用;例如,请参阅这篇文章,其中有一个更大的集合,其中还包括有关容器的讨论。

rpm-ostree 具体会谈:

devconf.cz 2018:Colin Walters:使用 rpm-ostree 进行混合映像/软件包操作系统更新幻灯片
devconf.cz 2018:Peter Robinson:将 Fedora 和 OSTree 用于物联网

1.6. 许可

rpm-ostree 包含在 GPLv2+、LGPLv2+(Apache 2.0 或 MIT)下许可的代码。

2. 背景

https://coreos.github.io/rpm-ostree/background/

2.1.1. 包系统的优点

  • 高度动态,快速访问各种软件
  • 状态管理中的/etc并且/var很好理解
  • 可以在主要/次要系统状态之间交换(apt-get upgrade类似于apt-get dist-upgrade
  • 一般支持任何文件系统或分区布局

2.1.2. 包系统的缺点

  • 随着包集的增长,测试变得更加昂贵
  • 实时系统突变,无回滚

2.1.3. 镜像系统的优点

  • 确保所有用户都在运行一个已知状态
  • 支持回滚
  • 更容易验证系统完整性

2.1.4. 镜像系统的缺点

  • 许多镜像系统在/etc其他地方都有只读分区和可写分区
  • 必须重新启动才能更新
  • 通常在块级别操作,因此需要固定的分区布局和文件系统
  • 许多使用“双根”模式,浪费空间且不灵活
  • 通常与单独的应用程序机制配对,但会错过不是应用程序的东西
  • 管理员需要知道里面的内容

2.2. rpm-ostree 如何提供中间立场

默认模式下的 rpm-ostree 感觉更像是镜像复制,但底层架构允许很多类似包的灵活性。

在此默认模式下,包在服务器上组合,客户端可以可靠地复制该状态。例如,如果在撰写服务器上添加了一个包,客户端就会得到它。如果删除了一个包,它也会在客户端升级时被删除。

rpm-ostree 的一个简单思维模型是:想象在服务器端获取一组包,将它们安装到 chroot,然后git commit对结果进行处理。想象一下客户就是git pull -rOSTree 添加到此图片的是对文件 uid/gid、扩展属性、引导加载程序配置的处理以及/etc.

强调一下,复制是在文件系统级别 - 这意味着在服务器端分配诸如 SELinux 标签和 uid/gid 映射之类的东西。

另一方面,rpm-ostree 可以在任何 Unix 文件系统之上运行。它不会干扰任何文件系统或块级快照或备份,例如 LVMBTRFS

3. 客户管理

3.1. 管理基于 rpm-ostree 的系统

目前,在rpm-ostree基于系统的系统上有四个主要命令需要熟悉。

# rpm-ostree status
State: idle
Deployments:
● fedora-atomic:fedora/27/x86_64/atomic-host
                   Version: 27.44 (2018-01-01 21:54:31)
                    Commit: b5845ebd002b2ec829c937d68645400aa163e7265936b3e91734c6f33a510473
              GPGSignature: Valid signature by 860E19B0AFA800A1751881A6F55E7430F5282EE4

将按照它们在引导加载程序中出现的顺序向您显示您的部署,列表中的第一个部署是当前的默认部署。将●显示当前启动部署。

# rpm-ostree upgrade
...
... Version: 27.61 (2018-01-17 15:52:47)

将准备离线系统升级,创建新部署(根文件系统)并将其设置为下次启动的默认值。更新将在关机时“完成”并准备好新的引导加载程序条目。因此,用于reboot应用更新。

# rpm-ostree rollback

这将回滚到之前的状态,即默认部署与非默认部署更改位置。默认情况下,rpm-ostree upgrade尽管底层技术支持更多,但最多会保留两个可引导的“部署”。

# rpm-ostree deploy <version>

该命令利用了 OSTree 的服务器端历史功能。它将在当前分支的历史记录中搜索具有指定版本的提交,并部署它。这可以在脚本中使用以确保一致的更新。例如,如果上游操作系统供应商在线提供更新,您可能不想在测试之前部署它。这有助于确保在您升级时,您得到的正是您所要求的。

3.1.1. 通过包分层的混合镜像/包

可以将更多包动态添加到系统中,这些包不属于服务器上提交的提交的一部分。这些额外的“分层”包在升级、变基和部署中是持久的(与 ostree解锁机制相反)。

ostree-admin-unlock
OSTREE ADMIN UNLOCK(1)         ostree admin unlock        OSTREE ADMIN UNLOCK(1)

NAME
       ostree-admin-unlock - Prepare the current deployment for hotfix or
       development

SYNOPSIS
       ostree admin unlock [OPTIONS...]

DESCRIPTION
       Remove the read-only bind mount on /usr and replace it with a writable
       overlay filesystem. This default invocation of "unlock" is intended for
       development/testing purposes. All changes in the overlay are lost on
       reboot. However, this command also supports "hotfixes", see below.

OPTIONS
       --hotfix
           If this option is provided, the current deployment will be cloned as
           a rollback target. This option is intended for things like emergency
           security updates to userspace components such as sshd. The semantics
           here differ from the default "development" unlock mode in that
           reboots will retain any changes (which is what you likely want for
           security hotfixes).

OSTree                                                    OSTREE ADMIN UNLOCK(1)

这就是 rpm-ostree 真正的混合镜像/包特性发挥作用的地方;您将获得图像和包的优点的组合。包更新仍然是完全事务性的和离线的。

例如,您可以使用包分层来安装 3rd 方内核模块或用户空间驱动程序守护程序,例如pcsc-lite-ccid. 虽然大多数软件都应该放入容器中,但您可以完全灵活地在适合的地方使用包。

# rpm-ostree install <pkg>

例如:https://fedorapeople.org/~walters/2018.01-devconf/index.html#/6/3

# rpm-ostree install libvirt
...  (Maybe other system prep, followed by reboot)
# rpm-ostree status
State: idle
Deployments:
● fedora-atomic:fedora/27/x86_64/atomic-host
                   Version: 27.44 (2018-01-01 21:54:31)
                BaseCommit: b5845ebd002b2ec829c937d68645400aa163e7265936b3e91734c6f33a510473
           LayeredPackages: libvirt
#

将下载目标包及其依赖项,并使用安装的这些包创建新部署。也可以指定一个不属于存储库的本地包。

要删除分层包,请使用:

# rpm-ostree uninstall <pkg>

要卸载属于基础层的包,请使用:

# rpm-ostree override remove <pkg>

例如:

# rpm-ostree override remove firefox

再例如:https://fedorapeople.org/~walters/2018.01-devconf/index.html#/6/5

# rpm-ostree override remove docker
...
# rpm-ostree status
...
     RemovedBasePackages: docker-2:1.13.1-44.git584d391.fc27.x86_64
# curl -L -O http://myrepo.example.com/iptables-patched.x86_64.rpm
# rpm-ostree override replace ./iptables-patched.x86_64.rpm

默认情况下,每个rpm-ostree操作都是“离线”的,它对您正在运行的系统没有影响,只有在您重新启动时才会生效。这种“待定”状态称为“待定部署”。操作可以链接;例如,如果您rpm-ostree upgrade在安装软件包后调用,您的新根目录将随着软件包的安装而升级。

3.1.2. 模块化

rpm-ostree 为模块提供实验性支持,这是一种分发同一软件的多个版本(或“流”)的方式。

一个模块可以有多个流,每个流可以有多个配置文件。配置文件是一组用于常见用例的包(例如,您可以有一个“客户端”和“服务器”配置文件,每个配置文件都安装不同的包)。

rpm-ostree ex module enable启用模块流并允许您rpm-ostree install从该流中单独挑选包。rpm-ostree ex module install直接安装模块流配置文件。

例如,要启用cri-o:1.20模块流,请使用:

# rpm-ostree ex module enable cri-o:1.20

然后,您可以rpm-ostree install从启用的模块中获取单个包。

或者要安装预定义的配置文件,请使用例如:

# rpm-ostree ex module install cri-o:1.20/default

有关模块化的更多信息,请参阅Fedora 文档。特别是,此页面提供了示例语法调用。

下图链接:https://docs.fedoraproject.org/en-US/modularity/
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CDKO3BUm-1636806591411)(_v_images/20211112142115689_19534.png =800x)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2B9G7wpw-1636806591412)(_v_images/20211112142132008_2826.png =800x)]

3.1.3. rebase

# rpm-ostree rebase -b $branchname

例如:
https://fedorapeople.org/~walters/2018.01-devconf/index.html#/6/2

# rpm-ostree rebase fedora-atomic-27:fedora/27/x86_64/atomic-host
...
# rpm-ostree status
  fedora-atomic-27:fedora/27/x86_64/atomic-host
                   Version: 27.44 (2018-01-01 21:54:31)
                    Commit: b5845ebd002b2ec829c937d68645400aa163e7265936b3e91734c6f33a510473

● fedora-atomic:fedora/26/x86_64/atomic-host
                   Version: 26.141 (2017-10-05 09:29:15)
                    Commit: 541abd650d1ffb3929e2ba8114436a0b04ee41da76a691af669dd037589a1421

您的操作系统供应商可能会提供多个基本分支。例如,Fedora Atomic Host 有以下形式的分支:

fedora/27/aarch64/atomic-host
fedora/27/aarch64/testing/atomic-host
fedora/27/aarch64/updates/atomic-host
fedora/27/ppc64le/atomic-host
fedora/27/ppc64le/testing/atomic-host
fedora/27/ppc64le/updates/atomic-host
fedora/27/x86_64/atomic-host
fedora/27/x86_64/testing/atomic-host
fedora/27/x86_64/updates/atomic-host

您可以使用rebase命令在这些之间切换;这可以代表主要版本升级,或者在同一版本中的不同“测试”流之间进行逻辑切换。与其他rpm-ostree所有操作一样,所有分层包和本地状态都将被传递。

3.1.4. 其他本地状态更改

查看man rpm-ostree更多。例如,有一个rpm-ostree initramfs命令可以启用本地 initramfs 生成。

3.1.5. 实验界面

有一个rpm-ostree ex提供实验性功能的通用命令。其中之一是rpm-ostree ex apply-live,它提供了将更改从挂起部署应用到启动部署的能力。

有关man rpm-ostree更多信息,请参阅。

3.2. 文件系统布局

唯一可写的目录是/etc/var。特别是,/usr始终具有只读绑定安装。/var永远不会触及其中的任何数据,并在升级之间共享。

在升级时,该过程采用新的默认值 /etc,并在顶部添加您的更改。这意味着升级将在 中接收新的默认文件/etc,这是一个非常关键的功能。

有关更多信息,请参阅OSTree:适应。

3.3. 操作系统变化

RPM 数据库存储在 中/usr/share/rpm,并且是不可变的。
需要一个包nss-altfiles,系统密码数据库存放在/usr/lib/passwd. 组数据库类似。这在未来可能会改变;看到这个问题。

4. DNF Count Me 支持

基于经典 DNF 的操作系统可以使用DNF Count Me 功能匿名报告系统运行了多长时间,而不会影响用户隐私。这是作为一个附加countme变量实现的,它添加到为获取 RPM 存储库元数据而提出的请求中。在这些系统上,此值随机添加到通过dnf-makecache.timer或 显式调用dnf update或自动发出的请求中dnf install。

但是,这不适用于rpm-ostree基于系统的默认情况下(没有包覆盖在基本提交之上),rpm-ostree根本不会获取任何 RPM 存储库元数据。

因此rpm-ostree包括一个独特的计时器 (rpm-ostree-countme.timer),每周触发,以独立的方式实现 DNF Count Me 功能。

4.1. 在系统上禁用 DNF Count Me

要禁用此功能,您需要停止rpm-ostree-countme.timer并屏蔽相应的单元作为预防措施:

$ systemctl mask --now rpm-ostree-countme.timer

5. 构造镜像

https://coreos.github.io/rpm-ostree/compose/

5.1. 构造服务器

https://coreos.github.io/rpm-ostree/compose-server/

5.1.1. 管理基于 RPM 的 OSTree 提交

有了rpm-ostree compose一个工具,您就可以根据树文件配置、几个 RPM、一些后期处理以及可能直接在结果树中进行一些自定义修改来组成您自己的 ostree 提交。

该工具允许使用单个命令一次性构建树提交:rpm-ostree compose tree. 或者使用rpm-ostree compose install, 后跟rpm-ostree compose postprocess和 finally将该过程分成更小的块rpm-ostree compose commit。虽然前一种方法非常完整并且允许大多数用例,但如果您需要对生成的文件系统进行更多自定义,则后者很有用。比树文件允许的沙盒后处理功能更多的自定义。

在大多数情况下,您需要考虑使用比rpm-ostree compose.

5.1.2. 使用更高级别的构建工具

最初rpm-ostree compose tree旨在成为“高级”工具,但在实践中效果不佳。今天,您应该将其视为低级工具。例如,大多数想要生成 OSTree 提交的人也想生成可引导磁盘映像,而 rpm-ostree 与此无关。

一个负责 OSTree 提交生成和可引导磁盘映像的高级工具示例是coreos-assembler;它强烈面向“类 CoreOS”系统,包括 rpm-ostree 和 Ignition。

osbuild项目有基于rpm的ostree系统一些支持。例如,请参阅How to: Image Builder + OSTree + Anaconda

5.1.3. 管理 OSTree 存储库的背景

在开始之前,建议阅读(至少)OSTree 手册的这两部分:

具体见ostree手册

5.1.4. 选择基本配置

目前,rpm-ostree 与 Fedora 项目相当耦合。但是,我们愿意支持其他发行版。

示例基本 rpm-ostree “清单存储库”是:

5.1.5. 运行rpm-ostree compose tree

该程序将描述目标系统的清单文件作为输入,并将结果提交到 OSTree 存储库。

输入格式是 YAML(或 JSON)“树文件”。

如果您多次这样做,强烈建议创建一个缓存目录:

# rpm-ostree compose tree --unified-core --cachedir=cache --repo=./build-repo /path/to/manifest.yaml

这将从引用的存储库下载 RPM,并将结果提交到 OSTree 存储库,使用由ref.

一旦我们有了那个提交,让我们导出它:

# ostree --repo=/srv/deploy-repo pull-local ./build-repo exampleos/8/x86_64/stable

您可以通过组合ostree remote add, 和rpm-ostree rebase在客户端告诉客户端系统重新设置它。

5.1.6. 粒状树组成 install|postprocess|commit

为了获得更多的控制权,我们拆分rpm-ostree compose treerpm-ostree compose install,其次是rpm-ostree compose postprocess最后rpm-ostree compose commit

类似于rpm-ostree compose tree我们将使用“树文件”。我们还将指定一个目标目录作为我们正在进行的 rootfs:

# rpm-ostree compose install --unified-core --cachedir=cache --repo=./build-repo /path/to/manifest.yaml ./sysroot

这将从引用的存储库下载 RPM 并执行任何指定的后处理脚本。

我们现在可以更改在./sysroot/rootfs.

接下来我们可以运行更多的后处理:

# rpm-ostree compose postprocess ./sysroot/rootfs /path/to/manifest.yaml

完成手动更改后,我们现在可以创建提交:

# rpm-ostree compose commit --repo=./build-repo /path/to/manifest.yaml ./sysroot/rootfs

一旦我们有了那个提交,让我们导出它:

# ostree --repo=/srv/deploy-repo pull-local ./build-repo exampleos/8/x86_64/stable

您可以通过组合ostree remote add, 和rpm-ostree rebase在客户端告诉客户端系统重新设置它。

5.1.7. 在容器中生成 OSTree 提交

rpm-ostree compose tree在非特权(或“以 root 身份运行”)的 podman 容器中运行良好。您还可以使用其他容器工具,只是测试频率较低。

您也可以直接安装rpm-ostree在基于传统yum/rpm的虚拟(或物理)机器上 - 它不会影响您的主机。但是,鼓励使用容器。

更多信息

5.2. Treefile参考

https://coreos.github.io/rpm-ostree/treefile/

TODO

5.3. 扩展

https://coreos.github.io/rpm-ostree/extensions/

扩展是客户端计算机可以使用包分层安装的附加包。虽然 rpm-ostree 本身对这个主题漠不关心,但大多数基于 rpm-ostree 的发行版都鼓励容器化工作流,以更好地分离主机层和应用程序层。但有时,容器化对于某些软件并不理想,但默认情况下将它们烘焙到 OSTree 提交中可能并不理想。

包分层通常从远程存储库中获取此类扩展。然而,在某些架构中,可能有更好的方法来传输它们,或者可能只是希望对它们进行更严格的控制,并在 OSTree 提交和扩展版本之间建立更强的绑定(例如,为了可重复性、保证 depsolve、QE、releng 等)。

rpm-ostree compose extensions接受一个extensions.yaml描述操作系统扩展(包)的文件和一个基本的 OSTree 提交。执行 depsolve 后,它会下载扩展包并将它们放在输出目录中。

5.3.1. extensions.yaml

extensions.yaml文件格式如下:

# Any additional repos to enable on top of treefile repos
repos:
  - myrepo

# Any modules to enable/install
modules:
  enable:
    - foo:bar
  install:
    - baz:boo/default

# The top-level object is a dict. The only supported key
# right now is `extensions`, which is a dict of extension
# names to extension objects.
extensions:
  # This can be whatever name you'd like. The name itself
  # isn't used by rpm-ostree.
  sooper-dooper-tracers:
    # Optional; defaults to `os-extension`. An OS extension
    # is an extension intended to be `rpm-ostree install`ed.
    kind: os-extension
    # List of packages for this extension
    packages:
        - strace
        - ltrace
    # Optional additional repos (still added globally).
    # The reason use per-extension `repos` and `modules`
    # is that it more closely groups them (where relevant)
    # and further these are only added after architecture conditionals
    # apply, so one can use repositories that only exist
    # on a particular architecture.
    repos:
      - sooper-repo
    # Optional additional modules (this also affects global state)
    modules:
      enable:
        - sooper:latest
    # Optional list of architectures on which this extension
    # is valid. These are RPM basearches. If omitted,
    # defaults to all architectures.
    architectures:
        - x86_64
        - aarch64
  kernel-dev:
    # A development extension lists packages useful for
    # developing for the target OSTree, but won't be layered
    # on top. A common example is kernel modules. No
    # depsolving happens, packages listed are downloaded.
    kind: development
    packages:
      - kernel-devel
      - kernel-headers
    # Optional name of a base package used to constrain the
    # EVR of all the packages in this extension.
    match-base-evr: kernel

6. 架构

6.1. RPM 包,ostree 提交

https://coreos.github.io/rpm-ostree/architecture-core/

TODO

6.2. 守护进程模型

https://coreos.github.io/rpm-ostree/architecture-daemon/

TODO

6.3. 应用live架构

https://coreos.github.io/rpm-ostree/apply-live/

TODO

7. 参考链接


Copyright (C) CESTC Com.
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值