Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
name: Deploy docs to Pages

on:
push:
branches: [main]
paths:
- 'docs/**'
workflow_dispatch:

permissions:
contents: read

concurrency:
group: pages
cancel-in-progress: false

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- name: Install mdBook
run: |
mkdir -p mdbook-bin
curl -sSL https://github.com/rust-lang/mdBook/releases/download/v0.5.4/mdbook-v0.5.4-x86_64-unknown-linux-gnu.tar.gz \
| tar -xz -C mdbook-bin
echo "$(pwd)/mdbook-bin" >> "$GITHUB_PATH"

- name: Build docs
run: mdbook build docs

- uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0

- uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0
with:
path: docs/book

deploy:
permissions:
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5.0.0
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ _output/
bin/
*.out
kubeconfig-*
docs/book/
user-docs
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ systemctl --user start podman.socket

Before diving into the code, familiarize yourself with the project from a user
perspective by reading the [README](README.md) and the
[Architecture](docs/ARCHITECTURE.md) document. We also recommend getting
[Architecture](docs/design/ARCHITECTURE.md) document. We also recommend getting
familiar with [bink](https://github.com/bootc-dev/bink), which is used to
create lightweight Kubernetes clusters backed by bootc nodes for development
and testing.
Expand Down
10 changes: 10 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,16 @@ print-var-%:
help: ## Display this help.
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)

##@ Documentation

.PHONY: docs
docs: ## Build documentation locally (requires mdBook).
mdbook build docs

.PHONY: docs-serve
docs-serve: ## Serve documentation locally with live reload.
mdbook serve docs --open

##@ Development

.PHONY: manifests
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ The Bootc Operator then exposes this bootc API to the Kubernetes control plane
in pure operator declarative fashion: you define the desired state your hosts
should be in, and the operator handles the reconciliation. This includes image
updates, but also future bootc enhancements like dynamic config overlays,
sysexts, etc. See the [PRD](docs/PRD.md) for more details and the
sysexts, etc. See the [PRD](docs/design/PRD.md) for more details and the
[Roadmap](ROADMAP.md) for what's ahead.

## Highlights
Expand Down
8 changes: 8 additions & 0 deletions docs/book.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[book]
title = "Bootc Operator"
language = "en"
src = "src"

[output.html]
git-repository-url = "https://github.com/bootc-dev/bootc-operator"
edit-url-template = "https://github.com/bootc-dev/bootc-operator/edit/main/docs/{path}"
File renamed without changes.
File renamed without changes.
File renamed without changes.
9 changes: 9 additions & 0 deletions docs/src/SUMMARY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Summary

[Introduction](introduction.md)

# User Guide

- [Concepts](concepts.md)
- [Operations](operations/index.md)
- [Managing a pool](operations/pool.md)
27 changes: 27 additions & 0 deletions docs/src/concepts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Concepts

## BootcNodePool

A `BootcNodePool` is the only resource users need to create. It defines a
group of nodes by label selector and the OS image those nodes should be running.
The operator creates one `BootcNode` per matching node and drives each toward
the desired image.

## BootcNode

A `BootcNode` represents a single managed node. It is created automatically by
the controller (one per node that matches a pool's selector) and named after
the Kubernetes `Node` it represents. Users do not create or modify `BootcNode`
objects directly.

The status of a `BootcNode` reflects the information reported by `bootc status`
on that node: the currently booted image, any staged image, and the rollback
entry if one is available.

## Image references

A pool's `spec.image.ref` can be either a digest reference
(`quay.io/example/myos@sha256:abc123`) or a tag reference
(`quay.io/example/myos:latest`). With a digest ref, the target is pinned and
immutable. With a tag ref, the controller periodically resolves the tag to a
digest and begins a new rollout whenever the digest changes.
19 changes: 19 additions & 0 deletions docs/src/introduction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Bootc Operator

A Kubernetes operator for managing [bootc] nodes.

[bootc] lets you define a complete Linux operating system as an OCI/Docker
container image and deploy it transactionally on physical or virtual machines.
It is a natural fit for managing Kubernetes cluster nodes: a node OS becomes
a container image, updated and rolled back with the same registry tooling
already in use for workloads.

The Bootc Operator exposes the bootc API to the Kubernetes control plane in
declarative fashion. You declare the desired OS image for a group of nodes in a
`BootcNodePool` resource; the operator resolves image tags, coordinates staged
rollouts, drains nodes, and orchestrates reboots, all without any per-node
configuration. Node OS upgrades become a standard Kubernetes operation, managed
with the same `kubectl` workflows used for any other resource and requiring no
additional tooling.

[bootc]: https://github.com/bootc-dev/bootc
4 changes: 4 additions & 0 deletions docs/src/operations/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Operations

This chapter covers the day-to-day operations for managing nodes with the
Bootc Operator.
107 changes: 107 additions & 0 deletions docs/src/operations/pool.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# Managing a pool

## Creating a pool

A `BootcNodePool` tells the operator which nodes to manage and what OS image
they should be running. Create one by applying a manifest to your cluster:

```yaml
apiVersion: node.bootc.dev/v1alpha1
kind: BootcNodePool
metadata:
name: workers
spec:
nodeSelector:
matchLabels:
node-role.kubernetes.io/worker: ""
image:
ref: ghcr.io/bootc-dev/bink/node:latest
```

The `nodeSelector` field follows the standard Kubernetes label selector format.
Each node can belong to at most one pool, if a node matches multiple selectors,
the affected pools are marked `Degraded` with reason `NodeConflict`.

The image in ref can be specified by digest or by tag. If it is specified by tag
the bootc-operator controller will periodically checks for update. If a new image
version under that tag is detected, then a rollout is started by patching the new
digest in the bootc node spec.

Once the pool exists, the operator creates a `BootcNode` for each matching node
and begins staging the image.

## Updating the OS image

To roll out a new OS image across the pool, update `spec.image.ref` to a new
digest:

```shell
kubectl patch bootcnodepool workers --type merge -p \
'{"spec":{"image":{"ref":"ghcr.io/bootc-dev/bink/node@sha256:newdigest..."}}}'
```

The operator stages the new image on each node, drains workloads, and reboots
nodes according to the rollout settings. Nodes that are already running the
target digest are left untouched.

## Monitoring a rollout

The `BootcNodePool` status shows the overall rollout progress:

```shell
kubectl get bootcnodepool workers
```

The columns `Nodes`, `Updated`, `Updating`, and `Degraded` give a quick
summary. For more detail:

```shell
kubectl get bootcnodepool workers -o yaml
```

```yaml
status:
targetDigest: sha256:9ce7d6d15b8558c226b4c41f3b27bf1722897b0c8a66c7a84a2877bca8d049f7
nodeCount: 10
updatedCount: 7
updatingCount: 2
degradedCount: 1
conditions:
- type: UpToDate
status: "False"
reason: RolloutInProgress
message: "7/10 updated; 2 staging, 1 rebooting"
```

The `UpToDate` condition is `True` when all nodes in the pool are running
the target digest.

Individual node progress is available through `BootcNode` resources:

```shell
kubectl get bootcnodes
```

Each `BootcNode` status reflects the output of `bootc status` on that node:
the booted image, any staged image, and the rollback entry.

## Pausing and resuming

To pause a rollout (nodes already staging will complete, but no new reboots
start):

```shell
kubectl patch bootcnodepool workers --type merge -p '{"spec":{"rollout":{"paused":true}}}'
```

To resume:

```shell
kubectl patch bootcnodepool workers --type merge -p '{"spec":{"rollout":{"paused":false}}}'
```

## Rolling back

To roll back, change `spec.image.ref` to the previous digest. Nodes already
running that image are left alone. Nodes that were updated go through the
normal staging and reboot cycle to return to the previous image.