mirror of
https://github.com/ostreedev/ostree.git
synced 2025-03-19 22:50:35 +03:00
doc: Add a section about how atomic upgrades work
Migrating some content from https://live.gnome.org/OSTree/DeploymentModel2
This commit is contained in:
parent
14c9f88e9c
commit
2b6d7d8d93
@ -77,6 +77,7 @@ content_files= \
|
||||
overview.xml \
|
||||
repo.xml \
|
||||
deployment.xml \
|
||||
atomic-upgrades.xml \
|
||||
$(NULL)
|
||||
|
||||
# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded
|
||||
|
201
doc/atomic-upgrades.xml
Normal file
201
doc/atomic-upgrades.xml
Normal file
@ -0,0 +1,201 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
|
||||
<!ENTITY version SYSTEM "../version.xml">
|
||||
]>
|
||||
<part id="atomic-upgrades">
|
||||
<title>Atomic Upgrades</title>
|
||||
<chapter id="upgrades-intro">
|
||||
<title>You can turn off the power anytime you want...</title>
|
||||
<para>
|
||||
At the time of this writing, it's common for released versions
|
||||
of mainstream operating systems (the Playstation OS, Microsoft
|
||||
Windows, Debian GNU/Linux, and Red Hat Enterprise Linux) to have
|
||||
non-atomic upgrades; that is, the good ones pop up a screen that
|
||||
says "Please do not turn off the power". The bad ones don't
|
||||
even tell you that it's unsafe. The <emphasis>really</emphasis>
|
||||
bad ones actually mutate your running filesystem without taking
|
||||
precautions to prevent corrupting running processes.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
In contrast, OSTree is designed to implement fully atomic and
|
||||
safe upgrades; more generally, atomic transitions between lists
|
||||
of bootable deployments. If the system crashes or you pull the
|
||||
power, you will have either the old system, or the new one.
|
||||
</para>
|
||||
</chapter>
|
||||
|
||||
<chapter id="simple-http">
|
||||
<title>Simple upgrades via HTTP</title>
|
||||
<para>
|
||||
First, the most basic model OSTree supports is one where it
|
||||
replicates pre-generated filesystem trees from a server over
|
||||
HTTP, tracking exactly one ref, which is stored in the <filename
|
||||
class='extension'>.origin</filename> file for the deployment.
|
||||
The command <command>ostree admin upgrade</command> implements
|
||||
this.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
To begin a simple upgrade, OSTree fetches the contents of the
|
||||
ref from the remote server. Suppose we're tracking a ref named
|
||||
<literal>gnome-ostree/buildmaster/x86_64-runtime</literal>.
|
||||
OSTree fetches the URL
|
||||
<literal>http://<replaceable>example.com</replaceable>/repo/refs/gnome-ostree/buildmaster/x86_64-runtime</literal>,
|
||||
which contains a SHA256 checksum. This determines the tree to
|
||||
deploy, and <filename class='directory'>/etc</filename> will be
|
||||
merged from currently booted tree.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
If we do not have this commit, then, then we perform a pull
|
||||
process. At present (without static deltas), this involves
|
||||
quite simply just fetching each individual object that we do not
|
||||
have, asynchronously. Put in other words, we only download
|
||||
changed files (zlib-compressed). Each object has its checksum
|
||||
validated and is stored in <filename
|
||||
class='directory'>/ostree/repo/objects/</filename>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Once the pull is complete, we have all the objects locally
|
||||
we need to perform a deployment.
|
||||
</para>
|
||||
</chapter>
|
||||
|
||||
<chapter id="package-manager">
|
||||
<title>Upgrades via external tools (e.g. package managers)</title>
|
||||
|
||||
<para>
|
||||
As mentioned in the introduction, OSTree is also designed to
|
||||
allow a model where filesystem trees are computed on the client.
|
||||
It is completely agnostic as to how those trees are generated;
|
||||
they could be computed with traditional packages, packages with
|
||||
post-deployment scripts on top, or built by developers directly
|
||||
from revision control locally, etc.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
At a practical level, most package managers today
|
||||
(<command>dpkg</command> and <command>rpm</command>) operate
|
||||
"live" on the currently booted filesystem. The way they could
|
||||
work with OSTree is instead to take the list of installed
|
||||
packages in the currently booted tree, and compute a new
|
||||
filesystem from that.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The most basic implementation of this would be something like
|
||||
taking the result of <command>rpm -qa</command>, and doing
|
||||
<command>yum --installroot=/var/tmp/newroot install
|
||||
<replaceable>package1</replaceable>
|
||||
<replaceable>package2</replaceable> ...</command>. Then,
|
||||
<command>ostree commit -b osname/localtree
|
||||
--tree=dir=/var/tmp/newroot</command>. This would checksum all
|
||||
of the input files and store them in local <filename
|
||||
class='directory'>/ostree/repo</filename> repository, creating
|
||||
a new commit.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Now, we can move on to deployment.
|
||||
</para>
|
||||
</chapter>
|
||||
|
||||
<chapter id="deployment-dir">
|
||||
<title>Assembling a new deployment directory</title>
|
||||
<para>
|
||||
Given a commit to deploy, OSTree first allocates a directory for
|
||||
it. This is of the form <filename
|
||||
class='directory'>/boot/loader/entries/ostree-<replaceable>osname</replaceable>-<replaceable>checksum</replaceable>.<replaceable>serial</replaceable>.conf</filename>.
|
||||
The <replaceable>serial</replaceable> is normally 0, but if a
|
||||
given commit is deployed more than once, it will be incremented.
|
||||
This is supported because the previous deployment may have
|
||||
configuration in <filename class='directory'>/etc</filename>
|
||||
that we do not want to use or overwrite.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Now that we have a deployment directory, a 3-way merge is
|
||||
performed between the (by default) currently booted deployment's
|
||||
<filename class='directory'>/etc</filename>, its default
|
||||
configuration, and the new deployment (based on its <filename
|
||||
class='directory'>/usr/etc</filename>).
|
||||
</para>
|
||||
</chapter>
|
||||
|
||||
<chapter id="swapping-boot">
|
||||
<title>Atomically swapping boot configuration</title>
|
||||
<para>
|
||||
At this point, a new deployment directory has been created as a
|
||||
hardlink farm; the running system is untouched, and the
|
||||
bootloader configuration is untouched. We want to add this deployment
|
||||
to the "deployment list".
|
||||
</para>
|
||||
|
||||
<para>
|
||||
To support a more general case, OSTree supports atomic
|
||||
transitioning between arbitrary sets of deployments, with the
|
||||
restriction that the currently booted deployment must always be
|
||||
in the new set. In the normal case, we have exactly one
|
||||
deployment, which is the booted one, and we want to add the new
|
||||
deployment to the list. A more complex command might allow
|
||||
creating 100 deployments as part of one atomic transaction, so
|
||||
that one can set up an automated system to bisect across them.
|
||||
</para>
|
||||
|
||||
<simplesect id="bootversion">
|
||||
<title>The bootversion</title>
|
||||
<para>
|
||||
OSTree allows swapping between boot configurations by
|
||||
implementing the "swapped directory pattern" in <filename
|
||||
class='directory'>/boot</filename>. This means it is a
|
||||
symbolic link to one of two directories <filename
|
||||
class='directory'>/ostree/boot.<replaceable>[0|1]</replaceable></filename>.
|
||||
To swap the contents atomically, if the current version is
|
||||
<literal>0</literal>, we create <filename
|
||||
class='directory'>/ostree/boot.1</filename>, populate it with
|
||||
the new contents, then atomically swap the symbolic link. Finally,
|
||||
the old contents can be garbage collected at any point.
|
||||
</para>
|
||||
</simplesect>
|
||||
|
||||
<simplesect id="ostree-bootversion">
|
||||
<title>The /ostree/boot directory</title>
|
||||
<para>
|
||||
However, we want to optimize for the case where we the set of
|
||||
kernel/initramfs pairs is the same between both the old and
|
||||
new deployment lists. This happens when doing an upgrade that
|
||||
does not include the kernel; think of a simple translation
|
||||
update. OSTree optimizes for this case because on some
|
||||
systems <filename class='directory'>/boot</filename> may be on
|
||||
a separate medium such as flash storage not optimized for
|
||||
significant amounts of write traffic.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
To implement this, OSTree also maintains the directory
|
||||
<filename
|
||||
class='directory'>/ostree/boot.<replaceable>bootversion</replaceable></filename>,
|
||||
which is a set of symbolic links to the deployment
|
||||
directories. The <replaceable>bootversion</replaceable> here
|
||||
must match the version of <filename
|
||||
class='directory'>/boot</filename>. However, in order to
|
||||
allow atomic transitions of <emphasis>this</emphasis>
|
||||
directory, this is also a swapped directory, so just like
|
||||
<filename class='directory'>/boot</filename>, it has a version
|
||||
of <literal>0</literal> or <literal>1</literal> appended.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Each bootloader entry has a special <literal>ostree=</literal>
|
||||
argument which refers to one of these symbolic links. This is
|
||||
parsed at runtime in the initramfs.
|
||||
</para>
|
||||
|
||||
</simplesect>
|
||||
|
||||
</chapter>
|
||||
|
||||
</part>
|
@ -111,6 +111,17 @@
|
||||
class='directory'>/usr</filename>, but this is not a hard
|
||||
requirement.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Finally, a deployment may have a <filename
|
||||
class='extension'>.origin</filename> file, stored next to its
|
||||
directory. This file tells <command>ostree admin
|
||||
upgrade</command> how to upgrade it. At the moment, OSTree only
|
||||
supports upgrading a single refspec. However, in the future
|
||||
OSTree may support a syntax for composing layers of trees, for
|
||||
example.
|
||||
</para>
|
||||
|
||||
</chapter>
|
||||
|
||||
<chapter id="managing-boot">
|
||||
|
@ -14,6 +14,7 @@
|
||||
<xi:include href="overview.xml"/>
|
||||
<xi:include href="repo.xml"/>
|
||||
<xi:include href="deployment.xml"/>
|
||||
<xi:include href="atomic-upgrades.xml"/>
|
||||
|
||||
<chapter xml:id="reference">
|
||||
<title>API Reference</title>
|
||||
|
Loading…
x
Reference in New Issue
Block a user