Seed bootapi-images: node rootfs build #1

Open
unkinben wants to merge 1 commits from benvin/bootapi-images-initial into main
10 changed files with 277 additions and 1 deletions
+2
View File
@@ -0,0 +1,2 @@
/rootfs/
/dist/
+20
View File
@@ -0,0 +1,20 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-added-large-files
- id: check-merge-conflict
- repo: https://github.com/adrienverge/yamllint
rev: v1.35.1
hooks:
- id: yamllint
args: [-c, .yamllint.yaml]
- repo: https://github.com/shellcheck-py/shellcheck-py
rev: v0.10.0.1
hooks:
- id: shellcheck
+18
View File
@@ -0,0 +1,18 @@
when:
- event: [pull_request, push]
steps:
- name: lint
image: koalaman/shellcheck-alpine:stable
commands:
- shellcheck scripts/*.sh
backend_options:
kubernetes:
serviceAccountName: default
resources:
requests:
memory: 128Mi
cpu: 100m
limits:
memory: 512Mi
cpu: 500m
+18
View File
@@ -0,0 +1,18 @@
when:
- event: [pull_request, push]
steps:
- name: pre-commit
image: git.unkin.net/unkin/almalinux9-gobuilder:20260606
commands:
- uvx pre-commit run --all-files
backend_options:
kubernetes:
serviceAccountName: default
resources:
requests:
memory: 512Mi
cpu: 1
limits:
memory: 2Gi
cpu: 2
+57
View File
@@ -0,0 +1,57 @@
when:
- event: tag
ref: refs/tags/v*
# On a v* tag: build the AlmaLinux 9 node rootfs and publish
# almalinux9-node-<tag-without-v>.tar.zst to the artifactapi rootfs-images local
# repo, where the bootapi-templates almalinux9-image catalog entry's liveimg
# points. Bump the image with `make patch|minor|major`.
steps:
- name: build-rootfs
image: git.unkin.net/unkin/almalinux9-base:20260606
commands:
- dnf -y install tar zstd
- ./scripts/build-rootfs.sh ${CI_COMMIT_TAG}
backend_options:
kubernetes:
serviceAccountName: default
resources:
requests:
memory: 2Gi
cpu: 2
ephemeral-storage: 8Gi
limits:
memory: 4Gi
cpu: 4
ephemeral-storage: 16Gi
- name: upload
image: git.unkin.net/unkin/almalinux9-base:20260606
commands:
- |
VER="${CI_COMMIT_TAG#v}"
HOST="https://artifactapi.k8s.syd1.au.unkin.net"
REPO="rootfs-images"
FILE="almalinux9-node-$${VER}.tar.zst"
# Immutable, versioned artifact; skip if this version already exists.
code=$$(curl -s -o /dev/null -w '%{http_code}' "$$HOST/api/v2/remotes/$$REPO/files/$$FILE" || true)
if [ "$$code" = "200" ]; then
echo "$$FILE already exists (HTTP $$code); skipping upload"
exit 0
fi
curl -f -X PUT "$$HOST/api/v2/remotes/$$REPO/files/$$FILE" \
-H "Content-Type: application/zstd" \
--data-binary @"dist/$$FILE"
depends_on: [build-rootfs]
backend_options:
kubernetes:
serviceAccountName: default
resources:
requests:
memory: 512Mi
cpu: 500m
ephemeral-storage: 8Gi
limits:
memory: 1Gi
cpu: 1
ephemeral-storage: 16Gi
+8
View File
@@ -0,0 +1,8 @@
---
extends: relaxed
rules:
line-length: disable
document-start: disable
comments:
min-spaces-from-content: 1
+32
View File
@@ -0,0 +1,32 @@
.PHONY: build lint clean patch minor major
VERSION ?= $(shell git describe --tags --always --dirty 2>/dev/null || echo "0.0.0-dev")
# Build the rootfs tarball locally (needs dnf + tar + zstd; run as root).
build:
./scripts/build-rootfs.sh $(VERSION)
lint:
shellcheck scripts/*.sh
clean:
rm -rf rootfs/ dist/
# --- version bump: tag + push triggers the release pipeline (build + upload) ---
_LATEST := $(shell git tag --sort=-v:refname | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$$' | head -1)
_BASE := $(if $(_LATEST),$(_LATEST),v0.0.0)
_MAJ := $(shell echo $(_BASE) | sed 's/^v//' | cut -d. -f1)
_MIN := $(shell echo $(_BASE) | sed 's/^v//' | cut -d. -f2)
_PAT := $(shell echo $(_BASE) | sed 's/^v//' | cut -d. -f3)
patch:
@NEW=v$(_MAJ).$(_MIN).$(shell expr $(_PAT) + 1); \
git tag $$NEW && echo "Tagged $$NEW" && git push origin $$NEW
minor:
@NEW=v$(_MAJ).$(shell expr $(_MIN) + 1).0; \
git tag $$NEW && echo "Tagged $$NEW" && git push origin $$NEW
major:
@NEW=v$(shell expr $(_MAJ) + 1).0.0; \
git tag $$NEW && echo "Tagged $$NEW" && git push origin $$NEW
+39 -1
View File
@@ -1,3 +1,41 @@
# bootapi-images
Builds AlmaLinux node rootfs tarballs for bootapi image-based provisioning; on v* tag publishes almalinux9-node-<ver>.tar.zst to the artifactapi rootfs-images repo.
Builds the AlmaLinux 9 **node rootfs** tarball that
[bootapi](https://git.unkin.net/unkin/bootapi)'s image-based provisioning unpacks
with Anaconda `liveimg`. On a `v*` tag it publishes
`almalinux9-node-<ver>.tar.zst` to the artifactapi `rootfs-images` local repo,
where the [bootapi-templates](https://git.unkin.net/unkin/bootapi-templates)
`almalinux9-image` catalog entry's `rootfs_tarball` points.
This is the build half; the kickstart/catalog that *consumes* the tarball live in
bootapi-templates. Kept separate so that repo stays templates-only.
## What's baked in
`packages.txt` is the package set installed into the rootfs — everything the
`image.ks.tmpl` `%post` assumes is already present (kernel, grub2 BIOS+UEFI,
dracut, NetworkManager, openssh, chrony, kexec-tools, curl, …). `puppet-agent` is
added from the puppet platform repo in `scripts/build-rootfs.sh`. Per-host config
(networking, hostname, puppet server, callback) stays in the kickstart `%post`.
## Layout
```
packages.txt # bake list (one package per line)
scripts/build-rootfs.sh # dnf --installroot -> tar.zst
.woodpecker/ # pre-commit + lint (PR); release build+upload (v* tag)
Makefile # build / lint / patch|minor|major
```
## Releasing an image
`make patch|minor|major` tags `v<x.y.z>` and pushes; CI builds the rootfs and
uploads `almalinux9-node-<x.y.z>.tar.zst`. Then bump `rootfs_tarball` in the
bootapi-templates `almalinux9-image` catalog entry to the new version (immutable;
overwrites are 409-rejected).
Build locally (needs `dnf`, `tar`, `zstd`, root):
```bash
make build VERSION=v0.0.0-dev
```
+40
View File
@@ -0,0 +1,40 @@
# Package set baked into the AlmaLinux 9 node rootfs image.
# Everything image.ks.tmpl's %post assumes is already installed (puppet-agent is
# added separately in build-rootfs.sh from the puppet platform repo). One package
# per line; blank lines and # comments ignored.
# base system + kernel
@core
kernel
# boot chain: BIOS + UEFI (fleet firmware is not standardized yet)
grub2-pc
grub2-efi-x64
shim-x64
grub2-tools
grub2-tools-efi
efibootmgr
dracut
dracut-config-generic
# storage
lvm2
xfsprogs
e2fsprogs
dosfstools
# networking + selinux
NetworkManager
selinux-policy-targeted
policycoreutils
# node tooling (matches the classic package install)
openssh-server
chrony
kexec-tools
bind-utils
vim-minimal
tmux
git
curl
glibc-langpack-en
+43
View File
@@ -0,0 +1,43 @@
#!/usr/bin/env bash
#
# Build the AlmaLinux 9 node rootfs and tar it as almalinux9-node-<ver>.tar.zst
# for bootapi image-based provisioning (liveimg). Usage:
# scripts/build-rootfs.sh [version] (version defaults to ${CI_COMMIT_TAG#v})
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "${ROOT_DIR}"
VER="${1:-${CI_COMMIT_TAG:-0.0.0-dev}}"
VER="${VER#v}"
RELEASEVER="${RELEASEVER:-9}"
ROOTFS="${ROOTFS:-${ROOT_DIR}/rootfs}"
DIST="${DIST:-${ROOT_DIR}/dist}"
OUT="${DIST}/almalinux9-node-${VER}.tar.zst"
# Read the bake list (skip comments / blank lines).
mapfile -t PKGS < <(grep -vE '^[[:space:]]*(#|$)' packages.txt)
if [ "${#PKGS[@]}" -eq 0 ]; then
echo "ERROR: packages.txt is empty" >&2
exit 1
fi
rm -rf "${ROOTFS}"
mkdir -p "${ROOTFS}" "${DIST}"
dnf -y --installroot="${ROOTFS}" --releasever="${RELEASEVER}" \
--setopt=install_weak_deps=False install "${PKGS[@]}"
# Puppet agent from the puppet platform repo (baked; image.ks.tmpl %post only
# configures it).
dnf -y --installroot="${ROOTFS}" install https://yum.puppet.com/puppet8-release-el-9.noarch.rpm
dnf -y --installroot="${ROOTFS}" install puppet-agent
dnf -y --installroot="${ROOTFS}" clean all
rm -rf "${ROOTFS}"/var/cache/dnf/* "${ROOTFS}"/var/log/dnf* "${ROOTFS}"/etc/machine-id
# Reproducible, ownership/xattr/SELinux-preserving tarball.
tar --numeric-owner --acls --xattrs --selinux -C "${ROOTFS}" -caf "${OUT}" .
echo "Built: ${OUT}"
ls -lh "${OUT}"