An immutable Ubuntu 24.04 container image with optional Kubernetes support (k3s or k0s) and secure supply chain practices. Multi-architecture builds with dynamic version resolution, vulnerability scanning, and provenance attestation.
- Container runtime (Docker, Podman, or similar)
- For Kubernetes variants: sufficient resources to run k3s/k0s
The image is published to ghcr.io/felegy/ubuntu-inmutable with variants:
Base image (no Kubernetes):
docker run -it ghcr.io/felegy/ubuntu-inmutable:latestWith k3s Kubernetes (minor version tags):
docker run -it ghcr.io/felegy/ubuntu-inmutable:k3s-v1.27
docker run -it ghcr.io/felegy/ubuntu-inmutable:k3s-v1.28
docker run -it ghcr.io/felegy/ubuntu-inmutable:k3s-v1.29With k0s Kubernetes:
docker run -it ghcr.io/felegy/ubuntu-inmutable:k0s-v1.27| Tag | Description |
|---|---|
latest |
Base Ubuntu 24.04 with default tools (open-vm-tools) |
k3s-v1.X |
Ubuntu with k3s lightweight Kubernetes (minor version only) |
k0s-v1.X |
Ubuntu with k0s lightweight Kubernetes (minor version only) |
dev |
Development build tag (local builds) |
- Base OS: Ubuntu 24.04
- Kairos Init: 0.7.0 (immutable OS bootstrap)
- Default User:
kairoswith passwordless sudo - Variant:
core(minimal footprint) - Extra Packages:
open-vm-tools(VM guest agent) - Additional Packages: Configurable via
--debsflag during build
Mount volumes and configure environment variables as needed:
docker run -it \
-v /var/lib/rancher:/var/lib/rancher \
-e KUBERNETES_SERVICE_HOST=k3s-master \
ghcr.io/felegy/ubuntu-inmutable:k3s-v1.29For persistent configuration, use Docker compose or container orchestration tools.
- Linux/macOS with Bash, or Windows with PowerShell
- Docker with Buildx (
docker buildx version) - .NET SDK 10.0+ (optional; build script bootstraps project-local installation)
- Trivy (optional locally; required in CI for vulnerability scanning)
Build without publishing to registry:
./build.sh ci --push falseThis produces a loadable image with tag ghcr.io/local/ubuntu-inmutable:dev.
Build with k3s v1.29 (latest 1.29.x release):
KUBERNETES_DISTRO=k3s KUBERNETES_VERSION=v1.29.1+k3s1 ./build.sh ci --push falseResolve k3s versions dynamically:
# Fetch latest 3 k3s releases and build matrix (local testing)
./build.sh print-context \
--kubernetes-distro k3s \
--skip-trivy-ignore falseThe build system supports fine-grained configuration via CLI flags:
-
--image ghcr.io/myregistry/ubuntu-inmutableContainer image name (default:ghcr.io/local/ubuntu-inmutable) -
--image-version 1.0.0Semantic version tag (default: git short SHA) -
--image-extra-tag custom-tagAdditional image tag suffix (e.g.,ubuntu-inmutable:custom-tag-dev) -
--base-image ubuntu:22.04Custom base image (default:ubuntu:24.04)
-
--version 0.3.2Kairos OS image version (required forcontainer-buildtarget) -
--kairos-init-version 0.8.0Kairos Init bootstrapper version (default:0.7.0) -
--default-user ubuntuDefault unprivileged user name (default:kairos) -
--variant immutableKairos variant type (default:core) -
--model genericKairos model selection (default:generic) -
--trusted-boot trueEnable Secure Boot and trusted boot measurement (default:false) -
--debs "git curl jq"Space-separated APT packages to install (default:open-vm-tools)
-
--kubernetes-distro k3sKubernetes provider:k3sork0s(optional) -
--kubernetes-version v1.29.1+k3s1Specific Kubernetes version (optional, overrides Containerfile default)
-
--push truePublish to registry and generate provenance/SBOM attestations (default:false) -
--skip-trivy-ignore falseUse.trivyignorefile to suppress known upstream vulnerabilities (default:false= use ignore file) -
--verbosity normalBuild output verbosity:quiet,minimal,normal,detailed,diagnostic(default:normal)
./build.sh ci --push falseRuns: restore → verify-tools → print-context → container-build → scan → publish
restore– Install project dotnet tools from manifestverify-tools– Check Docker/Trivy availabilityprint-context– Display resolved build configurationcontainer-build– Build and load image with Buildxscan– Run Trivy HIGH/CRITICAL vulnerability scanpublish– Push image and attestations to registry (requires--push true)
All build flags support environment variable fallback:
export KAIROS_VERSION=0.3.1
export KUBERNETES_DISTRO=k3s
export KUBERNETES_VERSION=v1.29.1+k3s1
export SKIP_TRIVY_IGNORE=true
export BUILD_VERBOSITY=normal
./build.sh ci --push falseIn CI, KAIROS_VERSION is resolved from the latest repository tag (for example v0.3.1 becomes 0.3.1) with fallback 0.1 when no tags exist.
| Variable | Flag | Default |
|---|---|---|
KAIROS_VERSION |
--version |
(required) |
KAIROS_INIT_VERSION |
--kairos-init-version |
0.7.0 |
KAIROS_DEFAULT_USER |
--default-user |
kairos |
KAIROS_VARIANT |
--variant |
core |
KAIROS_MODEL |
--model |
generic |
KAIROS_TRUSTED_BOOT |
--trusted-boot |
false |
KAIROS_DEBS |
--debs |
open-vm-tools |
BASE_IMAGE |
--base-image |
ubuntu:24.04 |
KUBERNETES_DISTRO |
--kubernetes-distro |
(none) |
KUBERNETES_VERSION |
--kubernetes-version |
(none) |
IMAGE_EXTRA_TAG |
--image-extra-tag |
(none) |
BUILD_VERBOSITY |
--verbosity |
normal |
IS_PRIMARY_TAG_TARGET |
(CI matrix env) | false |
SKIP_TRIVY_IGNORE |
--skip-trivy-ignore |
false |
For simple one-off builds without orchestration:
docker build \
-f Containerfile \
--build-arg BASE_IMAGE=ubuntu:24.04 \
--build-arg VERSION=0.3.1 \
--build-arg KUBERNETES_DISTRO=k3s \
--build-arg KUBERNETES_VERSION=v1.29.1+k3s1 \
-t local/ubuntu-inmutable:k3s-v1.29 \
.The workflow automatically:
- Validates code – EditorConfig compliance and ShellCheck linting
- Resolves
KAIROS_VERSION– Reads latest repository git tag and normalizes version - Resolves k3s versions – Fetches latest stable k3s releases via GitHub API
- Generates matrix – 1
isobaseline + 3 k3s variants with minor-version tags - Marks primary matrix entry – Newest k3s entry gets
latestandsha-<short>ownership - Builds containers – Parallel builds using Bullseye orchestration
- Scans security – Trivy HIGH/CRITICAL vulnerability detection
- Attests supply chain – SBOM and provenance generation
- Publishes – Push to ghcr.io with deterministic tagging
Tag behavior in CI push builds:
latestandsha-<short>are published only by the newest k3s matrix entry.- Matrix-specific tags (
iso,k3s-vX.Y) are published by their corresponding entries.
Release behavior:
- On
release.published, GitHub Actions builds an offline ISO fromghcr.io/<repo>:isoand uploads ISO + checksum artifacts to the release assets.
Workflow triggers:
- Push to
main - Manual dispatch via
workflow_dispatch release.publishedfor ISO artifact generation and upload
The .trivyignore file temporarily suppresses known upstream vulnerabilities (e.g., CVE-2026-25679 in Go stdlib). For strict scanning without suppressions:
./build.sh ci --push false --skip-trivy-ignore trueSee docs/ci-cd.md for tracking and remediation details.
The build.csx C# script uses Bullseye for task orchestration:
- Composable targets with dependency management
- Consistent exit codes for CI integration
- Minimal runtime dependencies (no GNU Make or shell scripting)
Platform-specific launchers bootstrap a project-local .NET SDK:
build.sh– Bash (Linux/macOS)build.ps1– PowerShell (Windows)build.cmd– CMD (Windows legacy)
Use launchers if dotnet is not in $PATH; otherwise call dotnet script build.csx directly.
Multi-stage Dockerfile:
- Base stage – Ubuntu 24.04 + Kairos Init
- Optional Kubernetes – k3s or k0s bootstrap (conditional)
- Custom packages – APT install from
DEBSbuild arg - Metadata – OCI image labels (created, revision, version)
- Planning prompts: .github/prompts/
- Workspace conventions: .github/copilot-instructions.md
- CI/CD details: docs/ci-cd.md
- EditorConfig compliance: Strict 2-space YAML, 4-space Markdown indentation
- Commit format:
<symbol> <TYPE>: <summary>(e.g.,+ ADD: new feature)