Last active
October 28, 2024 14:14
-
-
Save sfan5/52aa53f5dca06ac3af30455b203d3404 to your computer and use it in GitHub Desktop.
Create bootable systemd-nspawn containers with Alpine, Arch Linux or Ubuntu
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash -e | |
# Creates a systemd-nspawn container with Alpine | |
MIRROR=http://dl-cdn.alpinelinux.org/alpine | |
VERSION=${VERSION:-v3.20} | |
APKTOOLS_VERSION=2.14.4-r1 | |
wget_or_curl () { | |
if command -v wget >/dev/null; then | |
wget -qO- "$1" | |
elif command -v curl >/dev/null; then | |
curl -Ls "$1" | |
else | |
echo "missing either curl or wget" >&2 | |
return 1 | |
fi | |
} | |
if [ $UID -ne 0 ]; then | |
echo "run this script as root" >&2 | |
exit 1 | |
fi | |
dest="$1" | |
if [ -z "$dest" ]; then | |
echo "Usage: $0 <destination>" >&2 | |
exit 0 | |
fi | |
if [ -e "$dest/usr/bin" ]; then | |
echo "destination already seems to contain a root file system" >&2 | |
exit 1 | |
fi | |
if [[ "$(uname -m)" =~ ^i[3456]86|x86 ]]; then | |
toolarch=x86 | |
guestarch=$toolarch | |
[ "$(uname -m)" = x86_64 ] && guestarch=x86_64 | |
elif [[ "$(uname -m)" =~ ^arm|aarch64 ]]; then | |
toolarch=armv7 | |
guestarch=$toolarch | |
[ "$(uname -m)" = aarch64 ] && guestarch=aarch64 | |
else | |
echo "unsupported architecture" >&2 | |
exit 1 | |
fi | |
apkdir=$(mktemp -d) | |
trap 'rm -rf $apkdir' EXIT | |
wget_or_curl "$MIRROR/latest-stable/main/$toolarch/apk-tools-static-$APKTOOLS_VERSION.apk" \ | |
| tar -xz -C $apkdir || \ | |
{ echo "couldn't download apk-tools, the version might have changed..." >&2; exit 1; } | |
$apkdir/sbin/apk.static \ | |
-X $MIRROR/$VERSION/main -U --arch $guestarch \ | |
--allow-untrusted --root "$dest" \ | |
--initdb add alpine-base | |
mkdir -p "$dest"/{etc/apk,root} | |
# configure mirror | |
printf '%s/%s/main\n%s/%s/community\n' "$MIRROR" $VERSION "$MIRROR" $VERSION >"$dest"/etc/apk/repositories | |
for i in $(seq 0 10); do # https://github.com/systemd/systemd/issues/852 | |
echo "pts/$i" >>"$dest/etc/securetty" | |
done | |
# make console work | |
sed '/tty[0-9]:/ s/^/#/' -i "$dest"/etc/inittab | |
printf 'console::respawn:/sbin/getty 38400 console\n' >>"$dest"/etc/inittab | |
# minimal boot services | |
for s in hostname bootmisc syslog; do | |
ln -s /etc/init.d/$s "$dest"/etc/runlevels/boot/$s | |
done | |
for s in killprocs savecache; do | |
ln -s /etc/init.d/$s "$dest"/etc/runlevels/shutdown/$s | |
done | |
echo "" | |
echo "Alpine $VERSION $guestarch container was created successfully." |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash -e | |
# Creates a systemd-nspawn container with Arch Linux | |
MIRROR=http://mirror.fra10.de.leaseweb.net/archlinux | |
ISO_DATE=latest | |
PKG_GROUPS="base" | |
wget_or_curl () { | |
if command -v wget >/dev/null; then | |
wget "$1" -O "$2" | |
elif command -v curl >/dev/null; then | |
curl -L "$1" -o "$2" | |
else | |
echo "missing either curl or wget" >&2 | |
return 1 | |
fi | |
} | |
if [ $UID -ne 0 ]; then | |
echo "run this script as root" >&2 | |
exit 1 | |
fi | |
dest="$1" | |
if [ -z "$dest" ]; then | |
echo "Usage: $0 <destination>" >&2 | |
exit 0 | |
fi | |
if [ -e "$dest/usr/bin" ]; then | |
echo "destination already seems to contain a root file system" >&2 | |
exit 1 | |
fi | |
[ "$(uname -m)" = x86_64 ] || { echo "unsupported architecture" >&2; exit 1; } | |
tarfile=$(mktemp) | |
trap 'rm $tarfile' EXIT | |
wget_or_curl "$MIRROR/iso/$ISO_DATE/archlinux-bootstrap-x86_64.tar.zst" $tarfile | |
mkdir -p "$dest" | |
tar -xaf $tarfile -C "$dest" --strip-components=1 --numeric-owner | |
# configure mirror | |
printf 'Server = %s/$repo/os/$arch\n' "$MIRROR" >"$dest"/etc/pacman.d/mirrorlist | |
sed '/^root:/ s|\*||' -i "$dest/etc/shadow" # passwordless login | |
rm "$dest/etc/resolv.conf" # systemd configures this | |
# https://github.com/systemd/systemd/issues/852 | |
[ -f "$dest/etc/securetty" ] && \ | |
printf 'pts/%d\n' $(seq 0 10) >>"$dest/etc/securetty" | |
# seems to be this bug https://github.com/systemd/systemd/issues/3611 | |
systemd-machine-id-setup --root="$dest" | |
# install the packages | |
systemd-nspawn -q -D "$dest" sh -c " | |
pacman-key --init && pacman-key --populate | |
pacman -Sy --noconfirm --needed ${PKG_GROUPS} | |
" | |
echo "" | |
echo "Arch Linux container was created successfully (bootstrapped from $ISO_DATE)" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash -e | |
# Creates a systemd-nspawn container with Ubuntu | |
CODENAME=${CODENAME:-noble} | |
wget_or_curl () { | |
if command -v wget >/dev/null; then | |
wget "$1" -O "$2" | |
elif command -v curl >/dev/null; then | |
curl -L "$1" -o "$2" | |
else | |
echo "missing either curl or wget" >&2 | |
return 1 | |
fi | |
} | |
if [ $UID -ne 0 ]; then | |
echo "run this script as root" >&2 | |
exit 1 | |
fi | |
dest="$1" | |
if [ -z "$dest" ]; then | |
echo "Usage: $0 <destination>" >&2 | |
exit 0 | |
fi | |
if [ -e "$dest/usr/bin" ]; then | |
echo "destination already seems to contain a root file system" >&2 | |
exit 1 | |
fi | |
if [ "$(uname -m)" = x86_64 ]; then | |
guestarch=amd64 | |
elif [ "$(uname -m)" = aarch64 ]; then | |
guestarch=arm64 | |
else | |
echo "unsupported architecture" >&2 | |
exit 1 | |
fi | |
rootfs=$(mktemp) | |
trap 'rm $rootfs' EXIT | |
wget_or_curl "http://cloud-images.ubuntu.com/${CODENAME}/current/${CODENAME}-server-cloudimg-${guestarch}-root.tar.xz" $rootfs | |
mkdir -p "$dest" | |
tar -xaf $rootfs -C "$dest" --numeric-owner | |
sed '/^root:/ s|\*||' -i "$dest/etc/shadow" # passwordless login | |
rm "$dest/etc/resolv.conf" # systemd configures this | |
# https://github.com/systemd/systemd/issues/852 | |
[ -f "$dest/etc/securetty" ] && \ | |
printf 'pts/%d\n' $(seq 0 10) >>"$dest/etc/securetty" | |
# container needs no mounts | |
>"$dest/etc/fstab" | |
# disable services and uninstall packages | |
systemd-nspawn -q -D "$dest" sh -c ' | |
[ -s /etc/environment ] && . /etc/environment | |
for unit in ssh.service ssh.socket systemd-timesyncd systemd-networkd-wait-online systemd-resolved; do | |
systemctl is-enabled "$unit" && systemctl disable "$unit" | |
done | |
apt-get -qq satisfy -y --purge "Conflicts: lxcfs, lxd, snapd, cloud-init" || \ | |
apt-get -qq purge --autoremove snapd lxcfs lxd cloud-init | |
' | |
echo "" | |
echo "Ubuntu $CODENAME $guestarch container was created successfully" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks for this script! Building my own based on yours :)