本文是直接翻译了ostree官网文档。在正文之前,先将ostree的优点列出:
OSTree是基于Linux的操作系统的升级系统,它对完整的文件系统树执行原子升级。它不是一个包系统(package system);相反,这是为了补充它们。主要模型是在服务器(server)上编写包,然后将它们复制到客户端(client)。
底层架构可以概括为“操作系统二进制文件的git”。它在用户空间中运行,可以在任何Linux文件系统上运行。其核心是一个类似git的内容寻址对象仓库(object store),带有分支(branch 或“refs”)以跟踪仓库中有意义的文件系统树。跟git类似,您可以checkout 或 commit 这些branch 。
最上层是bootloader配置、/etc目录下的管理和其他一些负责升级的功能(升级并不单纯是复制文件)
您可以在纯复制模型中单独使用OSTree,但另一种方法是在顶部添加包管理器,从而创建混合树/包系统。
OSTree主要是作为库去使用,这里也可以通过CTL工具(基本指令)来了解下ostree基本的工作方式。
ostree --repo=os_repo init //执行成功后,会在当前目录下新建ostree仓库:os_repo
(1)bare。//裸机。 存储常规文件,用来存放硬链接。如果要存放root用户拥有的文件,就要以root权限运行ostree
(2) bare-splt-xattrs //裸机拆分xattrs。
(3) bare-user //裸机用户。
(4) bare-user-only //仅裸机用户。
** (5) archive : //**归档。通过普通HTTP传输,可以被非root用户读写(最常用,主控升级采用这种方式)
ostree --repo=repo commit --branch=foo tree/
把tree目录下的内容导入到foo分支
ostree --repo=repo refs
ostree --repo=repo ls foo
ostree --repo=repo checkout commit
OSTree是为部署核心操作系统而设计的,在这里与dpkg和rpm包管理器做一个比较。传统上,包(package)是由附加了元数据和脚本的部分文件系统树组成的,这些文件系统树在依赖关系解析过程之后在客户机上动态组装。也就是说,dpkg和rpm不会更新整个文件系统,它只会更新对应的软件包,它可以由客户端检查完一个软件包中各个组件的依赖关系后,动态组装。
而OSTree只支持记录和部署完整的(可引导的)文件系统树。它没有内置的关于给定文件系统树是如何生成的、单个文件的来源或者没有关于单个组件的依赖关系识。换句话说,OSTree只处理交付和部署;您可能仍然希望在每个树中包含关于进入树的各个组件的元数据。例如,系统管理员可能想知道您的树中包含了什么版本的OpenSSL,因此您应该支持等效的rpm-q或dpkg-L。
OSTree核心强调通过HTTP复制只读操作系统树,其中操作系统包括(如果需要)一个完全独立的机制来安装应用程序,如果它们是系统全局的,则应用程序(app)存在/var中,如果是给指定用户安装应用程序,则存于/home中。所以我们必须先安装这个独立的机制,也就是ostree本身,再在此基础上安装app。示例应用机制是http://docker.io/
除了更新整个文件系统外,Ostree也可以基于当前的文件系统,安装或者更新包。做法:把要更新或者新增的包放在一个基本树的顶部,将其记录在本地OsTree存储库中,然后为下一次引导进行设置。这样就不会更新整个运行中的文件系统,而是等下一次重启时,把新的包给装上。这种更新模式需要依赖一个C共享库:introspectable
OSTree有些地方跟“dumb”复制和“stateless”无状态部署类似。,比如云部署中常见的模型就是节点从只读磁盘启动,用户数据保存在不同的卷上。OSTree和云模型共享的“哑”复制的优点是它可靠且可预测。
但与许多默认的基于image映像的部署不同,OSTree只有两个目录在升级过程中是持久可写的:/etc和/var。
因为OSTree在Unix文件系统层运行,所以它可以在任何文件系统或块存储布局上工作;可以将给定的文件系统树从OSTree存储库复制到纯ext4、BTRFS、XFS,或者任何支持硬链接的Unix兼容文件系统。注意:如果OSTree部署在上面,它将透明地利用一些BTRFS功能。
“裸机”配置的用户会发现OSTree模型最有用。
包管理器和复制 image 映像之间的另一个根本区别是:OSTree旨在并行安装多个独立操作系统的多个版本。OSTree依赖于一个新的顶级OSTree目录;它可以并行安装在当前正在占用/root 目录的操作系统或者ostree分支上。
在每台客户机上,都有OSTree存储库放在在/OSTree/repo中,**主控板上有两个ostree仓库:/ostree/repo_os和/ostree/repo_app ,分别存放ostree本身,和实际的应用程序app. **还有一组“部署”存储在/ostere/deploy/ S T A T E R O O T / STATEROOT/ STATEROOT/CHECKSUM中。每个部署主要由一组到存储库的硬链接组成。这意味着每个版本都进行了重复数据消除;升级过程只需要与新文件成比例的磁盘空间,外加一些恒定的开销。
OSTree模型强调的是,操作系统只读内容保存在经典的Unix/usr中;它附带了创建Linux只读绑定挂载的代码,以防止意外损坏。给定操作系统的每个部署之间正好共享一个/var可写目录。OSTree核心代码不涉及此目录中的内容;如何管理和升级状态取决于每个操作系统中的代码。
OSTree很像git,核心层就是是一个版本控制文件系统。它的object类型类似于git;有commit对象和内容对象,也就是说,他会检查当前ostree有没有新的提交,或者文件有没有被修改。Git有“tree”对象,而OSTree将它们拆分为“dirtree”和“dirmeta”对象。
OSTree的校验和是SHA256。它的内容对象包括uid、gid和扩展属性(但仍然没有时间戳)。他不会因为时间戳改变而认为文件已经更新,而是根据拥有文件的用户、用户组、以及文件内容是否改变来判定是否更新。
以下详细介绍各个Objects
包含元数据,如时间戳、日志消息,最重要的是,对描述文件系统根目录的dirtree/dirmeta校验和对的引用。OSTree 也可以向git那样管理commit。
dirtree 包含:
(1)内容对象的排序数组,这个数组中是一个配对的信息<文件名,校验和>;
(2)二级排序数组,<文件名,dirtree校验和,dirmeta校验和>
在git中,tree objects 包含元数据,例如其子对象的权限。但是OSTree将其拆分为一个单独的对象,以避免重复扩展属性列表。这些类型的对象作为以.dirmeta结尾的文件存储在objects目录中。
一个需要升级的文件就对应一个objects。每一个objects包含以下信息:uid、gid、mode、符号链接目标、扩展属性,后面跟上这个文件的具体内容。
每一个objects对象 以zlib方式压缩,后缀为.filez,这些文件是经过SHA256校验的,存储在/ostree/repo_XX/objects目录下
在某些ostree存储库模式下(例如bare-splt-xattrs),xattrs存储在它们所引用的内容对象的一侧。这是通过两种专用对象类型(文件xattrs和文件xattr链接)完成的。
文件xattrs存储xattrs数据,编码为GVariant。每个对象都由xattrs内容的校验和进行键控,允许多个引用。
文件xattrs链接是与文件对象关联的硬链接。每个对象都由相应文件对象的相同校验和进行键控。硬链接的目标是一个现有的文件xattrs对象。如果达到链接太多的限制,这个对象也可能是一个普通文件。
在OSTree部署的系统上,“系统存储库”是/ostree/repo。它可以由任何uid读取,但只能由root写入。默认情况下,ostree命令将在系统存储库上运行;您可以提供–repo参数来覆盖它,或者设置$OSTREE_repo环境变量。主控板上,ostree命令就是在系统存储库 /ostree/repo_os 或 /ostree/repo_app上运行
如果系统崩掉或断电,会升级到新版本,或保持旧版本
OSTree支持的最基本模型是通过HTTP从服务器复制预先生成的文件系统树,只跟踪一个ref,也就是只下载一个指定的分支,该ref存储在.origin文件中用于部署。
拉动完成后,我们已经下载了执行部署(升级)所需的所有objects。
如介绍中所述,OSTree还允许在客户端计算文件系统树的模型。这些树是如何生成的,这是完全不可知的;它们可以用传统的包、顶部有部署后脚本的包来计算,或者由开发人员直接从本地版本控制中构建,等等
目前大多数包管理器(dpkg和rpm)都在当前启动的文件系统上“实时”运行。他们可以使用OSTree的方法是,在当前启动的树中获取已安装包的列表,并从中计算一个新的文件系统。后面的一章将更详细地描述如何实现这一点:调整现有系统。
为了本节的目的,让我们假设我们在repo中存储了一个新生成的文件系统树(它与现有的引导树共享存储空间)。
指定要部署的commit(也就是要升级到哪个commit),OSTree首先为其分配一个目录。它的格式为/boot/loader/entries/ostree-$stateroot-$checksum.$serial.conf
。$serial
通常为0
,但如果一个给定的commit 已经部署了多次,它将递增。同一个 commit 有可能会部署(更新)多次,因为之前的部署可能在 /etc 中有我们不想使用或覆盖的配置。
现在我们有了一个部署目录,在当前启动的部署的/etc、ostree的默认配置和新部署(/usr/etc)之间执行三路合并。
它的工作原理是:
当前的/etc目录中,已经被 /usr/etc更改过的文件保持不变;没有被/usr/etcg
可以使用 ostree-admin-config-diff 来查看启动部署的/etc 和 ostree默认值之间的差异。
此时,已经创建了一个新的部署目录作为 hardlink farm;正在运行的系统 和 bootloader配置 都没有受到影响。我们要将此部署添加到“部署列表”(deployment list)中。
OSTree支持任意部署集之间的原子转换,但有一个限制,即当前启动的部署必须始终在新的部署集中。在正常情况下,我们只有一个部署,就是正在被boot加载的哪个,我们希望将新的部署添加到列表中。一个更复杂的命令可能允许创建100个部署,作为一个原子事务的一部分,这样就可以建立一个自动化系统,将它们一分为二。
Ostree可以通过在/boot目录中实现“交换目录模式”,来实现新boot配置替换旧boot配置。
我们通过一个软链接指向需要执行的boot. 如果当前正在运行的boot是 /ostree/boot.0, 我们就创建/ostree/boot.1,用新的内容去填充。然后让软链接指向/ostree/boot.1,此时 /ostree/boot.0就没用了,可以被废弃掉。
OSTree和git之间的最关键的区别是git有一个“smart servers”。git 即使在通过https://获取数据时,http 也不仅仅是一个静态Web服务器,而是会为客户端动态计算和压缩packegs。
相比之下,OSTree的作者认为,对于操作系统更新,许多部署都希望使用简单的静态Web服务器,这是大多数包系统设计使用的目标。主要优点是安全性和计算效率。像Amazon S3和CDN 也是静态nginx服务器。
只需gzip压缩每个content objects。元数据对象未压缩存储。这就很容易通过静态HTTP提供服务。注意:repo配置文件使用 archive-z2 模式。
提交新内容时,可以看到objects/目录中生成了 新的 .filez文件
–depth=-1 检索所有commit的历史记录;–depth=3 检索最后3次commit。