diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index 79044b5f..d182eb6f 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -20,7 +20,8 @@ - [`man bootc status`](man/bootc-status.md) - [`man bootc upgrade`](man/bootc-upgrade.md) - [`man bootc switch`](man/bootc-switch.md) -- [`man bootc usroverlay`](man/bootc-usr-overlay.md) +- [`man bootc rollback`](man/bootc-rollback.md) +- [`man bootc usr-overlay`](man/bootc-usr-overlay.md) - [`man bootc-fetch-apply-updates.service`](man-md/bootc-fetch-apply-updates-service.md) # Using `bootc install` diff --git a/docs/src/bootc-install.md b/docs/src/bootc-install.md index b82c0eda..3d85c729 100644 --- a/docs/src/bootc-install.md +++ b/docs/src/bootc-install.md @@ -128,58 +128,7 @@ The bootc project aims to support generic/general-purpose operating systems and distributions that will ship unconfigured images. An unconfigured image does not have a default password or SSH key, etc. -There are two fundamental ways to handle this: - -### Using cloud-init type flows - -Some operating systems may come with `cloud-init` or similar tools -that know how to e.g. inject SSH keys or external configuration. - -Other tools in this space are: - -- [systemd-firstboot](https://www.freedesktop.org/software/systemd/man/systemd-firstboot.html) -- [gnome-initial-setup](https://gitlab.gnome.org/GNOME/gnome-initial-setup) - -The general idea here is that things like users, passwords and ssh keys -are dynamically created on first boot (and in general managed per-system); -the configuration comes from a place *external* to the image. - -### Injecting configuration into a custom image - -But a new super-power with `bootc` is that you can also easily -create a derived container that injects your desired configuration, -alongside any additional executable code (binaries, packages, scripts, etc). - -The expectation is that most operating systems will be designed such -that user state i.e. `/root` and `/home` will be on a separate, persistent data store. -For example, in the default ostree model, `/root` is `/var/roothome` -and `/home` is `/var/home`. Content in `/var` cannot be shipped -in the image - it is per machine state. - -#### Injecting SSH keys in a container image - -In the following example, we will configure OpenSSH to read the -set of authorized keys for the root user from content -that lives in `/usr` (i.e. is owned by the container image). -We will also create a `/usr/etc-system` directory which is intentionally distinct -from the default ostree `/etc` which may be locally writable. - -The `AuthorizedKeysFile` invocation below then configures sshd to look -for keys in this location. - -```Dockerfile -FROM -RUN mkdir -p /usr/etc-system/ && \ - echo 'AuthorizedKeysFile /usr/etc-system/%u.keys' >> /etc/ssh/sshd_config.d/30-auth-system.conf && \ - echo 'ssh-ed25519 AAAAC3Nza... root@example.com' > /usr/etc-system/root.keys && chmod 0600 /usr/etc-system/root.keys && \ - ostree container commit -``` - -A key point here is that now the set of authorized keys is "owned" -by the container image - it will be read-only at runtime because -the files are underneath `/usr`. To rotate or change the set of keys, -one would build a new container image. Client systems using `bootc upgrade` -will transactionally update to this new system state. +For more information, see [Image building and configuration guidance](building/guidance.md). ## More advanced installation with `to-filesystem` diff --git a/docs/src/man-md/bootc-fetch-apply-updates-service.md b/docs/src/man-md/bootc-fetch-apply-updates-service.md index ec1dd931..a0bebf22 100644 --- a/docs/src/man-md/bootc-fetch-apply-updates-service.md +++ b/docs/src/man-md/bootc-fetch-apply-updates-service.md @@ -1 +1,10 @@ # man bootc-fetch-apply-updates.service + +This systemd service and associated `.timer` unit simply invoke +`bootc upgrade --apply`. It is a minimal demonstration of +an "upgrade agent". + +More information: [bootc-upgrade](../man/bootc-upgrade.md). + +The systemd unit is not enabled by default upstream, but it +may be enabled in some operating systems. diff --git a/docs/src/man/bootc-edit.md b/docs/src/man/bootc-edit.md index f36b8a8a..40b7abcf 100644 --- a/docs/src/man/bootc-edit.md +++ b/docs/src/man/bootc-edit.md @@ -40,4 +40,4 @@ Only changes to the \`spec\` section are honored. # VERSION -v0.1.0 +v0.1.9 diff --git a/docs/src/man/bootc-install-print-configuration.md b/docs/src/man/bootc-install-print-configuration.md index 9b88b571..fe69f26e 100644 --- a/docs/src/man/bootc-install-print-configuration.md +++ b/docs/src/man/bootc-install-print-configuration.md @@ -31,4 +31,4 @@ string-valued filesystem name suitable for passing to \`mkfs.\$type\`. # VERSION -v0.1.0 +v0.1.9 diff --git a/docs/src/man/bootc-install-to-disk.md b/docs/src/man/bootc-install-to-disk.md index e60a78ac..b66656bd 100644 --- a/docs/src/man/bootc-install-to-disk.md +++ b/docs/src/man/bootc-install-to-disk.md @@ -139,4 +139,4 @@ firmware will be skipped # VERSION -v0.1.0 +v0.1.9 diff --git a/docs/src/man/bootc-install-to-existing-root.md b/docs/src/man/bootc-install-to-existing-root.md index 9397665f..576afcdc 100644 --- a/docs/src/man/bootc-install-to-existing-root.md +++ b/docs/src/man/bootc-install-to-existing-root.md @@ -123,4 +123,4 @@ firmware will be skipped # VERSION -v0.1.0 +v0.1.9 diff --git a/docs/src/man/bootc-install-to-filesystem.md b/docs/src/man/bootc-install-to-filesystem.md index 52e3f3e8..5a2570ab 100644 --- a/docs/src/man/bootc-install-to-filesystem.md +++ b/docs/src/man/bootc-install-to-filesystem.md @@ -139,4 +139,4 @@ mounting. To override this, use \`\--root-mount-spec\`. # VERSION -v0.1.0 +v0.1.9 diff --git a/docs/src/man/bootc-install.md b/docs/src/man/bootc-install.md index f47822d2..2b37e911 100644 --- a/docs/src/man/bootc-install.md +++ b/docs/src/man/bootc-install.md @@ -11,9 +11,23 @@ bootc-install - Install the running container to a target Install the running container to a target. -This has two main sub-commands \`to-disk\` (which expects an empty block -device) and \`to-filesystem\` which supports installation to an already -extant filesystem. +## Understanding installations + +OCI containers are effectively layers of tarballs with JSON for +metadata; they cannot be booted directly. The \`bootc install\` flow is +a highly opinionated method to take the contents of the container image +and install it to a target block device (or an existing filesystem) in +such a way that it can be booted. + +For example, a Linux partition table and filesystem is used, and the +bootloader and kernel embedded in the container image are also prepared. + +A bootc installed container currently uses OSTree as a backend, and this +sets it up such that a subsequent \`bootc upgrade\` can perform in-place +updates. + +An installation is not simply a copy of the container filesystem, but +includes other setup and metadata. # OPTIONS @@ -51,4 +65,4 @@ bootc-install-help(8) # VERSION -v0.1.0 +v0.1.9 diff --git a/docs/src/man/bootc-rollback.md b/docs/src/man/bootc-rollback.md new file mode 100644 index 00000000..57070d0d --- /dev/null +++ b/docs/src/man/bootc-rollback.md @@ -0,0 +1,41 @@ +# NAME + +bootc-rollback - Change the bootloader entry ordering; the deployment +under \`rollback\` will be queued for the next boot, and the current +will become rollback. If there is a \`staged\` entry (an unapplied, +queued upgrade) then it will be discarded + +# SYNOPSIS + +**bootc-rollback** \[**-h**\|**\--help**\] \[**-V**\|**\--version**\] + +# DESCRIPTION + +Change the bootloader entry ordering; the deployment under \`rollback\` +will be queued for the next boot, and the current will become rollback. +If there is a \`staged\` entry (an unapplied, queued upgrade) then it +will be discarded. + +Note that absent any additional control logic, if there is an active +agent doing automated upgrades (such as the default +\`bootc-fetch-apply-updates.timer\` and associated \`.service\`) the +change here may be reverted. Its recommended to only use this in concert +with an agent that is in active control. + +A systemd journal message will be logged with +\`MESSAGE_ID=26f3b1eb24464d12aa5e7b544a6b5468\` in order to detect a +rollback invocation. + +# OPTIONS + +**-h**, **\--help** + +: Print help (see a summary with -h) + +**-V**, **\--version** + +: Print version + +# VERSION + +v0.1.9 diff --git a/docs/src/man/bootc-status.md b/docs/src/man/bootc-status.md index 443b7562..a6301b76 100644 --- a/docs/src/man/bootc-status.md +++ b/docs/src/man/bootc-status.md @@ -37,4 +37,4 @@ The exact API format is not currently declared stable. # VERSION -v0.1.0 +v0.1.9 diff --git a/docs/src/man/bootc-switch.md b/docs/src/man/bootc-switch.md index d09f215f..514b05c8 100644 --- a/docs/src/man/bootc-switch.md +++ b/docs/src/man/bootc-switch.md @@ -13,8 +13,17 @@ bootc-switch - Target a new container image reference to boot Target a new container image reference to boot. -This operates in a very similar fashion to \`upgrade\`, but changes the -container image reference instead. +This is almost exactly the same operation as \`upgrade\`, but +additionally changes the container image reference instead. + +## Usage + +A common pattern is to have a management agent control operating system +updates via container image tags; for example, +\`quay.io/exampleos/someuser:v1.0\` and +\`quay.io/exampleos/someuser:v1.1\` where some machines are tracking +\`:v1.0\`, and as a rollout progresses, machines can be switched to +\`v:1.1\`. # OPTIONS @@ -56,4 +65,4 @@ includes a default policy which requires signatures. # VERSION -v0.1.0 +v0.1.9 diff --git a/docs/src/man/bootc-upgrade.md b/docs/src/man/bootc-upgrade.md index 6b92342e..a3466915 100644 --- a/docs/src/man/bootc-upgrade.md +++ b/docs/src/man/bootc-upgrade.md @@ -22,7 +22,8 @@ upgrade \--apply\` verb which will automatically take action (rebooting) if the system has changed. However, in the future this is likely to change such that reboots -outside of a \`bootc upgrade \--apply\` do \*not\* upgrade. +outside of a \`bootc upgrade \--apply\` do \*not\* automatically apply +the update. # OPTIONS @@ -55,4 +56,4 @@ userspace-only restart. # VERSION -v0.1.0 +v0.1.9 diff --git a/docs/src/man/bootc-usr-overlay.md b/docs/src/man/bootc-usr-overlay.md index e63ccf04..9c7d976a 100644 --- a/docs/src/man/bootc-usr-overlay.md +++ b/docs/src/man/bootc-usr-overlay.md @@ -1,6 +1,6 @@ # NAME -bootc-usr-overlay - Add a transient writable overlayfs on \`/usr\` that +bootc-usr-overlay - Adds a transient writable overlayfs on \`/usr\` that will be discarded on reboot # SYNOPSIS @@ -9,14 +9,35 @@ will be discarded on reboot # DESCRIPTION -Add a transient writable overlayfs on \`/usr\` that will be discarded on -reboot +Adds a transient writable overlayfs on \`/usr\` that will be discarded +on reboot. + +(`usroverlay` is an alias for this command) + +## Use cases + +A common pattern is wanting to use tracing/debugging tools, such as +\`strace\` that may not be in the base image. A system package manager +such as \`apt\` or \`dnf\` can apply changes into this transient overlay +that will be discarded on reboot. + +## /etc and /var + +However, this command has no effect on \`/etc\` and \`/var\` - changes +written there will persist. It is common for package installations to +modify these directories. + +## Unmounting + +Almost always, a system process will hold a reference to the open mount +point. You can however invoke \`umount -l /usr\` to perform a \"lazy +unmount\". # OPTIONS **-h**, **\--help** -: Print help +: Print help (see a summary with -h) **-V**, **\--version** @@ -24,4 +45,4 @@ reboot # VERSION -v0.1.0 +v0.1.9 diff --git a/docs/src/man/bootc.md b/docs/src/man/bootc.md index d8c313ea..2a0720ec 100644 --- a/docs/src/man/bootc.md +++ b/docs/src/man/bootc.md @@ -5,7 +5,8 @@ images # SYNOPSIS -**bootc** \[**-h**\|**\--help**\] \<*subcommands*\> +**bootc** \[**-h**\|**\--help**\] \[**-V**\|**\--version**\] +\<*subcommands*\> # DESCRIPTION @@ -25,6 +26,10 @@ Changes in \`/etc\` and \`/var\` persist. : Print help (see a summary with -h) +**-V**, **\--version** + +: Print version + # SUBCOMMANDS bootc-upgrade(8) @@ -35,6 +40,13 @@ bootc-switch(8) : Target a new container image reference to boot +bootc-rollback(8) + +: Change the bootloader entry ordering; the deployment under + \`rollback\` will be queued for the next boot, and the current will + become rollback. If there is a \`staged\` entry (an unapplied, + queued upgrade) then it will be discarded + bootc-edit(8) : Apply full changes to the host specification @@ -45,7 +57,7 @@ bootc-status(8) bootc-usr-overlay(8) -: Add a transient writable overlayfs on \`/usr\` that will be +: Adds a transient writable overlayfs on \`/usr\` that will be discarded on reboot bootc-install(8) @@ -55,3 +67,7 @@ bootc-install(8) bootc-help(8) : Print this message or the help of the given subcommand(s) + +# VERSION + +v0.1.9 diff --git a/docs/src/upgrades.md b/docs/src/upgrades.md index 2dc0bd0b..b6d1802e 100644 --- a/docs/src/upgrades.md +++ b/docs/src/upgrades.md @@ -18,21 +18,34 @@ There is also an opinionated `bootc-fetch-apply-updates.timer` and corresponding service available in upstream for operating systems and distributions to enable. +Man page: [bootc-upgrade](man/bootc-upgrade.md). + ## Changing the container image source Another useful pattern to implement can be to use a management agent -to invoke `bootc switch` to implement e.g. blue/green deployments, +to invoke `bootc switch` (or declaratively via `bootc edit`) +to implement e.g. blue/green deployments, where some hosts are rolled onto a new image independently of others. ```shell -bootc switch quay.io/examplecorp/os-prod-blue:lastest +bootc switch quay.io/examplecorp/os-prod-blue:latest ``` +`bootc switch` has the same effect as `bootc upgrade`; there is no +semantic difference between the two other than changing the +container image being tracked. + This will preserve existing state in `/etc` and `/var` - for example, host SSH keys and home directories. +Man page: [bootc-switch](man/bootc-switch.md). + ## Rollback -At the current time, bootc does not ship with an opinionated integrated -rollback flow. However, bootc always maintains (by default) a -`rollback` container image that is accessible via `bootc status`. +There is a `bootc rollback` verb, and associated declarative interface +accessible to tools via `bootc edit`. This will swap the bootloader +ordering to the previous boot entry. + +Man page: [bootc-rollback](man/bootc-rollback.md). + + diff --git a/lib/src/cli.rs b/lib/src/cli.rs index 623796a4..05f1b2b7 100644 --- a/lib/src/cli.rs +++ b/lib/src/cli.rs @@ -189,10 +189,7 @@ pub(crate) enum TestingOpts { /// to support a model of bootable container images. Once installed, /// whether directly via `bootc install` (executed as part of a container) /// or via another mechanism such as an OS installer tool, further -/// updates can be pulled via e.g. `bootc upgrade`. -/// -/// Changes in `/etc` and `/var` persist. -/// +/// updates can be pulled and `bootc upgrade`. #[derive(Debug, Parser, PartialEq, Eq)] #[clap(name = "bootc")] #[clap(rename_all = "kebab-case")] @@ -210,13 +207,19 @@ pub(crate) enum Opt { /// if the system has changed. /// /// However, in the future this is likely to change such that reboots outside of a `bootc upgrade --apply` - /// do *not* upgrade. + /// do *not* automatically apply the update in addition. #[clap(alias = "update")] Upgrade(UpgradeOpts), /// Target a new container image reference to boot. /// - /// This operates in a very similar fashion to `upgrade`, but changes the container image reference + /// This is almost exactly the same operation as `upgrade`, but additionally changes the container image reference /// instead. + /// + /// ## Usage + /// + /// A common pattern is to have a management agent control operating system updates via container image tags; + /// for example, `quay.io/exampleos/someuser:v1.0` and `quay.io/exampleos/someuser:v1.1` where some machines + /// are tracking `:v1.0`, and as a rollout progresses, machines can be switched to `v:1.1`. Switch(SwitchOpts), /// Change the bootloader entry ordering; the deployment under `rollback` will be queued for the next boot, /// and the current will become rollback. If there is a `staged` entry (an unapplied, queued upgrade) @@ -247,13 +250,45 @@ pub(crate) enum Opt { /// /// The exact API format is not currently declared stable. Status(StatusOpts), - /// Add a transient writable overlayfs on `/usr` that will be discarded on reboot. + /// Adds a transient writable overlayfs on `/usr` that will be discarded on reboot. + /// + /// ## Use cases + /// + /// A common pattern is wanting to use tracing/debugging tools, such as `strace` + /// that may not be in the base image. A system package manager such as `apt` or + /// `dnf` can apply changes into this transient overlay that will be discarded on + /// reboot. + /// + /// ## /etc and /var + /// + /// However, this command has no effect on `/etc` and `/var` - changes written + /// there will persist. It is common for package installations to modify these + /// directories. + /// + /// ## Unmounting + /// + /// Almost always, a system process will hold a reference to the open mount point. + /// You can however invoke `umount -l /usr` to perform a "lazy unmount". + /// #[clap(alias = "usroverlay")] UsrOverlay, /// Install the running container to a target. /// - /// This has two main sub-commands `to-disk` (which expects an empty block device) and `to-filesystem` - /// which supports installation to an already extant filesystem. + /// ## Understanding installations + /// + /// OCI containers are effectively layers of tarballs with JSON for metadata; they + /// cannot be booted directly. The `bootc install` flow is a highly opinionated + /// method to take the contents of the container image and install it to a target + /// block device (or an existing filesystem) in such a way that it can be booted. + /// + /// For example, a Linux partition table and filesystem is used, and the bootloader and kernel + /// embedded in the container image are also prepared. + /// + /// A bootc installed container currently uses OSTree as a backend, and this sets + /// it up such that a subsequent `bootc upgrade` can perform in-place updates. + /// + /// An installation is not simply a copy of the container filesystem, but includes + /// other setup and metadata. #[clap(subcommand)] #[cfg(feature = "install")] Install(InstallOpts), diff --git a/xtask/src/xtask.rs b/xtask/src/xtask.rs index 6b5bc098..b2283ec7 100644 --- a/xtask/src/xtask.rs +++ b/xtask/src/xtask.rs @@ -26,7 +26,21 @@ const TASKS: &[(&str, fn(&Shell) -> Result<()>)] = &[ ]; fn try_main() -> Result<()> { + // Ensure our working directory is the toplevel + { + let toplevel_path = Command::new("git") + .args(["rev-parse", "--show-toplevel"]) + .output() + .context("Invoking git rev-parse")?; + if !toplevel_path.status.success() { + anyhow::bail!("Failed to invoke git rev-parse"); + } + let path = String::from_utf8(toplevel_path.stdout)?; + std::env::set_current_dir(path.trim()).context("Changing to toplevel")?; + } + let task = std::env::args().nth(1); + let sh = xshell::Shell::new()?; if let Some(cmd) = task.as_deref() { let f = TASKS