This commit is contained in:
iceBear67
2026-06-05 16:42:56 +08:00
commit 87e76877ca
23 changed files with 662 additions and 0 deletions

26
image/.gitignore vendored Normal file
View File

@@ -0,0 +1,26 @@
# Build artifacts
*.qcow2
*.raw
*.img
# Extracted kernel / initramfs
*-vmlinuz
*-initramfs
*-boot/
# Downloaded tool
alpine-make-vm-image
# Generated GPG keys (secrets)
overlay/root/gpg-key.asc
overlay/root/gpg-pubkey.asc
# Build marker
.gpg-done
# Editor / OS
.DS_Store
*.swp
*.swo
*~
.reasonix/**

72
image/Makefile Normal file
View File

@@ -0,0 +1,72 @@
# Alpine VM Image Builder
# ------------------------
# Builds a bootable Alpine Linux disk image for Cloud Hypervisor direct boot.
#
# Usage:
# make build — generate GPG key + build qcow2 image
# make build-raw — build raw image (for Cloud Hypervisor direct boot)
# make extract-kernel — extract kernel + initramfs from image
# make clean — remove build artifacts
#
# Configurable variables (override on command line):
# IMAGE_SIZE Size of the disk image (default: 4G)
# ALPINE_BRANCH Alpine release branch (default: latest-stable)
# KERNEL_FLAVOR Kernel variant (default: virt)
# ALPINE_MIRROR APK mirror (default: http://dl-cdn.alpinelinux.org/alpine)
SHELL := /bin/sh
# --- configurable ----------------------------------------------------
IMAGE_NAME = alpine-vm
IMAGE_SIZE ?= 4G
IMAGE_FORMAT = raw
ALPINE_BRANCH ?= latest-stable
KERNEL_FLAVOR ?= virt
#INITFS_FEATURES ?= kms scsi virtio
IMAGE_FILE = vm.$(IMAGE_FORMAT)
SCRIPT_DIR = $(dir $(realpath $(lastword $(MAKEFILE_LIST))))
OVERLAY_DIR = $(SCRIPT_DIR)/overlay
CONFIGURE_SH = $(SCRIPT_DIR)/configure.sh
build:
@echo ">>> Building $(IMAGE_FILE) ..."
@test -f $(OVERLAY_DIR)/root/gpg-key.asc || { \
echo "ERROR: GPG key not found. Generate key first" >&2; \
exit 1; \
}
$(MAKE_VM_IMAGE) \
--branch $(ALPINE_BRANCH) \
--image-format $(IMAGE_FORMAT) \
--image-size $(IMAGE_SIZE) \
--kernel-flavor $(KERNEL_FLAVOR) \
--serial-console \
--fs-skel-dir $(OVERLAY_DIR) \
--fs-skel-chown root:root \
--script-chroot \
--packages "python3 py3-yaml py3-pydantic git curl gnupg docker docker-cli-buildx docker-cli-compose" \
$(IMAGE_FILE) \
$(CONFIGURE_SH)
@echo ">>> Image built: $(IMAGE_FILE)"
@ls -lh $(IMAGE_FILE)
# Raw image (best for Cloud Hypervisor)
build-raw:
$(MAKE) build IMAGE_FORMAT=raw
# --- kernel extraction -----------------------------------------------
extract-kernel: $(IMAGE_FILE)
@echo ">>> Extracting kernel and initramfs from $(IMAGE_FILE) ..."
@which guestmount >/dev/null 2>&1 || { \
echo "ERROR: guestmount (libguestfs) required. Install: apk add libguestfs" >&2; \
exit 1; \
}
@mkdir -p $(IMAGE_NAME)-boot
guestmount -a $(IMAGE_FILE) -m /dev/sda --ro $(IMAGE_NAME)-boot
cp $(IMAGE_NAME)-boot/boot/vmlinuz-$(KERNEL_FLAVOR) vmlinuz
cp $(IMAGE_NAME)-boot/boot/initramfs-$(KERNEL_FLAVOR) initramfs
guestunmount $(IMAGE_NAME)-boot
rmdir $(IMAGE_NAME)-boot
.PHONY: build build-raw build-no-gpg extract-kernel gpg-key gpg-fingerprint

57
image/configure.sh Executable file
View File

@@ -0,0 +1,57 @@
#!/bin/sh
# configure.sh — runs inside chroot after base install and overlay copy.
# Invoked via alpine-make-vm-image --script-chroot.
set -eu
_step_counter=0
step() {
_step_counter=$(( _step_counter + 1 ))
printf '\n\033[1;36m%d) %s\033[0m\n' $_step_counter "$@" >&2
}
uname -a
step 'Set timezone to UTC'
setup-timezone -z UTC
step 'Set up networking'
# The interfaces file was placed by --fs-skel-dir; link init.d scripts.
ln -sf networking /etc/init.d/net.lo
ln -sf networking /etc/init.d/net.eth0
step 'Adjust rc.conf'
sed -Ei \
-e 's/^[# ](rc_depend_strict)=.*/\1=NO/' \
-e 's/^[# ](rc_logger)=.*/\1=YES/' \
-e 's/^[# ](unicode)=.*/\1=YES/' \
/etc/rc.conf
step 'Enable base services'
rc-update add net.lo boot
rc-update add net.eth0 default
rc-update add acpid default
rc-update add docker default
rc-update add cronie default
step 'Import GPG key for root'
GPG_KEY_FILE="/root/gpg-key.asc"
if [ -f "$GPG_KEY_FILE" ]; then
echo "Found GPG key file: $GPG_KEY_FILE"
gpg --batch --import "$GPG_KEY_FILE"
# Mark the imported key as ultimately trusted (non-interactive)
fingerprint=$(gpg --batch --with-colons --fingerprint \
| grep '^fpr:' | head -1 | cut -d: -f10)
if [ -n "$fingerprint" ]; then
echo "$fingerprint:6:" | gpg --batch --import-ownertrust
echo " * GPG key trusted: $fingerprint"
fi
rm -f "$GPG_KEY_FILE"
else
echo "WARNING: GPG key file not found at $GPG_KEY_FILE — skipping import" >&2
fi
step 'Clean up APK cache'
rm -rf /var/cache/apk/* || true
echo ''
echo '=== Configure script completed ==='

16
image/overlay/daemon/update.sh Executable file
View File

@@ -0,0 +1,16 @@
#!/bin/sh
mkdir -p /app
cd /app
rm -rf ./template ./snapshot
mkdir /app/template /app/snapshot
set -euo pipefail
git clone -b _REVISION_ _REPO_ template
python3 /daemon/orchestrate.py \
--root /app/template \
--network cloud \
--volume-parent /data/volumes \
--snapshot-root /app/snapshot

View File

@@ -0,0 +1,2 @@
# This directory is the virtiofs mount point for host-shared data.
# Do not store critical data here before the virtiofs share is mounted.

View File

@@ -0,0 +1,3 @@
interface "eth0" {
supersede routers GATEWAY_ADDRESS;
}

View File

@@ -0,0 +1,9 @@
{
"data-root": "/data/docker",
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
},
"storage-driver": "overlay2"
}

5
image/overlay/etc/fstab Normal file
View File

@@ -0,0 +1,5 @@
# /etc/fstab: static file system information
#
# <file system> <mount point> <type> <options> <dump> <pass>
/dev/root / ext4 rw,noatime 0 1
data /data virtiofs rw,noatime,_netdev 0 0

View File

@@ -0,0 +1,7 @@
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet manual
post-up dhclient -v eth0
pre-down dhclient -x eth0

View File

@@ -0,0 +1,2 @@
# min hour day month weekday command
*/15 * * * * /usr/bin/sh /daemon/update.sh

10
image/packages Normal file
View File

@@ -0,0 +1,10 @@
python3
py3-yaml
py3-pydantic
git
curl
gnupg
docker
docker-cli-buildx
docker-cli-compose
cronie

2
image/repositories Normal file
View File

@@ -0,0 +1,2 @@
https://dl-cdn.alpinelinux.org/alpine/latest-stable/main
https://dl-cdn.alpinelinux.org/alpine/latest-stable/community