This commit is contained in:
bwees
2025-08-13 12:01:16 -05:00
parent a5aed7d76f
commit 0598aa7610
23 changed files with 1571 additions and 31 deletions
+4 -3
View File
@@ -1,3 +1,4 @@
overlay/usr/app/images/*.tar
immich.apkovl.tar.gz
mkimage.sh
overlay/var/lib/docker
build/
out/
.overlay-build/
+14 -25
View File
@@ -1,32 +1,21 @@
Steps to build:
# Immich-retro
1. Fire up a local alpine image on Docker:
## How to build
Run the following from the root of this repository
```bash
docker run --rm -it -v "$(pwd)":/home alpine sh
docker run --rm -it -v "$(pwd)":/home --privileged alpine sh ./home/build.sh
```
2. Inside the container, run
The built image will be placed in `out/`
```bash
apk add alpine-sdk abuild
```
### A couple of notes:
3. Run
```bash
tar --numeric-owner --owner=0 --group=0 -cf root-overlay.tar -C overlay .
```
3. Run
```bash
./mkimage.sh --tag immich \
--outdir out \
--arch x86_64 \
--repository https://dl-cdn.alpinelinux.org/alpine/latest-stable/main \
--profile immich
```
4.
- The entirety of the operating system runs from RAM. No configuration, assets, or settings will be persisted on reboot of the machine. DO NOT use this as your main Immich instance.
- All assets are stored in RAM so you may quickly run out of "storage" if your machine has less than 16GB of RAM.
- If booting from the DVD, the boot process **will be slow**. You may see "0%" for a prolonged period of time during boot. _Be patient!_. This part of the boot process requires reading the entire DVD and loading it into RAM.
- Minimum system requirements:
- 2 core x86 processor
- 8GB of RAM, 16GB recommended
- No storage drive needed!
Executable
+15
View File
@@ -0,0 +1,15 @@
#!/bin/sh
apk add alpine-sdk alpine-conf xorriso squashfs-tools grub grub-efi doas docker openrc fuse-overlayfs mtools dosfstools grub-efi
echo "permit persist root" > /etc/doas.d/doas.conf
echo "permit nopass root" >> /etc/doas.d/doas.conf
addgroup build docker
# su - build -c "
abuild-keygen -i -a -n
apk update
cd /home
./scripts/mkimage.sh --tag immich --outdir out --arch x86_64 --repository https://dl-cdn.alpinelinux.org/alpine/latest-stable/main --repository https://dl-cdn.alpinelinux.org/alpine/latest-stable/community --profile immich
+6
View File
@@ -0,0 +1,6 @@
docker run -d --privileged \
--name dind-test \
-v "$(pwd)":/home \
-v "$(pwd)/overlay/var/lib/docker":/var/lib/docker \
-e DOCKER_TLS_CERTDIR= \
docker:dind
+22
View File
@@ -0,0 +1,22 @@
# You can find documentation for all the supported env variables at https://immich.app/docs/install/environment-variables
# The location where your uploaded files are stored
UPLOAD_LOCATION=./library
# The location where your database files are stored. Network shares are not supported for the database
DB_DATA_LOCATION=./postgres
# To set a timezone, uncomment the next line and change Etc/UTC to a TZ identifier from this list: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List
# TZ=Etc/UTC
# The Immich version to use. You can pin this to a specific version like "v1.71.0"
IMMICH_VERSION=release
# Connection secret for postgres. You should change it to a random password
# Please use only the characters `A-Za-z0-9`, without special characters or spaces
DB_PASSWORD=postgres
# The values below this line do not need to be changed
###################################################################################
DB_USERNAME=postgres
DB_DATABASE_NAME=immich
+74
View File
@@ -0,0 +1,74 @@
#
# WARNING: To install Immich, follow our guide: https://immich.app/docs/install/docker-compose
#
# Make sure to use the docker-compose.yml of the current release:
#
# https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml
#
# The compose file on main may not be compatible with the latest release.
name: immich
services:
immich-server:
container_name: immich_server
image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release}
# extends:
# file: hwaccel.transcoding.yml
# service: cpu # set to one of [nvenc, quicksync, rkmpp, vaapi, vaapi-wsl] for accelerated transcoding
volumes:
# Do not edit the next line. If you want to change the media storage location on your system, edit the value of UPLOAD_LOCATION in the .env file
- ${UPLOAD_LOCATION}:/data
- /etc/localtime:/etc/localtime:ro
env_file:
- .env
ports:
- "2283:2283"
depends_on:
- redis
- database
restart: always
healthcheck:
disable: false
immich-machine-learning:
container_name: immich_machine_learning
# For hardware acceleration, add one of -[armnn, cuda, rocm, openvino, rknn] to the image tag.
# Example tag: ${IMMICH_VERSION:-release}-cuda
image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release}
# extends: # uncomment this section for hardware acceleration - see https://immich.app/docs/features/ml-hardware-acceleration
# file: hwaccel.ml.yml
# service: cpu # set to one of [armnn, cuda, rocm, openvino, openvino-wsl, rknn] for accelerated inference - use the `-wsl` version for WSL2 where applicable
volumes:
- model-cache:/cache
env_file:
- .env
restart: always
healthcheck:
disable: false
redis:
container_name: immich_redis
image: docker.io/valkey/valkey:8-bookworm@sha256:facc1d2c3462975c34e10fccb167bfa92b0e0dbd992fc282c29a61c3243afb11
healthcheck:
test: redis-cli ping || exit 1
restart: always
database:
container_name: immich_postgres
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0@sha256:32324a2f41df5de9efe1af166b7008c3f55646f8d0e00d9550c16c9822366b4a
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_USER: ${DB_USERNAME}
POSTGRES_DB: ${DB_DATABASE_NAME}
POSTGRES_INITDB_ARGS: "--data-checksums"
# Uncomment the DB_STORAGE_TYPE: 'HDD' var if your database isn't stored on SSDs
# DB_STORAGE_TYPE: 'HDD'
volumes:
# Do not edit the next line. If you want to change the database storage location on your system, edit the value of DB_DATA_LOCATION in the .env file
- ${DB_DATA_LOCATION}:/var/lib/postgresql/data
shm_size: 128mb
restart: always
volumes:
model-cache:
View File
+3
View File
@@ -0,0 +1,3 @@
The following folder contains the contents of the `scripts/` folder from https://gitlab.alpinelinux.org/alpine/aports.git
`mkimage.immich.sh` defines the configuration for the Immich custom ISO
+173
View File
@@ -0,0 +1,173 @@
#!/bin/sh
set -e
abuild_opts="-r"
if [ "$1" = "-k" ] || [ "$1" = "--keep" ]; then
abuild_opts="$abuild_opts -k"
shift
fi
TARGET_ARCH="$1"
SUDO_APK=abuild-apk
shift
# optional cross build packages
#: ${KERNEL_PKG=linux-firmware linux-lts}
#: ${COMPILER_PKG=libffi brotli libev c-ares cunit nghttp2 libidn2 libunistring libpsl curl libssh2 libxml2 llvm15 community/ghc llvm20 rust community/go}
# FIXME: Maybe subdivide into ghc, rust, and go stuff
: ${MKINITFS=libcap-ng ncurses readline sqlite util-linux libaio lvm2 popt xz json-c argon2 cryptsetup kmod lddtree mkinitfs pax-utils}
#: ${OPENSSH=openssh}
if [ -z "$TARGET_ARCH" ]; then
program=$(basename $0)
cat <<EOF
usage: $program TARGET_ARCH
This script creates a local cross-compiler, and uses it to
cross-compile an Alpine Linux base system for new architecture.
Steps for introducing new architecture include:
- adding the compiler triplet and arch type to abuild
- adjusting build rules for packages that are arch aware:
gcc, openssl, linux-headers, musl
- create new kernel config for linux-lts
- optionally reserve an architecture name in apk-tools
After these steps the initial cross-build can be completed
by running this with the target arch as parameter, e.g.:
./$program aarch64
The cross-compiler generated by this script is not intended
nor supported for any use other than building the base system
and other packages in the bootstrap path.
EOF
return 1
fi
# get abuild configurables
sharedir=${ABUILD_SHAREDIR:-/usr/share/abuild}
[ -e "$sharedir"/functions.sh ] || (echo "abuild not found" ; exit 1)
CBUILDROOT="$(CTARGET=$TARGET_ARCH . "$sharedir"/functions.sh ; echo $CBUILDROOT)"
. "$sharedir"/functions.sh
[ -z "$CBUILD_ARCH" ] && die "abuild is too old (use 2.29.0 or later)"
[ -z "$CBUILDROOT" ] && die "CBUILDROOT not set for $TARGET_ARCH"
export CBUILD
# deduce aports directory
[ -z "$APORTS" ] && APORTS=$(realpath $(dirname $0)/../)
[ -e "$APORTS/main/build-base" ] || die "Unable to deduce aports base checkout"
apkbuildname() {
local repo="${1%%/*}"
local pkg="${1##*/}"
[ "$repo" = "$1" ] && repo="main"
echo $APORTS/$repo/$pkg/APKBUILD
}
msg() {
[ -n "$quiet" ] && return 0
local prompt="$GREEN>>>${NORMAL}"
local name="${BLUE}bootstrap-${TARGET_ARCH}${NORMAL}"
printf "${prompt} ${name}: %s\n" "$1" >&2
}
if [ ! -d "$CBUILDROOT" ]; then
msg "Creating sysroot in $CBUILDROOT"
mkdir -p "$CBUILDROOT/etc/apk/keys"
# /etc/apk/keys and ~/.abuild/ can contain files with the same names.
# if that is the case, cp will abort copying and fail. Then on the next
# run of the bootstrap script, 1) the keys are not in the sysroot and
# 2) the apk database is not initialized the sysroot
# Thus it's unusable at that point and needs to be deleted manually.
cp -a /etc/apk/keys/* "$CBUILDROOT/etc/apk/keys"
cp -a ~/.abuild/*.pub "$CBUILDROOT/etc/apk/keys"
${SUDO_APK} add --quiet --initdb --arch $TARGET_ARCH --root $CBUILDROOT
fi
msg "Building cross-compiler"
# Build and install cross binutils (--with-sysroot)
CTARGET=$TARGET_ARCH BOOTSTRAP=nobase APKBUILD=$(apkbuildname binutils) abuild $abuild_opts
if ! CHOST=$TARGET_ARCH BOOTSTRAP=nolibc APKBUILD=$(apkbuildname musl) abuild up2date 2>/dev/null; then
# C-library headers for target
CHOST=$TARGET_ARCH BOOTSTRAP=nocc APKBUILD=$(apkbuildname musl) abuild $abuild_opts
# Minimal cross GCC
EXTRADEPENDS_HOST="musl-dev" \
CTARGET=$TARGET_ARCH BOOTSTRAP=nolibc APKBUILD=$(apkbuildname gcc) abuild $abuild_opts
# Cross build bootstrap C-library for the target
EXTRADEPENDS_BUILD="gcc-pass2-$TARGET_ARCH" \
CHOST=$TARGET_ARCH BOOTSTRAP=nolibc APKBUILD=$(apkbuildname musl) abuild $abuild_opts
fi
# Build libucontext without docs and pkgconfig file as a dependency for gcc-gdc
EXTRADEPENDS_BUILD="gcc-pass2-$TARGET_ARCH" \
EXTRADEPENDS_TARGET="musl musl-dev" \
CHOST=$TARGET_ARCH BOOTSTRAP=nobase APKBUILD=$(apkbuildname libucontext) abuild $abuild_opts
# Full cross GCC
EXTRADEPENDS_TARGET="musl musl-dev libucontext-dev" \
CTARGET=$TARGET_ARCH BOOTSTRAP=nobase APKBUILD=$(apkbuildname gcc) abuild $abuild_opts
# Cross build-base
CTARGET=$TARGET_ARCH BOOTSTRAP=nobase APKBUILD=$(apkbuildname build-base) abuild $abuild_opts
msg "Cross building base system"
# Implicit dependencies for early targets
EXTRADEPENDS_TARGET="libgcc libstdc++ musl-dev"
# On a few architectures like riscv64 we need to account for
# gcc requiring -ltomic to be set explicitly if a C[++]11 program
# uses atomics (e.g. #include <atomic>):
# https://github.com/riscv/riscv-gnu-toolchain/issues/183#issuecomment-253721765
# The reason gcc itself is needed is because .so is in that package,
# not in libatomic.
if [ "$TARGET_ARCH" = "riscv64" ]; then
NEEDS_LIBATOMIC="yes"
fi
if [ $# -eq 0 ]; then
set -- fortify-headers linux-headers musl pkgconf zlib \
openssl ca-certificates libmd \
gmp mpfr4 mpc1 isl26 libucontext zstd binutils gcc \
bsd-compat-headers libbsd busybox make \
apk-tools file \
libcap openrc alpine-conf alpine-baselayout alpine-keys alpine-base patch build-base \
attr acl fakeroot tar \
lzip abuild \
$OPENSSH \
$MKINITFS \
$COMPILER_PKG \
$KERNEL_PKG
fi
for PKG; do
if [ "$NEEDS_LIBATOMIC" = "yes" ]; then
EXTRADEPENDS_BUILD="libatomic gcc-$TARGET_ARCH g++-$TARGET_ARCH"
fi
EXTRADEPENDS_TARGET="$EXTRADEPENDS_TARGET" EXTRADEPENDS_BUILD="$EXTRADEPENDS_BUILD" \
CHOST=$TARGET_ARCH BOOTSTRAP=bootimage APKBUILD=$(apkbuildname $PKG) abuild $abuild_opts
case "$PKG" in
fortify-headers)
# Additional implicit dependencies once built
EXTRADEPENDS_TARGET="$EXTRADEPENDS_TARGET $PKG"
;;
gcc)
if [ "$NEEDS_LIBATOMIC" = "yes" ]; then
EXTRADEPENDS_TARGET="libatomic gcc $EXTRADEPENDS_TARGET"
fi
;;
build-base)
# After build-base, that alone is sufficient dependency in the target
EXTRADEPENDS_TARGET="busybox $PKG"
;;
esac
done
+66
View File
@@ -0,0 +1,66 @@
#!/bin/sh -e
HOSTNAME="$1"
if [ -z "$HOSTNAME" ]; then
echo "usage: $0 hostname"
exit 1
fi
cleanup() {
rm -rf "$tmp"
}
makefile() {
OWNER="$1"
PERMS="$2"
FILENAME="$3"
cat > "$FILENAME"
chown "$OWNER" "$FILENAME"
chmod "$PERMS" "$FILENAME"
}
rc_add() {
mkdir -p "$tmp"/etc/runlevels/"$2"
ln -sf /etc/init.d/"$1" "$tmp"/etc/runlevels/"$2"/"$1"
}
tmp="$(mktemp -d)"
trap cleanup EXIT
mkdir -p "$tmp"/etc
makefile root:root 0644 "$tmp"/etc/hostname <<EOF
$HOSTNAME
EOF
mkdir -p "$tmp"/etc/network
makefile root:root 0644 "$tmp"/etc/network/interfaces <<EOF
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet dhcp
EOF
mkdir -p "$tmp"/etc/apk
makefile root:root 0644 "$tmp"/etc/apk/world <<EOF
alpine-base
EOF
rc_add devfs sysinit
rc_add dmesg sysinit
rc_add mdev sysinit
rc_add hwdrivers sysinit
rc_add modloop sysinit
rc_add hwclock boot
rc_add modules boot
rc_add sysctl boot
rc_add hostname boot
rc_add bootmisc boot
rc_add syslog boot
rc_add mount-ro shutdown
rc_add killprocs shutdown
rc_add savecache shutdown
tar -c -C "$tmp" etc | gzip -9n > $HOSTNAME.apkovl.tar.gz
+75
View File
@@ -0,0 +1,75 @@
#!/bin/sh -e
HOSTNAME="$1"
if [ -z "$HOSTNAME" ]; then
echo "usage: $0 hostname"
exit 1
fi
cleanup() {
rm -rf "$tmp"
}
makefile() {
OWNER="$1"
PERMS="$2"
FILENAME="$3"
cat > "$FILENAME"
chown "$OWNER" "$FILENAME"
chmod "$PERMS" "$FILENAME"
}
rc_add() {
mkdir -p "$tmp"/etc/runlevels/"$2"
ln -sf /etc/init.d/"$1" "$tmp"/etc/runlevels/"$2"/"$1"
}
tmp="$(mktemp -d)"
trap cleanup EXIT
mkdir -p "$tmp"/etc
makefile root:root 0644 "$tmp"/etc/hostname <<EOF
$HOSTNAME
EOF
makefile root:root 0644 "$tmp"/etc/modules <<EOF
xen_netback
xen_blkback
xenfs
xen-platform-pci
xen_wdt
tun
EOF
mkdir -p "$tmp"/etc/network
makefile root:root 0644 "$tmp"/etc/network/interfaces <<EOF
auto lo
iface lo inet loopback
EOF
mkdir -p "$tmp"/etc/apk
makefile root:root 0644 "$tmp"/etc/apk/world <<EOF
xen
EOF
rc_add devfs sysinit
rc_add dmesg sysinit
rc_add udev sysinit
rc_add hwclock boot
rc_add modules boot
rc_add sysctl boot
rc_add hostname boot
rc_add bootmisc boot
rc_add syslog boot
rc_add udev-postmount default
rc_add xenstored default
rc_add xenconsoled default
rc_add mount-ro shutdown
rc_add killprocs shutdown
rc_add savecache shutdown
tar -c -C "$tmp" etc | gzip -9n > $HOSTNAME.apkovl.tar.gz
+60
View File
@@ -0,0 +1,60 @@
#!/bin/sh -e
cleanup() {
rm -rf "$tmp"
}
tmp="$(mktemp -d)"
trap cleanup EXIT
chmod 0755 "$tmp"
arch="$(apk --print-arch)"
repositories_file=/etc/apk/repositories
keys_dir=/etc/apk/keys
while getopts "a:r:k:o:" opt; do
case $opt in
a) arch="$OPTARG";;
r) repositories_file="$OPTARG";;
k) keys_dir="$OPTARG";;
o) outfile="$OPTARG";;
esac
done
shift $(( $OPTIND - 1))
cat "$repositories_file"
if [ -z "$outfile" ]; then
outfile=rootfs-$arch.tar.gz
fi
${APK:-apk} add --keys-dir "$keys_dir" --no-cache \
--repositories-file "$repositories_file" \
--no-script --root "$tmp" --initdb --arch "$arch" \
"$@"
rm -f "$tmp"/var/log/apk.log
for link in $("$tmp"/bin/busybox --list-full); do
[ -e "$tmp"/$link ] || ln -s /bin/busybox "$tmp"/$link
done
# disable password login but allow login with ssh keys for root
sed -i -e 's/^root::/root:*:/' "$tmp"/etc/shadow
# Set shadow group manually since we use --no-script above
# Use gid since we use --numeric-owner below
chgrp 42 "$tmp"/etc/shadow
branch=edge
VERSION_ID=$(awk -F= '$1=="VERSION_ID" {print $2}' "$tmp"/etc/os-release)
case $VERSION_ID in
*_alpha*|*_beta*) branch=edge;;
*.*.*) branch=v${VERSION_ID%.*};;
esac
cat > "$tmp"/etc/apk/repositories <<EOF
https://dl-cdn.alpinelinux.org/alpine/$branch/main
https://dl-cdn.alpinelinux.org/alpine/$branch/community
EOF
tar --numeric-owner --exclude='dev/*' -c -C "$tmp" . | gzip -9n > "$outfile"
+93
View File
@@ -0,0 +1,93 @@
#!/bin/sh
progname=$(basename $0)
usage() {
echo "usage: $progname --checksums <checksums> --arch <arch> FILE..."
}
checksums="sha256 sha512"
while [ $# -gt 0 ]; do
opt="$1"
shift
case "$opt" in
--checksums) checksums="$1"; shift ;;
--arch) arch="$1"; shift ;;
--branch) branch="$1"; shift;;
--release) release="$1"; shift;;
--flavor) flavor="$1"; shift;;
--title) title="$1"; shift;;
--desc) desc="$1"; shift;;
--) break ;;
-*) usage; exit 1;;
esac
done
set -- $opt "$@"
if [ -z "$branch" ]; then
case "$release" in
*.*.*_alpha*|*.*.*_beta*) branch=edge;;
*.*.*) branch=${release%.*}; branch="v${branch#v}";;
*)
git_branch="$(git rev-parse --abbrev-ref HEAD)"
case "$git_branch" in
*-stable) branch=${git_branch%-stable};;
*) branch=edge;;
esac
;;
esac
fi
releasedir="$branch/releases/$arch"
[ -n "$arch" ] || arch=$(apk --print-arch)
# size_and_sum [file] [prefix]
size_and_sum() {
echo " ${2}size: $(stat -c "%s" "$1")"
for hash in ${checksums}; do
# generate checksums if missing
if ! [ -f "$1.$hash" ]; then
${hash}sum "$1" | sed 's: .*/: :' > "$1.$hash"
fi
echo " $2$hash: $(cut -d' ' -f1 $1.$hash)"
done
}
for image; do
filepath="$releasedir/${image##*/}"
datetime="$(stat -c "%y" $image)"
size="$(stat -c "%s" $image)"
date=${datetime%% *}
time=${datetime#* }
time=${time%.*}
file=${filepath##*/}
flavor=${file%-${release}-${arch}.*}
desc=$(echo "$desc" | sed -E 's/^\s*/ /')
cat <<-EOF
-
title: "$title"
desc: |
$desc
branch: $branch
arch: $arch
version: $release
flavor: $flavor
file: $file
iso: $file
date: $date
time: $time
EOF
size_and_sum "$image"
case "$file" in
*.img.gz)
extracted=${image%.gz}
if ! [ -f "$extracted" ]; then
zcat < "$image" > "$extracted"
fi
size_and_sum "$extracted" extracted_
;;
esac
done
+332
View File
@@ -0,0 +1,332 @@
#!/bin/sh
# apk add \
# abuild apk-tools alpine-conf busybox fakeroot syslinux xorriso cmd:mksquashfs
# (for efi:) mtools grub
# (for s390x:) s390-tools
# (for ppc64le:) grub
# FIXME: clean workdir out of unneeded sections
# FIXME: --release: cp/mv images to REPODIR/$ARCH/releases/
# FIXME: --update-latest: rewrite latest-releases.yaml with this build
set -e
# get abuild configurables
. "${ABUILD_SHAREDIR:-/usr/share/abuild}"/functions.sh
scriptdir="$(dirname "$0")"
git=$(command -v git) || git=true
# echo '-dirty' if git is not clean
git_dirty() {
[ $($git status -s -- "$scriptdir" | wc -l) -ne 0 ] && echo "-dirty"
}
# echo last commit hash id
git_last_commit() {
$git log --format=oneline -n 1 -- "$scriptdir" | awk '{print $1}'
}
# date of last commit
git_last_commit_epoch() {
$git log -1 --format=%cd --date=unix "$1" -- "$scriptdir"
}
set_source_date() {
# dont error out if we're not in git
if ! $git rev-parse --show-toplevel >/dev/null 2>&1; then
git=true
fi
# set time stamp for reproducible builds
if [ -z "$ABUILD_LAST_COMMIT" ]; then
export ABUILD_LAST_COMMIT="$(git_last_commit)$(git_dirty)"
fi
if [ -z "$SOURCE_DATE_EPOCH" ] && [ "${ABUILD_LAST_COMMIT%-dirty}" = "$ABUILD_LAST_COMMIT" ]; then
SOURCE_DATE_EPOCH=$(git_last_commit_epoch "$ABUILD_LAST_COMMIT")
fi
if [ -z "$SOURCE_DATE_EPOCH" ]; then
SOURCE_DATE_EPOCH=$(date -u "+%s")
fi
export SOURCE_DATE_EPOCH
}
set_source_date
#
all_sections=""
all_profiles=""
all_checksums="sha256 sha512"
all_dirs=""
build_date="$(date -u +%y%m%d -d "@$SOURCE_DATE_EPOCH")"
default_arch="$(apk --print-arch)"
_hostkeys=""
_simulate=""
_checksum=""
OUTDIR="$PWD"
RELEASE="${build_date}"
msg() {
if [ -n "$quiet" ]; then return 0; fi
local prompt="$GREEN>>>${NORMAL}"
local name="${BLUE}mkimage${ARCH+-$ARCH}${NORMAL}"
printf "${prompt} ${name}: %s\n" "$1" >&2
}
list_has() {
local needle="$1"
local i
shift
for i in $@; do
[ "$needle" != "$i" ] || return 0
done
return 1
}
usage() {
cat <<EOF
$0 [--tag RELEASE] [--outdir OUTDIR] [--workdir WORKDIR]
[--arch ARCH] [--profile PROFILE] [--hostkeys] [--simulate]
[--repository REPO [--repository REPO]]
[--repositories-file REPO_FILE] [--yaml FILE]
$0 --help
options:
--arch Specify which architecture images to build
(default: $default_arch)
--hostkeys Copy system apk signing keys to created images
--outdir Specify directory for the created images
--profile Specify which profiles to build
--repositories-file List of repositories to use for the image create
--repository Package repository to use for the image create
--simulate Don't execute commands
--tag Build images for tag RELEASE
--workdir Specify temporary working directory (cache)
--yaml
known profiles: $(echo $all_profiles | sort -u)
EOF
}
# helpers
load_plugins() {
local f
[ -e "$1" ] || return 0
for f in "$1"/mkimg.*.sh; do
[ -e "$f" ] || return 0
break
done
all_profiles="$all_profiles $(sed -n -e 's/^profile_\(.*\)() {$/\1/p' $1/mkimg.*.sh)"
all_sections="$all_sections $(sed -n -e 's/^section_\(.*\)() {$/\1/p' $1/mkimg.*.sh)"
for f in "$1"/mkimg.*.sh; do
. $f
done
}
checksum() {
sha1sum | cut -f 1 -d ' '
}
build_section() {
local section="$1"
local args="$@"
local _dir="${args//[^a-zA-Z0-9]/_}"
shift
local args="$@"
if [ -z "$_dir" ]; then
_fail="yes"
return 1
fi
if [ ! -e "$WORKDIR/${_dir}" ]; then
DESTDIR="$WORKDIR/${_dir}.work"
msg "--> $section $args"
if [ -z "$_simulate" ]; then
rm -rf "$DESTDIR"
mkdir -p "$DESTDIR"
if build_${section} "$@"; then
mv "$DESTDIR" "$WORKDIR/${_dir}"
_dirty="yes"
else
rm -rf "$DESTDIR"
_fail="yes"
return 1
fi
fi
fi
unset DESTDIR
all_dirs="$all_dirs $_dir"
_my_sections="$_my_sections $_dir"
}
build_profile() {
local _id _dir _spec
_my_sections=""
_dirty="no"
_fail="no"
profile_$PROFILE
list_has $ARCH $arch || return 0
msg "Building $PROFILE"
# Collect list of needed sections, and make sure they are built
for SECTION in $all_sections; do
section_$SECTION || return 1
done
[ "$_fail" = "no" ] || return 1
# Defaults
[ -n "$image_name" ] || image_name="alpine-${PROFILE}"
[ -n "$output_filename" ] || output_filename="${image_name}-${RELEASE}-${ARCH}.${image_ext}"
local output_file="${OUTDIR:-.}/$output_filename"
# Construct final image
local _imgid=$(echo -n $_my_sections | sort | checksum)
DESTDIR=$WORKDIR/image-$_imgid-$ARCH-$PROFILE
if [ "$_dirty" = "yes" -o ! -e "$DESTDIR" ]; then
msg "Creating $output_filename"
if [ -z "$_simulate" ]; then
# Merge sections
rm -rf "$DESTDIR"
mkdir -p "$DESTDIR"
for _dir in $_my_sections; do
for _fn in $WORKDIR/$_dir/*; do
[ ! -e "$_fn" ] || cp -Lrs $_fn $DESTDIR/
done
done
echo "${image_name}-${RELEASE} ${build_date}" > "$DESTDIR"/.alpine-release
fi
fi
if [ "$_dirty" = "yes" -o ! -e "$output_file" ]; then
# Create image
[ -n "$output_format" ] || output_format="${image_ext//[:\.]/}"
create_image_${output_format} || { _fail="yes"; return 1; }
if [ "$_checksum" = "yes" ]; then
for _c in $all_checksums; do
echo "$(${_c}sum "$output_file" | cut -d' ' -f1) ${output_filename}" > "${output_file}.${_c}"
done
fi
fi
if [ -n "$_yaml_out" ]; then
$mkimage_yaml --release $RELEASE \
--title "$title" \
--desc "$desc" \
"$output_file" >> "$_yaml_out"
fi
}
# load plugins
load_plugins "$scriptdir"
[ -z "$HOME" ] || load_plugins "$HOME/.mkimage"
mkimage_yaml="$(dirname $0)"/mkimage-yaml.sh
# parse parameters
while [ $# -gt 0 ]; do
opt="$1"
shift
case "$opt" in
--repositories-file) REPOS_FILE="$1"; shift ;;
--repository)
if [ -z "$REPOS" ]; then
REPOS="$1"
else
REPOS=$(printf '%s\n%s' "$REPOS" "$1");
fi
shift ;;
--extra-repository)
warning "--extra-repository is deprecated. Use multiple --repository"
EXTRAREPOS="$EXTRAREPOS $1"
shift ;;
--workdir) WORKDIR="$1"; shift ;;
--outdir) OUTDIR="$1"; shift ;;
--tag) RELEASE="$1"; shift ;;
--arch) req_arch="$1"; shift ;;
--profile) req_profiles="$1"; shift ;;
--hostkeys) _hostkeys="--hostkeys";;
--simulate) _simulate="yes";;
--checksum) _checksum="yes";;
--yaml) _yaml="yes";;
--help) usage; exit 0;;
--) break ;;
-*) usage; exit 1;;
esac
done
if [ -z "$RELEASE" ]; then
if git describe --exact-match >/dev/null 2>&1; then
RELEASE=$(git describe --always)
RELEASE=${RELEASE#v}
else
RELEASE="${build_date}"
fi
fi
if [ -z "$REPOS" ]; then
echo "Must provide --repository"
exit 2
fi
# setup defaults
if [ -z "$WORKDIR" ]; then
WORKDIR="$(mktemp -d -t mkimage.XXXXXX)"
trap 'rm -rf $WORKDIR' INT EXIT
fi
req_profiles=${req_profiles:-${all_profiles}}
req_arch=${req_arch:-${default_arch}}
[ "$req_arch" != "all" ] || req_arch="${all_arch}"
[ "$req_profiles" != "all" ] || req_profiles="${all_profiles}"
mkdir -p "$OUTDIR"
# get abuild pubkey used to sign the apkindex
# we need inject this to the initramfs or we will not be able to use the
# boot repository
if [ -z "$_hostkeys" ]; then
_pub=${PACKAGER_PRIVKEY:+${PACKAGER_PRIVKEY}.pub}
_abuild_pubkey="${PACKAGER_PUBKEY:-$_pub}"
fi
# create images
for ARCH in $req_arch; do
APKROOT="$WORKDIR/apkroot-$ARCH"
if [ ! -e "$APKROOT" ]; then
# create root for caching packages
mkdir -p "$APKROOT/etc/apk/cache" "$APKROOT"/etc/apk/keys
[ -d /usr/share/apk/keys/"$ARCH" ] &&
cp /usr/share/apk/keys/"$ARCH"/* "$APKROOT"/etc/apk/keys
if [ -n "$_hostkeys" ]; then
cp /etc/apk/keys/* "$APKROOT"/etc/apk/keys
else
cp "$_abuild_pubkey" "$APKROOT"/etc/apk/keys
fi
apk --arch "$ARCH" --root "$APKROOT" add --initdb --no-chown
_repositories="$APKROOT/etc/apk/repositories"
if [ -n "$REPOS_FILE" ]; then
cat "$REPOS_FILE" > "$_repositories"
fi
echo "$REPOS" >> "$_repositories"
for repo in $EXTRAREPOS; do
echo "$repo" >> "$_repositories"
done
fi
apk update --root "$APKROOT"
if [ "$_yaml" = "yes" ]; then
_yaml_out=${OUTDIR:-.}/latest-releases.yaml
echo "---" > "$_yaml_out"
fi
for PROFILE in $req_profiles; do
(set -eo pipefail; build_profile) || exit 1
done
done
echo "Images generated in $OUTDIR"
+71
View File
@@ -0,0 +1,71 @@
build_rpi_blobs() {
for i in raspberrypi-bootloader-common raspberrypi-bootloader; do
apk fetch --root "$APKROOT" --quiet --stdout "$i" | tar -C "${DESTDIR}" -zx --strip=1 boot/ || return 1
done
}
rpi_gen_cmdline() {
echo "modules=loop,squashfs,sd-mod,usb-storage quiet ${kernel_cmdline}"
}
rpi_gen_config() {
local arm_64bit=0
case "$ARCH" in
aarch64) arm_64bit=1;;
esac
cat <<-EOF
# do not modify this file as it will be overwritten on upgrade.
# create and/or modify usercfg.txt instead.
# https://www.raspberrypi.com/documentation/computers/config_txt.html
kernel=boot/vmlinuz-rpi
initramfs boot/initramfs-rpi
arm_64bit=$arm_64bit
include usercfg.txt
EOF
}
build_rpi_config() {
rpi_gen_cmdline > "${DESTDIR}"/cmdline.txt
rpi_gen_config > "${DESTDIR}"/config.txt
}
section_rpi_config() {
[ "$hostname" = "rpi" ] || return 0
build_section rpi_config $( (rpi_gen_cmdline ; rpi_gen_config) | checksum )
build_section rpi_blobs
}
profile_rpi() {
profile_base
title="Raspberry Pi"
desc="First generation Pis including Zero/W (armhf).
Pi 2 to Pi 3+ generations (armv7).
Pi 3 to Pi 5 generations (aarch64)."
image_ext="tar.gz"
arch="aarch64 armhf armv7"
kernel_flavors="rpi"
kernel_cmdline="console=tty1"
initfs_features="base squashfs mmc usb kms dhcp https"
hostname="rpi"
grub_mod=
}
create_image_imggz() {
sync "$DESTDIR"
local image_size=$(du -L -k -s "$DESTDIR" | awk '{print $1 + 8192}' )
local imgfile="${OUTDIR}/${output_filename%.gz}"
dd if=/dev/zero of="$imgfile" bs=1M count=$(( image_size / 1024 ))
mformat -i "$imgfile" -N 0 ::
mcopy -s -i "$imgfile" "$DESTDIR"/* "$DESTDIR"/.alpine-release ::
echo "Compressing $imgfile..."
pigz -v -f -9 "$imgfile" || gzip -f -9 "$imgfile"
}
profile_rpiimg() {
profile_rpi
title="Raspberry Pi Disk Image"
image_name="alpine-rpi"
image_ext="img.gz"
}
+341
View File
@@ -0,0 +1,341 @@
build_kernel() {
local _flavor="$2" _modloopsign= _add
shift 3
local _pkgs="$@"
[ "$modloop_sign" = "yes" ] && _modloopsign="--modloopsign"
update-kernel \
$_hostkeys \
${_abuild_pubkey:+--apk-pubkey $_abuild_pubkey} \
$_modloopsign \
--media \
--cache-dir "$APKROOT/etc/apk/cache" \
--keys-dir "$APKROOT/etc/apk/keys" \
--flavor "$_flavor" \
--arch "$ARCH" \
--package "$_pkgs" \
--feature "$initfs_features" \
--modloopfw "$modloopfw" \
--repositories-file "$APKROOT/etc/apk/repositories" \
"$DESTDIR" \
|| return 1
for _add in $boot_addons; do
apk fetch --root "$APKROOT" --quiet --stdout $_add | tar -C "${DESTDIR}" -zx boot/
done
}
section_kernels() {
local _f _a _pkgs
for _f in $kernel_flavors; do
_pkgs="linux-$_f linux-firmware wireless-regdb $modloop_addons"
for _a in $kernel_addons; do
_pkgs="$_pkgs $_a-$_f"
done
local id=$( (echo "$initfs_features::$_hostkeys" ; apk fetch --root "$APKROOT" --simulate alpine-base $_pkgs | sort) | checksum)
build_section kernel $ARCH $_f $id $_pkgs
done
}
build_apks() {
local _apksdir="$DESTDIR/apks"
local _archdir="$_apksdir/$ARCH"
mkdir -p "$_archdir"
apk fetch --root "$APKROOT" --link --recursive --output "$_archdir" $apks
if ! ls "$_archdir"/*.apk >& /dev/null; then
return 1
fi
apk index \
--root "$APKROOT" \
--description "$RELEASE" \
--rewrite-arch "$ARCH" \
--index "$_archdir"/APKINDEX.tar.gz \
--output "$_archdir"/APKINDEX.tar.gz \
"$_archdir"/*.apk
abuild-sign "$_archdir"/APKINDEX.tar.gz
touch "$_apksdir/.boot_repository"
}
section_apks() {
[ -n "$apks" ] || return 0
build_section apks $ARCH $(apk fetch --root "$APKROOT" --simulate --recursive $apks | sort | checksum)
}
build_apkovl() {
local _host="$1" _script=
msg "Generating $_host.apkovl.tar.gz"
for _script in "$PWD"/"$apkovl" $HOME/.mkimage/$apkovl \
$(readlink -f "$scriptdir/$apkovl"); do
if [ -f "$_script" ]; then
break
fi
done
[ -n "$_script" ] || die "could not find $apkovl"
(cd "$DESTDIR"; fakeroot "$_script" "$_host")
}
section_apkovl() {
[ -n "$apkovl" -a -n "$hostname" ] || return 0
build_section apkovl $hostname $(checksum < "$apkovl")
}
build_syslinux() {
local _fn
mkdir -p "$DESTDIR"/boot/syslinux
apk fetch --root "$APKROOT" --stdout syslinux | tar -C "$DESTDIR" -xz usr/share/syslinux
for _fn in isohdpfx.bin isolinux.bin ldlinux.c32 libutil.c32 libcom32.c32 mboot.c32; do
mv "$DESTDIR"/usr/share/syslinux/$_fn "$DESTDIR"/boot/syslinux/$_fn || return 1
done
rm -rf "$DESTDIR"/usr
}
section_syslinux() {
[ "$ARCH" = x86 -o "$ARCH" = x86_64 ] || return 0
[ "$output_format" = "iso" ] || return 0
build_section syslinux $(apk fetch --root "$APKROOT" --simulate syslinux | sort | checksum)
}
syslinux_gen_config() {
[ -z "$syslinux_serial" ] || echo "SERIAL $syslinux_serial"
echo "TIMEOUT ${syslinux_timeout:-10}"
echo "PROMPT ${syslinux_prompt:-1}"
echo "DEFAULT ${kernel_flavors%% *}"
local _f _p _initrd
for _f in $kernel_flavors; do
if [ -z "${xen_params+set}" ]; then
_initrd="/boot/initramfs-$_f"
for _p in $initrd_ucode; do
_initrd="$_p,$_initrd"
done
cat <<- EOF
LABEL $_f
MENU LABEL Linux $_f
KERNEL /boot/vmlinuz-$_f
INITRD $_initrd
FDTDIR /boot/dtbs-$_f
APPEND $initfs_cmdline $kernel_cmdline
EOF
else
cat <<- EOF
LABEL $_f
MENU LABEL Xen/Linux $_f
KERNEL /boot/syslinux/mboot.c32
APPEND /boot/xen.gz ${xen_params} --- /boot/vmlinuz-$_f $initfs_cmdline $kernel_cmdline --- /boot/initramfs-$_f
EOF
fi
done
}
grub_gen_config() {
local _f _p _initrd
echo "set timeout=1"
for _f in $kernel_flavors; do
if [ -z "${xen_params+set}" ]; then
_initrd="/boot/initramfs-$_f"
for _p in $initrd_ucode; do
_initrd="$_p $_initrd"
done
cat <<- EOF
menuentry "Linux $_f" {
linux /boot/vmlinuz-$_f $initfs_cmdline $kernel_cmdline
initrd $_initrd
}
EOF
else
cat <<- EOF
menuentry "Xen/Linux $_f" {
multiboot2 /boot/xen.gz ${xen_params}
module2 /boot/vmlinuz-$_f $initfs_cmdline $kernel_cmdline
module2 /boot/initramfs-$_f
}
EOF
fi
done
}
build_syslinux_cfg() {
local syslinux_cfg="$1"
mkdir -p "${DESTDIR}/$(dirname $syslinux_cfg)"
syslinux_gen_config > "${DESTDIR}"/$syslinux_cfg
}
section_syslinux_cfg() {
syslinux_cfg=""
if [ "$ARCH" = x86 -o "$ARCH" = x86_64 ]; then
[ ! "$output_format" = "iso" ] || syslinux_cfg="boot/syslinux/syslinux.cfg"
fi
[ ! -n "$uboot_install" ] || syslinux_cfg="extlinux/extlinux.conf"
[ -n "$syslinux_cfg" ] || return 0
build_section syslinux_cfg $syslinux_cfg $(syslinux_gen_config | checksum)
}
build_grub_cfg() {
local grub_cfg="$1"
mkdir -p "${DESTDIR}/$(dirname $grub_cfg)"
grub_gen_config > "${DESTDIR}"/$grub_cfg
}
gen_volid() {
printf "%s" "alpine-${profile_abbrev:-$PROFILE} ${RELEASE%_rc*} $ARCH" | cut -c1-32
}
grub_gen_earlyconf() {
cat <<- EOF
search --no-floppy --set=root --label "$(gen_volid)"
set prefix=(\$root)/boot/grub
EOF
}
build_grub_efi() {
local _format="$1"
local _efi="$2"
apk fetch --root "$APKROOT" --quiet --stdout grub-efi | tar -C "$WORKDIR" -zx usr/lib/grub
# Prepare grub-efi bootloader
mkdir -p "$DESTDIR/efi/boot"
grub_gen_earlyconf > "$WORKDIR/grub_early.$3.cfg"
grub-mkimage \
--config="$WORKDIR/grub_early.$3.cfg" \
--directory="$WORKDIR"/usr/lib/grub/"$_format" \
--prefix="/boot/grub" \
--output="$DESTDIR/efi/boot/$_efi" \
--format="$_format" \
--compression="xz" \
$grub_mod
}
section_grubieee1275() {
[ "$ARCH" = ppc64le ] || return 0
[ "$output_format" = "iso" ] || return 0
kernel_cmdline="$kernel_cmdline console=hvc0"
build_section grub_cfg boot/grub/grub.cfg $(grub_gen_config | checksum)
}
section_grub_efi() {
[ -n "$grub_mod" ] || return 0
local _format _efi
case "$ARCH" in
aarch64)_format="arm64-efi"; _efi="bootaa64.efi" ;;
arm*) _format="arm-efi"; _efi="bootarm.efi" ;;
x86) _format="i386-efi"; _efi="bootia32.efi" ;;
x86_64) _format="x86_64-efi"; _efi="bootx64.efi" ;;
riscv64) _format="riscv64-efi"; _efi="bootriscv64.efi" ;;
loongarch64) _format="loongarch64-efi"; _efi="bootloongarch64.efi" ;;
*) return 0 ;;
esac
build_section grub_cfg boot/grub/grub.cfg $(grub_gen_config | checksum)
build_section grub_efi $_format $_efi $(grub_gen_earlyconf | checksum)
}
create_image_iso() {
local ISO="${OUTDIR}/${output_filename}"
local _isolinux
local _efiboot
if [ -e "${DESTDIR}/boot/syslinux/isolinux.bin" ]; then
# isolinux enabled
_isolinux="
-isohybrid-mbr ${DESTDIR}/boot/syslinux/isohdpfx.bin
-eltorito-boot boot/syslinux/isolinux.bin
-eltorito-catalog boot/syslinux/boot.cat
-no-emul-boot
-boot-load-size 4
-boot-info-table
"
fi
if [ -e "${DESTDIR}/efi" -a -e "${DESTDIR}/boot/grub" ]; then
# Create the EFI boot partition image
mformat -i ${DESTDIR}/boot/grub/efi.img -C -f 1440 -N 0 ::
mcopy -i ${DESTDIR}/boot/grub/efi.img -s ${DESTDIR}/efi ::
touch -md "@${SOURCE_DATE_EPOCH}" ${DESTDIR}/boot/grub/efi.img
# Enable EFI boot
if [ -z "$_isolinux" ]; then
# efi boot only
_efiboot="
-efi-boot-part
--efi-boot-image
-e boot/grub/efi.img
-no-emul-boot
"
else
# hybrid isolinux+efi boot
_efiboot="
-eltorito-alt-boot
-e boot/grub/efi.img
-no-emul-boot
-isohybrid-gpt-basdat
"
fi
fi
if [ "$ARCH" = ppc64le ]; then
apk fetch --root "$APKROOT" --quiet --stdout grub-ieee1275 | tar -C "$WORKDIR" -zx usr/lib/grub
grub-mkrescue --output ${ISO} ${DESTDIR} -follow-links \
--directory="$WORKDIR"/usr/lib/grub/powerpc-ieee1275 \
-sysid LINUX \
-volid "$(gen_volid)"
else
if [ "$ARCH" = s390x ]; then
printf %s "$initfs_cmdline $kernel_cmdline " > ${WORKDIR}/parmfile
for _f in $kernel_flavors; do
mk-s390-cdboot -p ${WORKDIR}/parmfile \
-i ${DESTDIR}/boot/vmlinuz-$_f \
-r ${DESTDIR}/boot/initramfs-$_f \
-o ${DESTDIR}/boot/merged.img
done
iso_opts="$iso_opts -no-emul-boot -eltorito-boot boot/merged.img"
fi
xorrisofs \
-quiet \
-output ${ISO} \
-full-iso9660-filenames \
-joliet \
-rational-rock \
-sysid LINUX \
-volid "$(gen_volid)" \
$_isolinux \
$_efiboot \
-follow-links \
${iso_opts} \
${DESTDIR}
fi
}
create_image_targz() {
tar -C "${DESTDIR}" \
--mtime="@${SOURCE_DATE_EPOCH}" \
--owner=0 --group=0 --numeric-owner \
-chzf "${OUTDIR}/${output_filename}" .
}
profile_base() {
kernel_flavors="lts"
initfs_cmdline="modules=loop,squashfs,sd-mod,usb-storage quiet"
initfs_features="ata base bootchart cdrom ext4 mmc nvme raid scsi squashfs usb virtio"
modloop_sign=yes
grub_mod="all_video disk part_gpt part_msdos linux normal configfile search search_label efi_gop fat iso9660 cat echo ls test true help gzio"
case "$ARCH" in
x86*) grub_mod="$grub_mod multiboot2 efi_uga";;
esac
case "$ARCH" in
x86_64) initfs_features="$initfs_features nfit";;
arm*|aarch64) initfs_features="$initfs_features phy";;
esac
apks="alpine-base apk-cron busybox chrony dhcpcd doas e2fsprogs
kbd-bkeymaps network-extras openntpd openssl openssh
tzdata wget tiny-cloud-alpine"
apkovl=
hostname="alpine"
}
@@ -1,5 +1,5 @@
profile_immich() {
profile_standard
apks="$apks docker docker-compose"
apkovl="immich.apkovl.tar.gz"
apkovl="scripts/genapkovl-dhcp.sh"
}
+25
View File
@@ -0,0 +1,25 @@
section_minirootfs() {
return 0
}
create_image_rootfs() {
local _script=$(readlink -f "$scriptdir/genrootfs.sh")
local output_file="$(readlink -f ${OUTDIR:-.})/$output_filename"
(cd "$OUTDIR"; fakeroot "$_script" -k "$APKROOT"/etc/apk/keys \
-r "$APKROOT"/etc/apk/repositories \
-o "$output_file" \
-a $ARCH \
$rootfs_apks)
}
profile_minirootfs() {
title="Mini root filesystem"
desc="Minimal root filesystem.
For use in containers
and minimal chroots."
image_ext=tar.gz
output_format=rootfs
arch="$ARCH" # allow any arch
rootfs_apks="busybox alpine-baselayout alpine-keys alpine-release apk-tools libc-utils"
}
+32
View File
@@ -0,0 +1,32 @@
create_image_netboot() {
rm -rf "${OUTDIR}"/netboot-$RELEASE "${OUTDIR}"/netboot
cp -aL "${DESTDIR}"/boot "${OUTDIR}"/netboot-$RELEASE
ln -s netboot-$RELEASE "${OUTDIR}"/netboot
# let webserver read initramfs
chmod a+r "${OUTDIR}"/netboot-$RELEASE/*
tar -C "${DESTDIR}" -chzf ${OUTDIR}/${output_filename} boot/
}
profile_netboot() {
title="Netboot"
desc="Kernel, initramfs and modloop for
netboot.
"
arch="aarch64 armhf armv7 ppc64le x86 x86_64 s390x"
case "$ARCH" in
armhf) kernel_flavors="rpi";;
armv7) kernel_flavors="lts rpi";;
aarch64) kernel_flavors="lts virt rpi";;
x86_64) kernel_flavors="lts virt";;
*) kernel_flavors="lts";;
esac
case "$ARCH" in
s390x) initfs_features="base network squashfs usb dasd_mod qeth zfcp";;
*) initfs_features="base network squashfs usb virtio"
esac
modloop_sign=yes
apks=""
output_format="netboot"
image_ext="tar.gz"
}
+86
View File
@@ -0,0 +1,86 @@
profile_standard() {
title="Standard"
desc="Alpine as it was intended.
Just enough to get you started.
Network connection is required."
profile_base
profile_abbrev="std"
image_ext="iso"
arch="aarch64 armv7 x86 x86_64 ppc64le s390x loongarch64"
output_format="iso"
kernel_addons="xtables-addons"
case "$ARCH" in
s390x)
apks="$apks s390-tools"
initfs_features="$initfs_features dasd_mod qeth zfcp"
initfs_cmdline="modules=loop,squashfs,dasd_mod,qeth,zfcp quiet"
;;
ppc64le)
initfs_cmdline="modules=loop,squashfs,sd-mod,usb-storage,ibmvscsi quiet"
;;
esac
apks="$apks iw wpa_supplicant"
}
profile_extended() {
profile_standard
profile_abbrev="ext"
title="Extended"
desc="Most common used packages included.
Suitable for routers and servers.
Runs from RAM.
Includes AMD and Intel microcode updates."
arch="x86 x86_64"
kernel_addons="xtables-addons zfs"
boot_addons="amd-ucode intel-ucode"
initrd_ucode="/boot/amd-ucode.img /boot/intel-ucode.img"
apks="$apks
coreutils ethtool hwids doas
logrotate lsof lm_sensors lxc lxc-templates nano
pciutils strace tmux
usbutils v86d vim xtables-addons curl
acct arpon arpwatch awall bridge-utils bwm-ng
ca-certificates conntrack-tools cutter cyrus-sasl
dhcpcd dnsmasq fping fprobe htop
igmpproxy ip6tables iproute2 iproute2-qos
iptables iputils nftables iw kea ldns-tools links
ncurses-terminfo net-snmp net-snmp-tools nrpe nsd
opennhrp openvpn pingu ppp quagga
quagga-nhrp rng-tools sntpc socat ssmtp strongswan
sysklogd tcpdump tinyproxy unbound
wireguard-tools wireless-tools wpa_supplicant zonenotify
btrfs-progs cksfv dosfstools cryptsetup
e2fsprogs e2fsprogs-extra efibootmgr f2fs-tools
grub-bios grub-efi lvm2 lz4 mdadm mkinitfs mtools nfs-utils
parted rsync sfdisk syslinux util-linux xfsprogs zstd zfs
"
local _k _a
for _k in $kernel_flavors; do
apks="$apks linux-$_k"
for _a in $kernel_addons; do
apks="$apks $_a-$_k"
done
done
apks="$apks linux-firmware linux-firmware-none"
}
profile_virt() {
profile_standard
profile_abbrev="virt"
title="Virtual"
desc="Similar to standard.
Slimmed down kernel.
Optimized for virtual systems."
arch="aarch64 armv7 x86 x86_64"
kernel_addons=
kernel_flavors="virt"
case "$ARCH" in
arm*|aarch64)
kernel_cmdline="console=tty0 console=ttyAMA0"
;;
esac
syslinux_serial="0 115200"
}
+32
View File
@@ -0,0 +1,32 @@
build_uboot() {
# FIXME: Fix apk-tools to extract packages directly
local pkg pkgs="$(apk fetch --simulate --root "$APKROOT" --recursive u-boot-all | sed -ne "s/^Downloading \(.*\)\-[0-9].*$/\1/p")"
for pkg in $pkgs; do
[ "$pkg" = "u-boot-all" ] || apk fetch --root "$APKROOT" --stdout $pkg | tar -C "$DESTDIR" -xz usr
done
mkdir -p "$DESTDIR"/u-boot
mv "$DESTDIR"/usr/sbin/update-u-boot "$DESTDIR"/usr/share/u-boot/* "$DESTDIR"/u-boot
rm -rf "$DESTDIR"/usr
}
section_uboot() {
[ -n "$uboot_install" ] || return 0
build_section uboot $ARCH $(apk fetch --root "$APKROOT" --simulate --recursive u-boot-all | sort | checksum)
}
profile_uboot() {
profile_base
title="Generic U-Boot"
desc="Has default LTS kernel.
Includes the U-Boot bootloader.
Tarball.
"
image_ext="tar.gz"
arch="aarch64 armv7 riscv64"
kernel_flavors="lts"
case "$ARCH" in
aarch64|armv7) kernel_addons="xtables-addons";;
esac
initfs_features="base ext4 kms mmc nvme phy raid scsi squashfs usb"
uboot_install="yes"
}
+29
View File
@@ -0,0 +1,29 @@
build_xen() {
apk fetch --root "$APKROOT" --stdout xen-hypervisor | tar -C "$DESTDIR" -xz boot
}
section_xen() {
[ -n "${xen_params+set}" ] || return 0
build_section xen $ARCH $(apk fetch --root "$APKROOT" --simulate xen-hypervisor | checksum)
}
profile_xen() {
profile_standard
profile_abbrev="xen"
title="Xen"
desc="Built-in support for Xen Hypervisor.
Includes packages targetted at Xen usage.
Use for Xen Dom0."
arch="x86_64"
kernel_addons="zfs"
xen_params=""
apks="$apks ethtool lvm2 mdadm multipath-tools rng-tools sfdisk xen xen-bridge xen-qemu syslinux zfs"
local _k _a
for _k in $kernel_flavors; do
apks="$apks linux-$_k"
for _a in $kernel_addons; do
apks="$apks $_a-$_k"
done
done
}
+17 -2
View File
@@ -1,5 +1,7 @@
#!/bin/sh -e
# modified from https://gitlab.alpinelinux.org/alpine/aports/-/blob/master/scripts/genapkovl-dhcp.sh?ref_type=heads
HOSTNAME="$1"
if [ -z "$HOSTNAME" ]; then
echo "usage: $0 hostname"
@@ -68,6 +70,19 @@ rc_add killprocs shutdown
rc_add savecache shutdown
# copy all directories from overlay/ into $tmp and merge
cp -a overlay/. "$tmp"/
cp -a /home/overlay/. "$tmp"/
tar -c -C "$tmp" etc usr | gzip -9n > $HOSTNAME.apkovl.tar.gz
# run docker and docker pull the images
mkdir -p "$tmp"/var/lib/docker
dockerd --data-root "$tmp"/var/lib/docker/ &
sleep 5
docker pull ghcr.io/immich-app/immich-server:release
docker pull ghcr.io/immich-app/immich-machine-learning:release
docker pull docker.io/valkey/valkey:8-bookworm
docker pull ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0
pkill docker || true
tar -c -C "$tmp" etc usr var | gzip -9n > $HOSTNAME.apkovl.tar.gz