- Moved all documentation files to docs/ directory for better organization - Maintained all existing documentation content - Improved project structure for better maintainability - Documentation now follows standard open source project layout
1562 lines
No EOL
40 KiB
Markdown
1562 lines
No EOL
40 KiB
Markdown
# Building Universal Blue Systems on Your Own Infrastructure: Complete Guide
|
|
|
|
This guide walks you through building Universal Blue operating systems (Bazzite, Aurora, Bluefin, uCore, and custom images) on your own git servers and infrastructure, including the complete ecosystem of tools needed to create bootable operating system images.
|
|
|
|
## Overview
|
|
|
|
Universal Blue systems use a container-native approach where the OS is built as a container image, then converted to bootable formats using a comprehensive ecosystem of tools. The key components are:
|
|
|
|
### Core Infrastructure Tools
|
|
- **Container Image**: The OS filesystem and packages in OCI format
|
|
- **bootc**: Container bootloader interface for updates and management
|
|
- **bootupd**: Handles A/B partition updates for atomic upgrades
|
|
- **bootc-image-builder**: Converts container images to bootable drive formats
|
|
- **osbuilder**: Red Hat's advanced OS building tool for complex image customization and multi-arch builds
|
|
- **rpm-ostree**: Package layering and system management
|
|
|
|
### Universal Blue Ecosystem Tools
|
|
- **BlueBuild**: Declarative image building framework using `recipe.yml` files
|
|
- **startingpoint**: Template repository for creating custom Universal Blue images
|
|
- **forge**: On-premise Universal Blue infrastructure for self-hosting
|
|
- **ujust**: Justfile-based system management and automation
|
|
- **upgrade-tools**: Migration utilities for switching between Universal Blue images
|
|
- **ublue-os packages**: Package management and application installation system
|
|
|
|
### Target Systems
|
|
- **Bazzite**: Gaming-focused desktop and handheld OS
|
|
- **Aurora**: KDE desktop environment variant
|
|
- **Bluefin**: GNOME-based developer workstation
|
|
- **uCore**: Fedora CoreOS with batteries included
|
|
- **Custom Images**: Your own Universal Blue derivatives
|
|
|
|
## Prerequisites
|
|
|
|
### Infrastructure Requirements
|
|
- Git server (GitLab, Gitea, etc.) with webhook capabilities
|
|
- Container registry (Harbor, GitLab Registry, Docker Registry, etc.)
|
|
- CI/CD system with privileged container support
|
|
- Sufficient storage (100GB+ for builds, 20GB+ per bootable image)
|
|
- x86_64 build environment with adequate RAM (16GB+ recommended for multiple variants)
|
|
- For osbuilder: Additional storage for composer workspaces (100GB+ recommended)
|
|
|
|
### Software Dependencies
|
|
- Podman or Docker with buildah support
|
|
- bootc-image-builder container access
|
|
- osbuilder (osbuild, composer) for advanced builds
|
|
- BlueBuild CLI for declarative builds
|
|
- Registry authentication configured in CI
|
|
- just command runner for automation
|
|
|
|
## Step 1: Repository Setup and Tool Installation
|
|
|
|
### 1.1 Install Universal Blue Tools
|
|
|
|
Create `scripts/setup-ublue-tools.sh`:
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
set -euo pipefail
|
|
|
|
echo "Setting up Universal Blue ecosystem tools..."
|
|
|
|
# Install just command runner
|
|
curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to /usr/local/bin
|
|
|
|
# Install BlueBuild CLI
|
|
cargo install bluebuild
|
|
|
|
# Install bootc tools
|
|
sudo rpm-ostree install bootc bootupd
|
|
|
|
# Install osbuilder/osbuild
|
|
sudo dnf install -y osbuild osbuild-composer composer-cli
|
|
|
|
# Start and enable osbuild-composer
|
|
sudo systemctl enable --now osbuild-composer.socket
|
|
|
|
# Add current user to weldr group for composer access
|
|
sudo usermod -a -G weldr $(whoami)
|
|
|
|
echo "Universal Blue tools installation complete"
|
|
```
|
|
|
|
### 1.2 Clone Universal Blue Repositories
|
|
|
|
```bash
|
|
# Create workspace for all Universal Blue systems
|
|
mkdir -p ublue-workspace
|
|
cd ublue-workspace
|
|
|
|
# Clone main Universal Blue repositories
|
|
git clone https://github.com/ublue-os/main.git
|
|
git clone https://github.com/ublue-os/bazzite.git
|
|
git clone https://github.com/ublue-os/bluefin.git
|
|
git clone https://github.com/ublue-os/aurora.git
|
|
git clone https://github.com/ublue-os/ucore.git
|
|
git clone https://github.com/ublue-os/startingpoint.git
|
|
git clone https://github.com/ublue-os/forge.git
|
|
|
|
# Clone ecosystem tools
|
|
git clone https://github.com/ublue-os/packages.git
|
|
git clone https://github.com/ublue-os/upgrade-tools.git
|
|
|
|
# Update remotes to point to your infrastructure
|
|
for repo in main bazzite bluefin aurora ucore startingpoint forge packages upgrade-tools; do
|
|
cd $repo
|
|
git remote set-url origin https://your-git-server.com/ublue-os/$repo.git
|
|
git push origin main
|
|
cd ..
|
|
done
|
|
```
|
|
|
|
### 1.3 Set Up forge for On-Premise Infrastructure
|
|
|
|
```bash
|
|
cd forge
|
|
|
|
# Configure forge for your environment
|
|
cp config/config.yaml.example config/config.yaml
|
|
|
|
# Edit config.yaml with your settings
|
|
cat > config/config.yaml << EOF
|
|
forge:
|
|
domain: "forge.yourdomain.com"
|
|
registry: "your-registry.com"
|
|
git_server: "your-git-server.com"
|
|
|
|
builds:
|
|
parallel_jobs: 4
|
|
storage_path: "/var/lib/forge/builds"
|
|
|
|
images:
|
|
- name: "bazzite"
|
|
variants: ["desktop", "deck", "ally", "legion"]
|
|
- name: "bluefin"
|
|
variants: ["base", "dx", "nvidia"]
|
|
- name: "aurora"
|
|
variants: ["base", "dx", "nvidia"]
|
|
- name: "ucore"
|
|
variants: ["base", "minimal"]
|
|
EOF
|
|
|
|
# Deploy forge
|
|
just setup-forge
|
|
```
|
|
|
|
## Step 2: BlueBuild Integration for Declarative Builds
|
|
|
|
### 2.1 Understanding BlueBuild
|
|
|
|
BlueBuild enables building full images by only editing a recipe file, with no need to delve into Containerfiles or GitHub Actions. This makes it much easier to maintain Universal Blue systems.
|
|
|
|
### 2.2 Convert Existing Images to BlueBuild Format
|
|
|
|
Create `recipes/bazzite.yml`:
|
|
|
|
```yaml
|
|
name: bazzite
|
|
description: Bazzite Gaming OS
|
|
base-image: ghcr.io/ublue-os/silverblue-main
|
|
image-version: 40
|
|
|
|
stages:
|
|
- type: default-flatpaks
|
|
notify: true
|
|
system:
|
|
repo-url: https://dl.flathub.org/repo/flathub.flatpakrepo
|
|
install:
|
|
- com.valvesoftware.Steam
|
|
- org.lutris.Lutris
|
|
- com.heroicgameslauncher.hgl
|
|
|
|
modules:
|
|
- type: rpm-ostree
|
|
repos:
|
|
- https://copr.fedorainfracloud.org/coprs/kylegospo/bazzite/repo/fedora-%OS_VERSION%/kylegospo-bazzite-fedora-%OS_VERSION%.repo
|
|
install:
|
|
- gamemode
|
|
- gamescope
|
|
- jupiter-fan-control
|
|
- steamdeck-kde-presets
|
|
remove:
|
|
- firefox
|
|
- firefox-langpacks
|
|
|
|
- type: signing
|
|
cosign-private-key: /etc/pki/containers/cosign.key
|
|
|
|
- type: script
|
|
scripts:
|
|
- gaming-optimizations.sh
|
|
- steam-deck-support.sh
|
|
|
|
files:
|
|
- source: config/
|
|
destination: /etc/bazzite/
|
|
```
|
|
|
|
### 2.3 Create BlueBuild Recipes for All Systems
|
|
|
|
**recipes/bluefin.yml:**
|
|
```yaml
|
|
name: bluefin
|
|
description: Bluefin Developer Workstation
|
|
base-image: ghcr.io/ublue-os/silverblue-main
|
|
image-version: 40
|
|
|
|
modules:
|
|
- type: rpm-ostree
|
|
repos:
|
|
- https://copr.fedorainfracloud.org/coprs/projectbluefin/bluefin/repo/fedora-%OS_VERSION%/projectbluefin-bluefin-fedora-%OS_VERSION%.repo
|
|
install:
|
|
- distrobox
|
|
- toolbox
|
|
- code
|
|
- podman-compose
|
|
- docker-compose
|
|
|
|
- type: containerfiles
|
|
containerfiles:
|
|
- containerfiles/bluefin/Containerfile.dx
|
|
|
|
stages:
|
|
- type: default-flatpaks
|
|
system:
|
|
install:
|
|
- com.visualstudio.code
|
|
- com.docker.Docker
|
|
- io.podman_desktop.PodmanDesktop
|
|
```
|
|
|
|
**recipes/aurora.yml:**
|
|
```yaml
|
|
name: aurora
|
|
description: Aurora KDE Desktop
|
|
base-image: ghcr.io/ublue-os/kinoite-main
|
|
image-version: 40
|
|
|
|
modules:
|
|
- type: rpm-ostree
|
|
install:
|
|
- kde-connect
|
|
- krita
|
|
- kdenlive
|
|
remove:
|
|
- konversation
|
|
|
|
stages:
|
|
- type: default-flatpaks
|
|
system:
|
|
install:
|
|
- org.kde.krita
|
|
- org.kde.kdenlive
|
|
- org.telegram.desktop
|
|
```
|
|
|
|
**recipes/ucore.yml:**
|
|
```yaml
|
|
name: ucore
|
|
description: Fedora CoreOS with batteries included
|
|
base-image: quay.io/fedora/fedora-coreos
|
|
image-version: stable
|
|
|
|
modules:
|
|
- type: rpm-ostree
|
|
install:
|
|
- tailscale
|
|
- podman-compose
|
|
- docker-compose
|
|
- btop
|
|
- micro
|
|
|
|
- type: systemd
|
|
system:
|
|
enabled:
|
|
- tailscaled
|
|
- podman.socket
|
|
```
|
|
|
|
## Step 3: Comprehensive CI/CD Pipeline
|
|
|
|
### 3.1 GitLab CI Configuration
|
|
|
|
Create `.gitlab-ci.yml`:
|
|
|
|
```yaml
|
|
stages:
|
|
- setup
|
|
- build-base
|
|
- build-variants
|
|
- bootc-validate
|
|
- generate-bootable-images
|
|
- publish
|
|
- deploy-forge
|
|
|
|
variables:
|
|
REGISTRY: "your-registry.com"
|
|
FORGE_URL: "https://forge.yourdomain.com"
|
|
|
|
# Build matrix for all Universal Blue systems
|
|
.build_template: &build_template
|
|
stage: build-variants
|
|
script:
|
|
- |
|
|
if [ -f "recipes/${SYSTEM}.yml" ]; then
|
|
bluebuild build recipes/${SYSTEM}.yml --registry ${REGISTRY}
|
|
else
|
|
podman build -f Containerfile.${SYSTEM} -t ${REGISTRY}/ublue-os/${SYSTEM}:${CI_COMMIT_SHA} .
|
|
fi
|
|
- podman push ${REGISTRY}/ublue-os/${SYSTEM}:${CI_COMMIT_SHA}
|
|
tags:
|
|
- privileged
|
|
|
|
setup-tools:
|
|
stage: setup
|
|
script:
|
|
- ./scripts/setup-ublue-tools.sh
|
|
artifacts:
|
|
paths:
|
|
- /usr/local/bin/just
|
|
expire_in: 1 hour
|
|
|
|
build-base-images:
|
|
stage: build-base
|
|
script:
|
|
- cd main
|
|
- podman build -f Containerfile.silverblue -t ${REGISTRY}/ublue-os/silverblue-main:latest
|
|
- podman build -f Containerfile.kinoite -t ${REGISTRY}/ublue-os/kinoite-main:latest
|
|
- podman push ${REGISTRY}/ublue-os/silverblue-main:latest
|
|
- podman push ${REGISTRY}/ublue-os/kinoite-main:latest
|
|
dependencies:
|
|
- setup-tools
|
|
|
|
# Build all Universal Blue systems
|
|
bazzite:
|
|
<<: *build_template
|
|
variables:
|
|
SYSTEM: "bazzite"
|
|
dependencies:
|
|
- build-base-images
|
|
|
|
bluefin:
|
|
<<: *build_template
|
|
variables:
|
|
SYSTEM: "bluefin"
|
|
dependencies:
|
|
- build-base-images
|
|
|
|
aurora:
|
|
<<: *build_template
|
|
variables:
|
|
SYSTEM: "aurora"
|
|
dependencies:
|
|
- build-base-images
|
|
|
|
ucore:
|
|
<<: *build_template
|
|
variables:
|
|
SYSTEM: "ucore"
|
|
dependencies:
|
|
- build-base-images
|
|
|
|
# Validation stage
|
|
validate-images:
|
|
stage: bootc-validate
|
|
parallel:
|
|
matrix:
|
|
- SYSTEM: ["bazzite", "bluefin", "aurora", "ucore"]
|
|
script:
|
|
- podman run --rm ${REGISTRY}/ublue-os/${SYSTEM}:${CI_COMMIT_SHA} bootc container lint
|
|
dependencies:
|
|
- bazzite
|
|
- bluefin
|
|
- aurora
|
|
- ucore
|
|
|
|
# Bootable image generation
|
|
generate-bootable:
|
|
stage: generate-bootable-images
|
|
parallel:
|
|
matrix:
|
|
- SYSTEM: ["bazzite", "bluefin", "aurora", "ucore"]
|
|
BUILDER: ["bootc-image-builder", "osbuilder"]
|
|
script:
|
|
- mkdir -p output/${SYSTEM}
|
|
- |
|
|
if [ "$BUILDER" == "bootc-image-builder" ]; then
|
|
podman run --rm --privileged \
|
|
-v $PWD/output/${SYSTEM}:/output \
|
|
-v /var/lib/containers/storage:/var/lib/containers/storage \
|
|
quay.io/centos-bootc/bootc-image-builder:latest \
|
|
--type iso,raw \
|
|
--output /output \
|
|
${REGISTRY}/ublue-os/${SYSTEM}:${CI_COMMIT_SHA}
|
|
else
|
|
BUILD_METHOD=osbuilder-only OUTPUT_DIR=output/${SYSTEM} \
|
|
./scripts/build-with-osbuilder.sh ${REGISTRY}/ublue-os/${SYSTEM}:${CI_COMMIT_SHA}
|
|
fi
|
|
artifacts:
|
|
paths:
|
|
- output/
|
|
expire_in: 1 week
|
|
tags:
|
|
- privileged
|
|
dependencies:
|
|
- validate-images
|
|
|
|
# Deploy to forge
|
|
deploy-to-forge:
|
|
stage: deploy-forge
|
|
script:
|
|
- |
|
|
curl -X POST ${FORGE_URL}/api/builds \
|
|
-H "Authorization: Bearer ${FORGE_TOKEN}" \
|
|
-d '{
|
|
"images": ["bazzite", "bluefin", "aurora", "ucore"],
|
|
"tag": "'${CI_COMMIT_SHA}'"
|
|
}'
|
|
dependencies:
|
|
- generate-bootable
|
|
```
|
|
|
|
## Step 4: ujust Integration for System Management
|
|
|
|
### 4.1 Create Comprehensive Justfile
|
|
|
|
Create `justfile` for system management:
|
|
|
|
```just
|
|
#!/usr/bin/env just --justfile
|
|
|
|
# Default recipe to display help
|
|
default:
|
|
@just --list
|
|
|
|
# Build all Universal Blue systems
|
|
build-all:
|
|
#!/usr/bin/env bash
|
|
for system in bazzite bluefin aurora ucore; do
|
|
echo "Building $system..."
|
|
if [ -f "recipes/$system.yml" ]; then
|
|
bluebuild build "recipes/$system.yml"
|
|
else
|
|
podman build -f "Containerfile.$system" -t "localhost/ublue-os/$system:latest" .
|
|
fi
|
|
done
|
|
|
|
# Build specific system
|
|
build system:
|
|
#!/usr/bin/env bash
|
|
if [ -f "recipes/{{system}}.yml" ]; then
|
|
bluebuild build "recipes/{{system}}.yml"
|
|
else
|
|
podman build -f "Containerfile.{{system}}" -t "localhost/ublue-os/{{system}}:latest" .
|
|
fi
|
|
|
|
# Generate bootable images for a system
|
|
generate-bootable system builder="both":
|
|
#!/usr/bin/env bash
|
|
mkdir -p output/{{system}}
|
|
BUILD_METHOD={{builder}} OUTPUT_DIR=output/{{system}} \
|
|
./scripts/build-bootable.sh localhost/ublue-os/{{system}}:latest
|
|
|
|
# Set up development environment
|
|
setup-dev:
|
|
#!/usr/bin/env bash
|
|
./scripts/setup-ublue-tools.sh
|
|
echo "Development environment ready"
|
|
|
|
# Clean build artifacts
|
|
clean:
|
|
#!/usr/bin/env bash
|
|
rm -rf output/
|
|
podman image prune -f
|
|
podman system prune -f
|
|
|
|
# Install ujust recipes for end users
|
|
install-ujust-recipes:
|
|
#!/usr/bin/env bash
|
|
sudo mkdir -p /usr/share/ublue-os/just
|
|
sudo cp -r just/* /usr/share/ublue-os/just/
|
|
echo "ujust recipes installed system-wide"
|
|
|
|
# Update all base images
|
|
update-bases:
|
|
#!/usr/bin/env bash
|
|
podman pull ghcr.io/ublue-os/silverblue-main:latest
|
|
podman pull ghcr.io/ublue-os/kinoite-main:latest
|
|
podman pull quay.io/fedora/fedora-coreos:stable
|
|
echo "Base images updated"
|
|
|
|
# Validate all images
|
|
validate-all:
|
|
#!/usr/bin/env bash
|
|
for system in bazzite bluefin aurora ucore; do
|
|
echo "Validating $system..."
|
|
podman run --rm localhost/ublue-os/$system:latest bootc container lint
|
|
done
|
|
|
|
# Deploy to forge
|
|
deploy-forge tag="latest":
|
|
#!/usr/bin/env bash
|
|
curl -X POST ${FORGE_URL}/api/builds \
|
|
-H "Authorization: Bearer ${FORGE_TOKEN}" \
|
|
-d '{
|
|
"images": ["bazzite", "bluefin", "aurora", "ucore"],
|
|
"tag": "{{tag}}"
|
|
}'
|
|
```
|
|
|
|
### 4.2 End-User ujust Recipes
|
|
|
|
Create `just/` directory with user-facing commands:
|
|
|
|
**just/bazzite.just:**
|
|
```just
|
|
# Gaming-specific ujust commands for Bazzite
|
|
|
|
# Install Steam
|
|
install-steam:
|
|
flatpak install -y flathub com.valvesoftware.Steam
|
|
|
|
# Install Lutris
|
|
install-lutris:
|
|
flatpak install -y flathub org.lutris.Lutris
|
|
|
|
# Enable Gamemode optimizations
|
|
enable-gamemode:
|
|
systemctl --user enable gamemoded
|
|
|
|
# Install OpenTabletDriver
|
|
install-opentabletdriver:
|
|
rpm-ostree install opentabletdriver
|
|
|
|
# Toggle Wayland session
|
|
toggle-wayland:
|
|
#!/usr/bin/env bash
|
|
if grep -q "WaylandEnable=false" /etc/gdm/custom.conf; then
|
|
sudo sed -i 's/WaylandEnable=false/WaylandEnable=true/' /etc/gdm/custom.conf
|
|
echo "Wayland enabled. Restart required."
|
|
else
|
|
sudo sed -i 's/WaylandEnable=true/WaylandEnable=false/' /etc/gdm/custom.conf
|
|
echo "Wayland disabled. Restart required."
|
|
fi
|
|
```
|
|
|
|
**just/bluefin.just:**
|
|
```just
|
|
# Developer-focused ujust commands for Bluefin
|
|
|
|
# Set up development environment
|
|
setup-dev-env:
|
|
#!/usr/bin/env bash
|
|
distrobox create --name dev --image registry.fedoraproject.org/fedora:latest
|
|
distrobox enter dev -- sudo dnf install -y nodejs npm python3-pip golang rust cargo
|
|
echo "Development environment created in 'dev' distrobox"
|
|
|
|
# Install VS Code via Flatpak
|
|
install-vscode:
|
|
flatpak install -y flathub com.visualstudio.code
|
|
|
|
# Enable Docker/Podman services
|
|
enable-containers:
|
|
systemctl --user enable podman.socket
|
|
sudo systemctl enable docker
|
|
|
|
# Install development Flatpaks
|
|
install-dev-flatpaks:
|
|
#!/usr/bin/env bash
|
|
flatpaks=(
|
|
"com.docker.Docker"
|
|
"io.podman_desktop.PodmanDesktop"
|
|
"com.github.tchx84.Flatseal"
|
|
"org.gnome.Builder"
|
|
)
|
|
for app in "${flatpaks[@]}"; do
|
|
flatpak install -y flathub $app
|
|
done
|
|
```
|
|
|
|
## Step 5: Package Management Integration
|
|
|
|
### 5.1 Universal Blue Packages System
|
|
|
|
Create `packages/packages.json`:
|
|
|
|
```json
|
|
{
|
|
"packages": {
|
|
"gaming": {
|
|
"flatpaks": [
|
|
"com.valvesoftware.Steam",
|
|
"org.lutris.Lutris",
|
|
"com.heroicgameslauncher.hgl",
|
|
"net.davidotek.pupgui2"
|
|
],
|
|
"rpms": [
|
|
"gamemode",
|
|
"gamescope"
|
|
]
|
|
},
|
|
"development": {
|
|
"flatpaks": [
|
|
"com.visualstudio.code",
|
|
"com.docker.Docker",
|
|
"io.podman_desktop.PodmanDesktop"
|
|
],
|
|
"rpms": [
|
|
"distrobox",
|
|
"toolbox"
|
|
]
|
|
},
|
|
"multimedia": {
|
|
"flatpaks": [
|
|
"org.kde.krita",
|
|
"org.blender.Blender",
|
|
"org.audacityteam.Audacity"
|
|
]
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### 5.2 Package Installation Scripts
|
|
|
|
Create `scripts/install-packages.sh`:
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
set -euo pipefail
|
|
|
|
PACKAGE_GROUP="$1"
|
|
PACKAGES_FILE="packages/packages.json"
|
|
|
|
echo "Installing package group: $PACKAGE_GROUP"
|
|
|
|
# Install Flatpaks
|
|
if jq -e ".packages.$PACKAGE_GROUP.flatpaks" "$PACKAGES_FILE" > /dev/null; then
|
|
flatpaks=$(jq -r ".packages.$PACKAGE_GROUP.flatpaks[]" "$PACKAGES_FILE")
|
|
for app in $flatpaks; do
|
|
echo "Installing Flatpak: $app"
|
|
flatpak install -y flathub "$app"
|
|
done
|
|
fi
|
|
|
|
# Install RPMs
|
|
if jq -e ".packages.$PACKAGE_GROUP.rpms" "$PACKAGES_FILE" > /dev/null; then
|
|
rpms=$(jq -r ".packages.$PACKAGE_GROUP.rpms[]" "$PACKAGES_FILE")
|
|
for pkg in $rpms; do
|
|
echo "Installing RPM: $pkg"
|
|
rpm-ostree install "$pkg"
|
|
done
|
|
fi
|
|
|
|
echo "Package group $PACKAGE_GROUP installation complete"
|
|
```
|
|
|
|
## Step 6: Upgrade Tools Integration
|
|
|
|
### 6.1 Migration Between Universal Blue Systems
|
|
|
|
Create `scripts/ublue-migration.sh`:
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
set -euo pipefail
|
|
|
|
SOURCE_SYSTEM="$1"
|
|
TARGET_SYSTEM="$2"
|
|
REGISTRY="${REGISTRY:-your-registry.com}"
|
|
|
|
echo "Migrating from $SOURCE_SYSTEM to $TARGET_SYSTEM"
|
|
|
|
# Use upgrade-tools for safe migration
|
|
if command -v ublue-upgrade >/dev/null 2>&1; then
|
|
ublue-upgrade "$REGISTRY/ublue-os/$TARGET_SYSTEM:latest"
|
|
else
|
|
# Fallback to bootc switch
|
|
sudo bootc switch "$REGISTRY/ublue-os/$TARGET_SYSTEM:latest"
|
|
fi
|
|
|
|
echo "Migration initiated. Reboot to complete."
|
|
```
|
|
|
|
## Step 7: Advanced osbuilder Configurations
|
|
|
|
### 7.1 Multi-System osbuilder Manifests
|
|
|
|
Create `scripts/generate-multi-system-manifest.sh`:
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
set -euo pipefail
|
|
|
|
SYSTEMS=("bazzite" "bluefin" "aurora" "ucore")
|
|
OUTPUT_DIR="osbuilder-workspace"
|
|
|
|
mkdir -p "$OUTPUT_DIR"
|
|
|
|
for system in "${SYSTEMS[@]}"; do
|
|
cat > "$OUTPUT_DIR/$system-manifest.json" << EOF
|
|
{
|
|
"version": "2",
|
|
"pipelines": [
|
|
{
|
|
"name": "$system-container-tree",
|
|
"source": {
|
|
"org.osbuild.containers": {
|
|
"images": {
|
|
"$system": {
|
|
"source": "your-registry.com/ublue-os/$system:latest",
|
|
"local": false
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"stages": [
|
|
{
|
|
"type": "org.osbuild.container-deploy",
|
|
"options": {
|
|
"image": "$system"
|
|
}
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"name": "$system-image",
|
|
"build": "$system-container-tree",
|
|
"stages": [
|
|
{
|
|
"type": "org.osbuild.truncate",
|
|
"options": {
|
|
"filename": "$system-disk.img",
|
|
"size": "10737418240"
|
|
}
|
|
},
|
|
{
|
|
"type": "org.osbuild.bootc.install-to-filesystem",
|
|
"options": {
|
|
"deployment": {
|
|
"container-image-reference": "your-registry.com/ublue-os/$system:latest"
|
|
},
|
|
"root_filesystem": "xfs"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
EOF
|
|
done
|
|
|
|
echo "Generated osbuilder manifests for all systems"
|
|
```
|
|
|
|
## Step 8: Security and Signing
|
|
|
|
### 8.1 Comprehensive Signing Pipeline
|
|
|
|
Create `scripts/sign-all-images.sh`:
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
set -euo pipefail
|
|
|
|
SYSTEMS=("bazzite" "bluefin" "aurora" "ucore")
|
|
REGISTRY="${REGISTRY:-your-registry.com}"
|
|
COSIGN_KEY="${COSIGN_KEY:-cosign.key}"
|
|
|
|
for system in "${SYSTEMS[@]}"; do
|
|
echo "Signing $system..."
|
|
cosign sign --key "$COSIGN_KEY" "$REGISTRY/ublue-os/$system:latest"
|
|
|
|
# Generate SBOM
|
|
syft "$REGISTRY/ublue-os/$system:latest" -o spdx-json > "$system-sbom.spdx.json"
|
|
cosign attest --key "$COSIGN_KEY" --predicate "$system-sbom.spdx.json" \
|
|
"$REGISTRY/ublue-os/$system:latest"
|
|
done
|
|
|
|
echo "All images signed and attested"
|
|
```
|
|
|
|
## Step 9: forge Deployment and Management
|
|
|
|
### 9.1 forge Configuration for All Systems
|
|
|
|
Update your forge configuration:
|
|
|
|
```yaml
|
|
# forge/config/systems.yaml
|
|
systems:
|
|
bazzite:
|
|
description: "Gaming-focused desktop and handheld OS"
|
|
variants:
|
|
- desktop
|
|
- deck
|
|
- ally
|
|
- legion
|
|
base_image: "silverblue-main"
|
|
|
|
bluefin:
|
|
description: "GNOME-based developer workstation"
|
|
variants:
|
|
- base
|
|
- dx
|
|
- nvidia
|
|
base_image: "silverblue-main"
|
|
|
|
aurora:
|
|
description: "KDE desktop environment variant"
|
|
variants:
|
|
- base
|
|
- dx
|
|
- nvidia
|
|
base_image: "kinoite-main"
|
|
|
|
ucore:
|
|
description: "Fedora CoreOS with batteries included"
|
|
variants:
|
|
- base
|
|
- minimal
|
|
base_image: "fedora-coreos"
|
|
|
|
build_matrix:
|
|
architectures:
|
|
- x86_64
|
|
- aarch64
|
|
formats:
|
|
- iso
|
|
- raw
|
|
- qcow2
|
|
builders:
|
|
- bootc-image-builder
|
|
- osbuilder
|
|
```
|
|
|
|
### 9.2 forge API Integration
|
|
|
|
Create `scripts/forge-api.sh`:
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
set -euo pipefail
|
|
|
|
FORGE_URL="${FORGE_URL:-https://forge.yourdomain.com}"
|
|
FORGE_TOKEN="${FORGE_TOKEN}"
|
|
ACTION="$1"
|
|
SYSTEM="${2:-all}"
|
|
|
|
case "$ACTION" in
|
|
"build")
|
|
curl -X POST "$FORGE_URL/api/builds" \
|
|
-H "Authorization: Bearer $FORGE_TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d "{\"system\": \"$SYSTEM\"}"
|
|
;;
|
|
"status")
|
|
curl -X GET "$FORGE_URL/api/builds/status" \
|
|
-H "Authorization: Bearer $FORGE_TOKEN"
|
|
;;
|
|
"artifacts")
|
|
curl -X GET "$FORGE_URL/api/artifacts/$SYSTEM" \
|
|
-H "Authorization: Bearer $FORGE_TOKEN"
|
|
;;
|
|
*)
|
|
echo "Usage: $0 {build|status|artifacts} [system]"
|
|
exit 1
|
|
;;
|
|
esac
|
|
```
|
|
|
|
## Step 10: Testing and Validation
|
|
|
|
### 10.1 Comprehensive Testing Pipeline
|
|
|
|
Create `scripts/test-all-systems.sh`:
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
set -euo pipefail
|
|
|
|
SYSTEMS=("bazzite" "bluefin" "aurora" "ucore")
|
|
OUTPUT_DIR="output"
|
|
|
|
for system in "${SYSTEMS[@]}"; do
|
|
echo "Testing $system..."
|
|
|
|
# Test container lint
|
|
podman run --rm "your-registry.com/ublue-os/$system:latest" bootc container lint
|
|
|
|
# Test bootable image
|
|
if [ -f "$OUTPUT_DIR/$system/disk.raw" ]; then
|
|
echo "Testing boot for $system..."
|
|
timeout 300 qemu-system-x86_64 \
|
|
-m 2G \
|
|
-drive file="$OUTPUT_DIR/$system/disk.raw",format=raw \
|
|
-nographic \
|
|
-serial stdio \
|
|
-monitor none || echo "$system boot test completed"
|
|
fi
|
|
|
|
# Test specific system features
|
|
case "$system" in
|
|
"bazzite")
|
|
echo "Testing gaming features..."
|
|
podman run --rm "your-registry.com/ublue-os/$system:latest" \
|
|
rpm -q gamemode gamescope
|
|
;;
|
|
"bluefin")
|
|
echo "Testing development tools..."
|
|
podman run --rm "your-registry.com/ublue-os/$system:latest" \
|
|
rpm -q distrobox toolbox
|
|
;;
|
|
esac
|
|
done
|
|
|
|
echo "All system tests completed"
|
|
```
|
|
|
|
## Step 11: Documentation and User Guides
|
|
|
|
### 11.1 Generate System Documentation
|
|
|
|
Create `scripts/generate-docs.sh`:
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
set -euo pipefail
|
|
|
|
SYSTEMS=("bazzite" "bluefin" "aurora" "ucore")
|
|
DOCS_DIR="docs"
|
|
|
|
mkdir -p "$DOCS_DIR"
|
|
|
|
for system in "${SYSTEMS[@]}"; do
|
|
cat > "$DOCS_DIR/$system.md" << EOF
|
|
# $system Installation and Usage Guide
|
|
|
|
## Installation
|
|
|
|
### From ISO
|
|
1. Download the $system ISO from your forge: https://forge.yourdomain.com
|
|
2. Write to USB: \`dd if=$system.iso of=/dev/sdX bs=4M status=progress\`
|
|
3. Boot and follow the installer
|
|
|
|
### From Existing System
|
|
\`\`\`bash
|
|
sudo bootc switch your-registry.com/ublue-os/$system:latest
|
|
sudo systemctl reboot
|
|
\`\`\`
|
|
|
|
## Available ujust Commands
|
|
\`\`\`bash
|
|
ujust --list
|
|
\`\`\`
|
|
|
|
## System-Specific Features
|
|
EOF
|
|
|
|
# Add system-specific documentation
|
|
case "$system" in
|
|
"bazzite")
|
|
cat >> "$DOCS_DIR/$system.md" << EOF
|
|
|
|
### Gaming Features
|
|
- Steam pre-installed and optimized
|
|
- Gamemode for performance optimization
|
|
- Handheld-specific optimizations for Steam Deck, ROG Ally, Legion Go
|
|
- \`ujust install-opentabletdriver\` for drawing tablet support
|
|
|
|
### Gaming Commands
|
|
- \`ujust install-steam\` - Install Steam
|
|
- \`ujust install-lutris\` - Install Lutris
|
|
- \`ujust enable-gamemode\` - Enable Gamemode optimizations
|
|
EOF
|
|
;;
|
|
"bluefin")
|
|
cat >> "$DOCS_DIR/$system.md" << EOF
|
|
|
|
### Developer Features
|
|
- Distrobox and Toolbox pre-configured
|
|
- Container development tools
|
|
- VS Code and development Flatpaks available
|
|
|
|
### Development Commands
|
|
- \`ujust setup-dev-env\` - Create development distrobox
|
|
- \`ujust install-vscode\` - Install VS Code
|
|
- \`ujust enable-containers\` - Enable Docker/Podman services
|
|
- \`ujust install-dev-flatpaks\` - Install development Flatpaks
|
|
EOF
|
|
;;
|
|
"aurora")
|
|
cat >> "$DOCS_DIR/$system.md" << EOF
|
|
|
|
### KDE Features
|
|
- KDE Plasma desktop environment
|
|
- KDE applications suite
|
|
- Multimedia tools pre-installed
|
|
|
|
### KDE Commands
|
|
- Standard ujust commands available
|
|
- KDE-specific configurations in System Settings
|
|
EOF
|
|
;;
|
|
"ucore")
|
|
cat >> "$DOCS_DIR/$system.md" << EOF
|
|
|
|
### Container Platform Features
|
|
- Fedora CoreOS base with additional tools
|
|
- Container orchestration ready
|
|
- Optimized for server/edge deployments
|
|
|
|
### Server Commands
|
|
- Standard container management tools
|
|
- Tailscale VPN integration
|
|
- Optimized for headless operation
|
|
EOF
|
|
;;
|
|
esac
|
|
|
|
echo "Generated documentation for $system"
|
|
done
|
|
|
|
echo "Documentation generation complete"
|
|
```
|
|
|
|
## Step 12: Maintenance and Monitoring
|
|
|
|
### 12.1 Automated Health Checks
|
|
|
|
Create `scripts/health-check.sh`:
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
set -euo pipefail
|
|
|
|
SYSTEMS=("bazzite" "bluefin" "aurora" "ucore")
|
|
REGISTRY="${REGISTRY:-your-registry.com}"
|
|
HEALTH_LOG="/var/log/ublue-health.log"
|
|
|
|
echo "=== Universal Blue Health Check $(date) ===" >> "$HEALTH_LOG"
|
|
|
|
for system in "${SYSTEMS[@]}"; do
|
|
echo "Checking $system..." | tee -a "$HEALTH_LOG"
|
|
|
|
# Check if image exists and is pullable
|
|
if podman pull "$REGISTRY/ublue-os/$system:latest" &>/dev/null; then
|
|
echo "✓ $system image available" | tee -a "$HEALTH_LOG"
|
|
else
|
|
echo "✗ $system image unavailable" | tee -a "$HEALTH_LOG"
|
|
continue
|
|
fi
|
|
|
|
# Check container lint
|
|
if podman run --rm "$REGISTRY/ublue-os/$system:latest" bootc container lint &>/dev/null; then
|
|
echo "✓ $system passes bootc lint" | tee -a "$HEALTH_LOG"
|
|
else
|
|
echo "✗ $system fails bootc lint" | tee -a "$HEALTH_LOG"
|
|
fi
|
|
|
|
# Check signature
|
|
if cosign verify "$REGISTRY/ublue-os/$system:latest" &>/dev/null; then
|
|
echo "✓ $system signature valid" | tee -a "$HEALTH_LOG"
|
|
else
|
|
echo "✗ $system signature invalid" | tee -a "$HEALTH_LOG"
|
|
fi
|
|
done
|
|
|
|
echo "Health check complete" | tee -a "$HEALTH_LOG"
|
|
```
|
|
|
|
### 12.2 Update Monitoring
|
|
|
|
Create `scripts/monitor-updates.sh`:
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
set -euo pipefail
|
|
|
|
SYSTEMS=("bazzite" "bluefin" "aurora" "ucore")
|
|
REGISTRY="${REGISTRY:-your-registry.com}"
|
|
WEBHOOK_URL="${WEBHOOK_URL:-}"
|
|
|
|
check_for_updates() {
|
|
local system="$1"
|
|
local current_digest=$(podman inspect "$REGISTRY/ublue-os/$system:latest" --format '{{.Digest}}' 2>/dev/null || echo "")
|
|
local remote_digest=$(skopeo inspect "docker://$REGISTRY/ublue-os/$system:latest" --format '{{.Digest}}' 2>/dev/null || echo "")
|
|
|
|
if [ "$current_digest" != "$remote_digest" ] && [ -n "$remote_digest" ]; then
|
|
echo "Update available for $system"
|
|
if [ -n "$WEBHOOK_URL" ]; then
|
|
curl -X POST "$WEBHOOK_URL" \
|
|
-H "Content-Type: application/json" \
|
|
-d "{\"text\": \"Update available for $system: $remote_digest\"}"
|
|
fi
|
|
return 0
|
|
fi
|
|
return 1
|
|
}
|
|
|
|
echo "Monitoring for updates..."
|
|
for system in "${SYSTEMS[@]}"; do
|
|
if check_for_updates "$system"; then
|
|
echo "Triggering rebuild for $system"
|
|
# Trigger CI pipeline or forge build
|
|
./scripts/forge-api.sh build "$system"
|
|
fi
|
|
done
|
|
```
|
|
|
|
### 12.3 Storage Management
|
|
|
|
Create `scripts/cleanup-storage.sh`:
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
set -euo pipefail
|
|
|
|
RETENTION_DAYS="${RETENTION_DAYS:-7}"
|
|
OUTPUT_DIR="output"
|
|
OSBUILDER_WORKSPACE="osbuilder-workspace"
|
|
|
|
echo "Cleaning up build artifacts older than $RETENTION_DAYS days..."
|
|
|
|
# Clean output artifacts
|
|
find "$OUTPUT_DIR" -type f -name "*.iso" -mtime +$RETENTION_DAYS -delete
|
|
find "$OUTPUT_DIR" -type f -name "*.raw" -mtime +$RETENTION_DAYS -delete
|
|
find "$OUTPUT_DIR" -type f -name "*.qcow2" -mtime +$RETENTION_DAYS -delete
|
|
|
|
# Clean osbuilder workspace
|
|
if [ -d "$OSBUILDER_WORKSPACE" ]; then
|
|
find "$OSBUILDER_WORKSPACE" -type f -mtime +$RETENTION_DAYS -delete
|
|
# Clean osbuilder store cache (keep recent builds)
|
|
sudo find "$OSBUILDER_WORKSPACE/store" -type f -mtime +$RETENTION_DAYS -delete 2>/dev/null || true
|
|
fi
|
|
|
|
# Prune container images (keep last 5 versions of each system)
|
|
SYSTEMS=("bazzite" "bluefin" "aurora" "ucore")
|
|
for system in "${SYSTEMS[@]}"; do
|
|
echo "Pruning old $system images..."
|
|
# Keep only the 5 most recent tags
|
|
podman images --format "table {{.Repository}}:{{.Tag}} {{.CreatedAt}}" \
|
|
--filter "reference=*/$system" \
|
|
--sort created \
|
|
| tail -n +6 \
|
|
| awk '{print $1}' \
|
|
| xargs -r podman rmi 2>/dev/null || true
|
|
done
|
|
|
|
# General container cleanup
|
|
podman system prune -f --volumes
|
|
|
|
echo "Storage cleanup complete"
|
|
```
|
|
|
|
## Step 13: Advanced forge Features
|
|
|
|
### 13.1 forge Web Interface Configuration
|
|
|
|
Create `forge/web/config.yaml`:
|
|
|
|
```yaml
|
|
server:
|
|
port: 8080
|
|
host: "0.0.0.0"
|
|
|
|
database:
|
|
type: "postgresql"
|
|
host: "localhost"
|
|
port: 5432
|
|
name: "forge"
|
|
user: "forge"
|
|
password_file: "/run/secrets/db_password"
|
|
|
|
build_queue:
|
|
workers: 4
|
|
max_concurrent_builds: 2
|
|
|
|
storage:
|
|
artifacts_path: "/var/lib/forge/artifacts"
|
|
max_artifact_age: "30d"
|
|
|
|
systems:
|
|
bazzite:
|
|
display_name: "Bazzite"
|
|
description: "The next generation of Linux gaming"
|
|
icon: "/static/icons/bazzite.svg"
|
|
variants:
|
|
desktop:
|
|
display_name: "Desktop"
|
|
description: "Full desktop gaming experience"
|
|
deck:
|
|
display_name: "Steam Deck"
|
|
description: "Optimized for Steam Deck"
|
|
ally:
|
|
display_name: "ROG Ally"
|
|
description: "Optimized for ASUS ROG Ally"
|
|
legion:
|
|
display_name: "Legion Go"
|
|
description: "Optimized for Lenovo Legion Go"
|
|
|
|
bluefin:
|
|
display_name: "Bluefin"
|
|
description: "The developer experience"
|
|
icon: "/static/icons/bluefin.svg"
|
|
variants:
|
|
base:
|
|
display_name: "Base"
|
|
description: "Standard developer workstation"
|
|
dx:
|
|
display_name: "Developer Experience"
|
|
description: "Enhanced developer tools and workflows"
|
|
nvidia:
|
|
display_name: "NVIDIA"
|
|
description: "With NVIDIA driver support"
|
|
|
|
aurora:
|
|
display_name: "Aurora"
|
|
description: "KDE desktop experience"
|
|
icon: "/static/icons/aurora.svg"
|
|
variants:
|
|
base:
|
|
display_name: "Base"
|
|
description: "Standard KDE desktop"
|
|
dx:
|
|
display_name: "Developer Experience"
|
|
description: "KDE with developer tools"
|
|
nvidia:
|
|
display_name: "NVIDIA"
|
|
description: "With NVIDIA driver support"
|
|
|
|
ucore:
|
|
display_name: "uCore"
|
|
description: "Fedora CoreOS with batteries included"
|
|
icon: "/static/icons/ucore.svg"
|
|
variants:
|
|
base:
|
|
display_name: "Base"
|
|
description: "Standard container platform"
|
|
minimal:
|
|
display_name: "Minimal"
|
|
description: "Minimal container platform"
|
|
```
|
|
|
|
### 13.2 forge API Extensions
|
|
|
|
Create `forge/api/systems.py`:
|
|
|
|
```python
|
|
from flask import Blueprint, request, jsonify
|
|
from forge.models import BuildJob, System
|
|
from forge.queue import build_queue
|
|
|
|
systems_bp = Blueprint('systems', __name__)
|
|
|
|
@systems_bp.route('/api/systems', methods=['GET'])
|
|
def list_systems():
|
|
"""List all available systems and variants"""
|
|
systems = System.query.all()
|
|
return jsonify({
|
|
'systems': [{
|
|
'name': s.name,
|
|
'display_name': s.display_name,
|
|
'description': s.description,
|
|
'variants': [v.to_dict() for v in s.variants]
|
|
} for s in systems]
|
|
})
|
|
|
|
@systems_bp.route('/api/builds', methods=['POST'])
|
|
def create_build():
|
|
"""Create a new build job"""
|
|
data = request.json
|
|
|
|
job = BuildJob(
|
|
system=data['system'],
|
|
variant=data.get('variant', 'base'),
|
|
architecture=data.get('architecture', 'x86_64'),
|
|
builder=data.get('builder', 'bootc-image-builder'),
|
|
formats=data.get('formats', ['iso', 'raw'])
|
|
)
|
|
|
|
build_queue.enqueue(job)
|
|
|
|
return jsonify({
|
|
'job_id': job.id,
|
|
'status': 'queued'
|
|
})
|
|
|
|
@systems_bp.route('/api/builds/<job_id>/status', methods=['GET'])
|
|
def build_status(job_id):
|
|
"""Get build job status"""
|
|
job = BuildJob.query.get_or_404(job_id)
|
|
|
|
return jsonify({
|
|
'job_id': job.id,
|
|
'status': job.status,
|
|
'created_at': job.created_at.isoformat(),
|
|
'completed_at': job.completed_at.isoformat() if job.completed_at else None,
|
|
'artifacts': [a.to_dict() for a in job.artifacts] if job.artifacts else []
|
|
})
|
|
```
|
|
|
|
## Step 14: User Migration Tools
|
|
|
|
### 14.1 Universal Blue System Switcher
|
|
|
|
Create `scripts/ublue-switch.sh`:
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
set -euo pipefail
|
|
|
|
show_help() {
|
|
cat << EOF
|
|
Universal Blue System Switcher
|
|
|
|
Usage: $0 [OPTIONS] TARGET_SYSTEM [VARIANT]
|
|
|
|
Switch between Universal Blue systems (bazzite, bluefin, aurora, ucore)
|
|
|
|
OPTIONS:
|
|
-h, --help Show this help
|
|
-r, --registry Custom registry (default: your-registry.com)
|
|
-f, --force Force switch without confirmation
|
|
-b, --backup Create backup before switching
|
|
|
|
EXAMPLES:
|
|
$0 bazzite # Switch to Bazzite (base variant)
|
|
$0 bluefin dx # Switch to Bluefin DX variant
|
|
$0 aurora nvidia # Switch to Aurora with NVIDIA drivers
|
|
$0 ucore minimal # Switch to uCore minimal variant
|
|
|
|
EOF
|
|
}
|
|
|
|
REGISTRY="your-registry.com"
|
|
FORCE=false
|
|
BACKUP=false
|
|
TARGET_SYSTEM=""
|
|
VARIANT="base"
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case $1 in
|
|
-h|--help)
|
|
show_help
|
|
exit 0
|
|
;;
|
|
-r|--registry)
|
|
REGISTRY="$2"
|
|
shift 2
|
|
;;
|
|
-f|--force)
|
|
FORCE=true
|
|
shift
|
|
;;
|
|
-b|--backup)
|
|
BACKUP=true
|
|
shift
|
|
;;
|
|
-*)
|
|
echo "Unknown option $1"
|
|
exit 1
|
|
;;
|
|
*)
|
|
if [ -z "$TARGET_SYSTEM" ]; then
|
|
TARGET_SYSTEM="$1"
|
|
else
|
|
VARIANT="$1"
|
|
fi
|
|
shift
|
|
;;
|
|
esac
|
|
done
|
|
|
|
if [ -z "$TARGET_SYSTEM" ]; then
|
|
echo "Error: TARGET_SYSTEM required"
|
|
show_help
|
|
exit 1
|
|
fi
|
|
|
|
# Validate target system
|
|
case "$TARGET_SYSTEM" in
|
|
bazzite|bluefin|aurora|ucore)
|
|
;;
|
|
*)
|
|
echo "Error: Invalid system '$TARGET_SYSTEM'"
|
|
echo "Valid systems: bazzite, bluefin, aurora, ucore"
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
CURRENT_SYSTEM=$(rpm-ostree status --json | jq -r '.deployments[0]."container-image-reference"' | cut -d'/' -f3 | cut -d':' -f1 2>/dev/null || echo "unknown")
|
|
TARGET_IMAGE="$REGISTRY/ublue-os/$TARGET_SYSTEM"
|
|
|
|
if [ "$VARIANT" != "base" ]; then
|
|
TARGET_IMAGE="$TARGET_IMAGE-$VARIANT"
|
|
fi
|
|
TARGET_IMAGE="$TARGET_IMAGE:latest"
|
|
|
|
echo "Current system: $CURRENT_SYSTEM"
|
|
echo "Target system: $TARGET_SYSTEM${VARIANT:+ ($VARIANT)}"
|
|
echo "Target image: $TARGET_IMAGE"
|
|
|
|
if [ "$FORCE" != true ]; then
|
|
echo
|
|
read -p "Continue with system switch? [y/N] " -n 1 -r
|
|
echo
|
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
echo "Aborted"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
# Create backup if requested
|
|
if [ "$BACKUP" = true ]; then
|
|
echo "Creating backup..."
|
|
sudo ostree admin pin 0
|
|
fi
|
|
|
|
# Perform the switch
|
|
echo "Switching to $TARGET_SYSTEM..."
|
|
sudo bootc switch "$TARGET_IMAGE"
|
|
|
|
echo
|
|
echo "System switch initiated. Reboot to complete the transition."
|
|
echo "After reboot, run 'rpm-ostree status' to verify the new system."
|
|
|
|
if [ "$BACKUP" = true ]; then
|
|
echo "Backup created. You can rollback with 'rpm-ostree rollback' if needed."
|
|
fi
|
|
```
|
|
|
|
### 14.2 Configuration Migration Tool
|
|
|
|
Create `scripts/migrate-config.sh`:
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
set -euo pipefail
|
|
|
|
SOURCE_SYSTEM="$1"
|
|
TARGET_SYSTEM="$2"
|
|
CONFIG_DIR="$HOME/.config/ublue-migration"
|
|
|
|
mkdir -p "$CONFIG_DIR"
|
|
|
|
echo "Migrating configuration from $SOURCE_SYSTEM to $TARGET_SYSTEM..."
|
|
|
|
# Export current Flatpaks
|
|
echo "Backing up Flatpaks..."
|
|
flatpak list --app --columns=application > "$CONFIG_DIR/flatpaks-user.txt"
|
|
flatpak list --app --system --columns=application > "$CONFIG_DIR/flatpaks-system.txt"
|
|
|
|
# Export dconf settings
|
|
echo "Backing up GNOME/KDE settings..."
|
|
dconf dump / > "$CONFIG_DIR/dconf-settings.txt"
|
|
|
|
# Export layered packages
|
|
echo "Backing up layered packages..."
|
|
rpm-ostree status --json | jq -r '.deployments[0]."requested-packages"[]?' > "$CONFIG_DIR/layered-packages.txt"
|
|
|
|
# System-specific migrations
|
|
case "$TARGET_SYSTEM" in
|
|
"bazzite")
|
|
echo "Preparing gaming-specific configuration..."
|
|
# Gaming controller configs, Steam settings, etc.
|
|
if [ -d "$HOME/.steam" ]; then
|
|
echo "Steam configuration found, will be preserved"
|
|
fi
|
|
;;
|
|
"bluefin")
|
|
echo "Preparing development environment..."
|
|
# Export distrobox containers
|
|
if command -v distrobox >/dev/null 2>&1; then
|
|
distrobox list | tail -n +2 > "$CONFIG_DIR/distroboxes.txt"
|
|
fi
|
|
;;
|
|
"aurora")
|
|
echo "Preparing KDE configuration..."
|
|
# KDE-specific settings
|
|
if [ -d "$HOME/.config/kde" ]; then
|
|
tar -czf "$CONFIG_DIR/kde-config.tar.gz" -C "$HOME/.config" kde
|
|
fi
|
|
;;
|
|
esac
|
|
|
|
# Create restoration script
|
|
cat > "$CONFIG_DIR/restore-config.sh" << EOF
|
|
#!/bin/bash
|
|
# Configuration restoration script for $TARGET_SYSTEM
|
|
|
|
echo "Restoring configuration for $TARGET_SYSTEM..."
|
|
|
|
# Restore Flatpaks
|
|
if [ -f "$CONFIG_DIR/flatpaks-user.txt" ]; then
|
|
while read -r app; do
|
|
flatpak install -y --user flathub "\$app" 2>/dev/null || true
|
|
done < "$CONFIG_DIR/flatpaks-user.txt"
|
|
fi
|
|
|
|
# Restore dconf settings (be careful with cross-desktop migrations)
|
|
if [ -f "$CONFIG_DIR/dconf-settings.txt" ] && command -v dconf >/dev/null 2>&1; then
|
|
echo "Restoring desktop settings..."
|
|
dconf load / < "$CONFIG_DIR/dconf-settings.txt"
|
|
fi
|
|
|
|
# Restore layered packages
|
|
if [ -f "$CONFIG_DIR/layered-packages.txt" ]; then
|
|
echo "Restoring layered packages..."
|
|
packages=\$(cat "$CONFIG_DIR/layered-packages.txt" | tr '\n' ' ')
|
|
if [ -n "\$packages" ]; then
|
|
rpm-ostree install \$packages
|
|
fi
|
|
fi
|
|
|
|
echo "Configuration restoration complete"
|
|
echo "Some applications may need to be reconfigured manually"
|
|
EOF
|
|
|
|
chmod +x "$CONFIG_DIR/restore-config.sh"
|
|
|
|
echo "Configuration backup complete"
|
|
echo "After switching systems, run: $CONFIG_DIR/restore-config.sh"
|
|
```
|
|
|
|
## Conclusion
|
|
|
|
This comprehensive guide provides a complete Universal Blue ecosystem for self-hosted infrastructure, including:
|
|
|
|
### Core Tools Covered:
|
|
- **bootc & bootupd**: Container-native OS management
|
|
- **bootc-image-builder**: Standard bootable image generation
|
|
- **osbuilder**: Advanced multi-architecture and cloud-optimized builds
|
|
- **rpm-ostree**: Package layering and system management
|
|
- **BlueBuild**: Declarative image building with recipe files
|
|
- **ujust**: System automation and user-friendly commands
|
|
- **forge**: On-premise Universal Blue infrastructure
|
|
- **startingpoint**: Template for custom image creation
|
|
- **upgrade-tools**: Safe system migration utilities
|
|
- **ublue-os packages**: Standardized package management
|
|
|
|
### Universal Blue Systems Supported:
|
|
- **Bazzite**: Gaming desktop and handheld optimization
|
|
- **Bluefin**: Developer workstation with containers and tools
|
|
- **Aurora**: KDE desktop environment variant
|
|
- **uCore**: Server/edge container platform
|
|
- **Custom Images**: Your own Universal Blue derivatives
|
|
|
|
### Key Capabilities:
|
|
1. **Multi-system builds** with parallel CI/CD pipelines
|
|
2. **Declarative configuration** using BlueBuild recipes
|
|
3. **Advanced customization** with osbuilder for cloud/edge deployments
|
|
4. **User-friendly management** through ujust commands
|
|
5. **Safe system migration** between Universal Blue variants
|
|
6. **Comprehensive testing** and validation pipelines
|
|
7. **On-premise infrastructure** with forge web interface
|
|
8. **Security and signing** with cosign and SBOMs
|
|
9. **Health monitoring** and automated maintenance
|
|
10. **Complete documentation** and user guides
|
|
|
|
This ecosystem provides enterprise-grade container-native operating system distribution capabilities while maintaining the user-friendly experience that makes Universal Blue systems popular for desktop, gaming, development, and server workloads.
|
|
|
|
The combination of all these tools creates a robust, maintainable, and scalable platform for delivering modern Linux distributions entirely on your own infrastructure. |