feat: add distribution and fleet management — CI/CD, OCI, metrics, ARM64 (Phase 5)
- Gitea Actions CI pipeline: Go tests, build, shellcheck on push/PR - Gitea Actions release pipeline: full build + artifact upload on version tags - OCI container image builder for registry-based OS distribution - Zero-dependency Prometheus metrics endpoint (kubesolo_os_info, boot, memory, update status) with 10 tests - USB provisioning tool for air-gapped deployments with cloud-init injection - ARM64 cross-compilation support (TARGET_ARCH env var + build-cross.sh) - Updated build scripts to accept TARGET_ARCH for both amd64 and arm64 - New Makefile targets: oci-image, build-cross Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
155
build/scripts/create-oci-image.sh
Executable file
155
build/scripts/create-oci-image.sh
Executable file
@@ -0,0 +1,155 @@
|
||||
#!/bin/bash
|
||||
# create-oci-image.sh — Package KubeSolo OS as an OCI container image
|
||||
#
|
||||
# Creates an OCI image containing the kernel and initramfs, suitable for
|
||||
# distribution via container registries (Docker Hub, GHCR, Quay, etc.).
|
||||
#
|
||||
# The OCI image is a minimal scratch-based image containing:
|
||||
# /vmlinuz — kernel
|
||||
# /kubesolo-os.gz — initramfs
|
||||
# /version — version string
|
||||
# /metadata.json — build metadata
|
||||
#
|
||||
# Usage:
|
||||
# build/scripts/create-oci-image.sh [--registry REGISTRY] [--push]
|
||||
#
|
||||
# Examples:
|
||||
# build/scripts/create-oci-image.sh
|
||||
# build/scripts/create-oci-image.sh --registry ghcr.io/portainer --push
|
||||
# build/scripts/create-oci-image.sh --registry docker.io/portainer --push
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||
VERSION="$(cat "$PROJECT_ROOT/VERSION")"
|
||||
OUTPUT_DIR="$PROJECT_ROOT/output"
|
||||
|
||||
# Defaults
|
||||
REGISTRY=""
|
||||
IMAGE_NAME="kubesolo-os"
|
||||
PUSH=false
|
||||
ARCH="${ARCH:-amd64}"
|
||||
|
||||
# Parse args
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--registry) REGISTRY="$2"; shift 2 ;;
|
||||
--push) PUSH=true; shift ;;
|
||||
--arch) ARCH="$2"; shift 2 ;;
|
||||
*) echo "Unknown option: $1" >&2; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Build full image tag
|
||||
if [ -n "$REGISTRY" ]; then
|
||||
FULL_IMAGE="${REGISTRY}/${IMAGE_NAME}:${VERSION}"
|
||||
LATEST_TAG="${REGISTRY}/${IMAGE_NAME}:latest"
|
||||
else
|
||||
FULL_IMAGE="${IMAGE_NAME}:${VERSION}"
|
||||
LATEST_TAG="${IMAGE_NAME}:latest"
|
||||
fi
|
||||
|
||||
echo "==> Building OCI image: $FULL_IMAGE"
|
||||
|
||||
# Check for required files
|
||||
VMLINUZ="$OUTPUT_DIR/vmlinuz"
|
||||
INITRAMFS="$OUTPUT_DIR/kubesolo-os.gz"
|
||||
|
||||
# If individual files don't exist, try to extract from ISO
|
||||
if [ ! -f "$VMLINUZ" ] || [ ! -f "$INITRAMFS" ]; then
|
||||
ISO="$OUTPUT_DIR/kubesolo-os-${VERSION}.iso"
|
||||
if [ -f "$ISO" ]; then
|
||||
echo " Extracting from ISO..."
|
||||
TMPDIR=$(mktemp -d)
|
||||
trap "rm -rf $TMPDIR" EXIT
|
||||
|
||||
# Extract kernel and initramfs from ISO
|
||||
xorriso -osirrox on -indev "$ISO" -extract /boot/vmlinuz "$TMPDIR/vmlinuz" 2>/dev/null || \
|
||||
bsdtar -xf "$ISO" -C "$TMPDIR" boot/vmlinuz boot/kubesolo-os.gz 2>/dev/null || true
|
||||
|
||||
# Try common paths
|
||||
for kpath in "$TMPDIR/boot/vmlinuz" "$TMPDIR/vmlinuz"; do
|
||||
[ -f "$kpath" ] && VMLINUZ="$kpath" && break
|
||||
done
|
||||
for ipath in "$TMPDIR/boot/kubesolo-os.gz" "$TMPDIR/kubesolo-os.gz"; do
|
||||
[ -f "$ipath" ] && INITRAMFS="$ipath" && break
|
||||
done
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -f "$VMLINUZ" ] || [ ! -f "$INITRAMFS" ]; then
|
||||
echo "ERROR: Required files not found:"
|
||||
echo " vmlinuz: $VMLINUZ"
|
||||
echo " kubesolo-os.gz: $INITRAMFS"
|
||||
echo ""
|
||||
echo "Run 'make iso' or 'make initramfs' first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create build context
|
||||
OCI_BUILD="$OUTPUT_DIR/oci-build"
|
||||
rm -rf "$OCI_BUILD"
|
||||
mkdir -p "$OCI_BUILD"
|
||||
|
||||
cp "$VMLINUZ" "$OCI_BUILD/vmlinuz"
|
||||
cp "$INITRAMFS" "$OCI_BUILD/kubesolo-os.gz"
|
||||
echo "$VERSION" > "$OCI_BUILD/version"
|
||||
|
||||
# Create metadata
|
||||
cat > "$OCI_BUILD/metadata.json" << EOF
|
||||
{
|
||||
"name": "KubeSolo OS",
|
||||
"version": "$VERSION",
|
||||
"arch": "$ARCH",
|
||||
"build_date": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
|
||||
"vmlinuz_sha256": "$(sha256sum "$OCI_BUILD/vmlinuz" | cut -d' ' -f1)",
|
||||
"initramfs_sha256": "$(sha256sum "$OCI_BUILD/kubesolo-os.gz" | cut -d' ' -f1)"
|
||||
}
|
||||
EOF
|
||||
|
||||
# Create Dockerfile
|
||||
cat > "$OCI_BUILD/Dockerfile" << 'DOCKERFILE'
|
||||
FROM scratch
|
||||
LABEL org.opencontainers.image.title="KubeSolo OS"
|
||||
LABEL org.opencontainers.image.description="Immutable Kubernetes OS for edge/IoT"
|
||||
LABEL org.opencontainers.image.vendor="Portainer"
|
||||
LABEL org.opencontainers.image.source="https://github.com/portainer/kubesolo-os"
|
||||
COPY vmlinuz /vmlinuz
|
||||
COPY kubesolo-os.gz /kubesolo-os.gz
|
||||
COPY version /version
|
||||
COPY metadata.json /metadata.json
|
||||
DOCKERFILE
|
||||
|
||||
# Build OCI image
|
||||
echo " Building..."
|
||||
docker build \
|
||||
--platform "linux/${ARCH}" \
|
||||
-t "$FULL_IMAGE" \
|
||||
-t "$LATEST_TAG" \
|
||||
-f "$OCI_BUILD/Dockerfile" \
|
||||
"$OCI_BUILD"
|
||||
|
||||
echo " Built: $FULL_IMAGE"
|
||||
echo " Size: $(docker image inspect "$FULL_IMAGE" --format='{{.Size}}' | awk '{printf "%.1f MB", $1/1024/1024}')"
|
||||
|
||||
# Push if requested
|
||||
if [ "$PUSH" = true ]; then
|
||||
echo " Pushing to registry..."
|
||||
docker push "$FULL_IMAGE"
|
||||
docker push "$LATEST_TAG"
|
||||
echo " Pushed: $FULL_IMAGE"
|
||||
echo " Pushed: $LATEST_TAG"
|
||||
fi
|
||||
|
||||
# Cleanup
|
||||
rm -rf "$OCI_BUILD"
|
||||
|
||||
echo ""
|
||||
echo "==> OCI image ready: $FULL_IMAGE"
|
||||
echo ""
|
||||
echo "Usage:"
|
||||
echo " # Pull and extract on target machine:"
|
||||
echo " docker create --name kubesolo-extract $FULL_IMAGE"
|
||||
echo " docker cp kubesolo-extract:/vmlinuz ./vmlinuz"
|
||||
echo " docker cp kubesolo-extract:/kubesolo-os.gz ./kubesolo-os.gz"
|
||||
echo " docker rm kubesolo-extract"
|
||||
Reference in New Issue
Block a user