From a260f9685532ee5841920b498f9a6edac00e7eff Mon Sep 17 00:00:00 2001 From: Alice Frosi Date: Wed, 5 Aug 2026 14:21:18 +0000 Subject: [PATCH 1/6] docs: move design documents to docs/design/ Make room for mdBook user documentation by moving developer design artifacts to a dedicated subdirectory. Signed-off-by: Alice Frosi --- CONTRIBUTING.md | 2 +- README.md | 2 +- docs/{ => design}/ARCHITECTURE.md | 0 docs/{ => design}/IMPLEMENTATION_PLAN.md | 0 docs/{ => design}/PRD.md | 0 5 files changed, 2 insertions(+), 2 deletions(-) rename docs/{ => design}/ARCHITECTURE.md (100%) rename docs/{ => design}/IMPLEMENTATION_PLAN.md (100%) rename docs/{ => design}/PRD.md (100%) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 998d9a1..6e4ee6a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -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. diff --git a/README.md b/README.md index ca2f8f0..20c09df 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/docs/ARCHITECTURE.md b/docs/design/ARCHITECTURE.md similarity index 100% rename from docs/ARCHITECTURE.md rename to docs/design/ARCHITECTURE.md diff --git a/docs/IMPLEMENTATION_PLAN.md b/docs/design/IMPLEMENTATION_PLAN.md similarity index 100% rename from docs/IMPLEMENTATION_PLAN.md rename to docs/design/IMPLEMENTATION_PLAN.md diff --git a/docs/PRD.md b/docs/design/PRD.md similarity index 100% rename from docs/PRD.md rename to docs/design/PRD.md From a5bcead295603c4856bd7b826ea632ff2f43f2b3 Mon Sep 17 00:00:00 2001 From: Alice Frosi Date: Wed, 5 Aug 2026 14:21:26 +0000 Subject: [PATCH 2/6] docs: add mdBook skeleton for user documentation Set up the mdBook scaffolding with a placeholder introduction page. Add Makefile targets for building and serving docs locally. Assisted-by: AI Signed-off-by: Alice Frosi --- .gitignore | 1 + Makefile | 10 ++++++++++ docs/book.toml | 8 ++++++++ docs/src/SUMMARY.md | 3 +++ docs/src/introduction.md | 6 ++++++ 5 files changed, 28 insertions(+) create mode 100644 docs/book.toml create mode 100644 docs/src/SUMMARY.md create mode 100644 docs/src/introduction.md diff --git a/.gitignore b/.gitignore index 092058e..3622181 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ _output/ bin/ *.out kubeconfig-* +docs/book/ diff --git a/Makefile b/Makefile index 8ceb1ed..fd50934 100644 --- a/Makefile +++ b/Makefile @@ -29,6 +29,16 @@ print-var-%: help: ## Display this help. @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\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 diff --git a/docs/book.toml b/docs/book.toml new file mode 100644 index 0000000..c92deb8 --- /dev/null +++ b/docs/book.toml @@ -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}" diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md new file mode 100644 index 0000000..007d8f7 --- /dev/null +++ b/docs/src/SUMMARY.md @@ -0,0 +1,3 @@ +# Summary + +[Introduction](introduction.md) diff --git a/docs/src/introduction.md b/docs/src/introduction.md new file mode 100644 index 0000000..5ad039d --- /dev/null +++ b/docs/src/introduction.md @@ -0,0 +1,6 @@ +# Bootc Operator + +A Kubernetes operator for managing [bootc](https://github.com/bootc-dev/bootc) nodes. + +> **Warning:** This project is in early development and not yet fully functional. +> APIs may change. From 3ee650978e7db3564f0cce6c4d3a285447381fa1 Mon Sep 17 00:00:00 2001 From: Alice Frosi Date: Wed, 5 Aug 2026 14:21:33 +0000 Subject: [PATCH 3/6] ci: add GitHub Actions workflow for docs deployment Build mdBook and deploy to GitHub Pages on push to main when docs/ changes. This is similarly to what bootc is doing in the main repo. Assisted-by: AI Signed-off-by: Alice Frosi --- .github/workflows/docs.yml | 53 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 .github/workflows/docs.yml diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..b2fe052 --- /dev/null +++ b/.github/workflows/docs.yml @@ -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 From 29651856f1c7eda4898cf0ba4170d79f54679860 Mon Sep 17 00:00:00 2001 From: Alice Frosi Date: Tue, 25 Aug 2026 15:19:14 +0200 Subject: [PATCH 4/6] Add user-doc to gitignore Signed-off-by: Alice Frosi --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 3622181..6b7ef89 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ bin/ *.out kubeconfig-* docs/book/ +user-docs From b3ed07bc5701511273e36df4f69370b8eb1dbef7 Mon Sep 17 00:00:00 2001 From: Alice Frosi Date: Sun, 9 Aug 2026 14:04:39 +0200 Subject: [PATCH 5/6] docs: introduce the bootc operator Add the introduction for the bootc operator, a summary and introduce the first concepts of the bootc node pool and bootc node. Assisted-by: AI Signed-off-by: Alice Frosi --- docs/src/SUMMARY.md | 4 ++++ docs/src/concepts.md | 27 +++++++++++++++++++++++++++ docs/src/introduction.md | 19 ++++++++++++++++--- 3 files changed, 47 insertions(+), 3 deletions(-) create mode 100644 docs/src/concepts.md diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index 007d8f7..571b813 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -1,3 +1,7 @@ # Summary [Introduction](introduction.md) + +# User Guide + +- [Concepts](concepts.md) diff --git a/docs/src/concepts.md b/docs/src/concepts.md new file mode 100644 index 0000000..15756a8 --- /dev/null +++ b/docs/src/concepts.md @@ -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. diff --git a/docs/src/introduction.md b/docs/src/introduction.md index 5ad039d..418f0d4 100644 --- a/docs/src/introduction.md +++ b/docs/src/introduction.md @@ -1,6 +1,19 @@ # Bootc Operator -A Kubernetes operator for managing [bootc](https://github.com/bootc-dev/bootc) nodes. +A Kubernetes operator for managing [bootc] nodes. -> **Warning:** This project is in early development and not yet fully functional. -> APIs may change. +[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 From b69f274f29751cd0f1af30f880a7cb0915f1d49f Mon Sep 17 00:00:00 2001 From: Alice Frosi Date: Sun, 9 Aug 2026 15:17:16 +0200 Subject: [PATCH 6/6] docs: add paragraph for the pool operations Include how to create a pool, how to pause and it covers rollback. Signed-off-by: Alice Frosi --- docs/src/SUMMARY.md | 2 + docs/src/operations/index.md | 4 ++ docs/src/operations/pool.md | 107 +++++++++++++++++++++++++++++++++++ 3 files changed, 113 insertions(+) create mode 100644 docs/src/operations/index.md create mode 100644 docs/src/operations/pool.md diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index 571b813..cf70574 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -5,3 +5,5 @@ # User Guide - [Concepts](concepts.md) +- [Operations](operations/index.md) + - [Managing a pool](operations/pool.md) diff --git a/docs/src/operations/index.md b/docs/src/operations/index.md new file mode 100644 index 0000000..106cc27 --- /dev/null +++ b/docs/src/operations/index.md @@ -0,0 +1,4 @@ +# Operations + +This chapter covers the day-to-day operations for managing nodes with the +Bootc Operator. diff --git a/docs/src/operations/pool.md b/docs/src/operations/pool.md new file mode 100644 index 0000000..ecc4b0f --- /dev/null +++ b/docs/src/operations/pool.md @@ -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.