Skip to content

Instantly share code, notes, and snippets.

@sfan5
Last active May 28, 2023 10:01
Embed
What would you like to do?
bootable systemd-nspawn containers with Linux distributions: Alpine, Arch Linux, Ubuntu
#!/bin/bash -e
# Creates a systemd-nspawn container with Alpine
MIRROR=http://dl-cdn.alpinelinux.org/alpine
VERSION=${VERSION:-v3.17}
APKTOOLS_VERSION=2.12.10-r1
if [ $UID -ne 0 ]; then
echo "run this script as root" >&2
exit 1
fi
if [ -z "$1" ]; then
echo "Usage: $0 <destination>" >&2
exit 0
fi
dest="$1"
apkdir=$(mktemp -d)
guestarch=x86
[ "$(uname -m)" == x86_64 ] && guestarch=x86_64
trap 'rm -r $apkdir' EXIT
wget -qO- $MIRROR/latest-stable/main/x86/apk-tools-static-$APKTOOLS_VERSION.apk \
| tar -xz -C $apkdir || \
{ echo "Couldn't download apk-tools, the version might have changed..."; 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}
printf '%s/%s/main\n' $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 container was created successfully."
#!/bin/bash -e
# Creates a systemd-nspawn container with Arch Linux
MIRROR=http://mirror.fra10.de.leaseweb.net/archlinux
ISO_DATE=2022.12.01
PKG_GROUPS="base"
if [ $UID -ne 0 ]; then
echo "run this script as root" >&2
exit 1
fi
if [ -z "$1" ]; then
echo "Usage: $0 <destination>" >&2
exit 0
fi
dest="$1"
tarfile=$(mktemp)
trap 'rm $tarfile' EXIT
wget "$MIRROR/iso/$ISO_DATE/archlinux-bootstrap-$ISO_DATE-x86_64.tar.gz" -O $tarfile
mkdir -p "$dest"
tar -xzf $tarfile -C "$dest" --strip-components=1 --numeric-owner
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"
cat >"$dest"/setup.sh <<SCRIPT
pacman-key --init && pacman-key --populate
pacman -Sy --noconfirm --needed ${PKG_GROUPS}
rm /setup.sh
SCRIPT
systemd-nspawn -q -D "$dest" sh /setup.sh
echo ""
echo "Arch Linux container was created successfully (bootstrapped from $ISO_DATE)"
#!/bin/bash -e
# Creates a systemd-nspawn container with Ubuntu
CODENAME=${CODENAME:-jammy}
if [ $UID -ne 0 ]; then
echo "run this script as root" >&2
exit 1
fi
if [ -z "$1" ]; then
echo "Usage: $0 <destination>" >&2
exit 0
fi
dest="$1"
rootfs=$(mktemp)
trap 'rm $rootfs' EXIT
wget "http://cloud-images.ubuntu.com/${CODENAME}/current/${CODENAME}-server-cloudimg-amd64-root.tar.xz" -O $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"
>"$dest/etc/fstab"
systemd-nspawn -q -D "$dest" /bin/systemctl disable \
ssh systemd-{timesyncd,networkd-wait-online,resolved}
# uninstall some packages
systemd-nspawn -q -D "$dest" /usr/bin/apt-get -qq satisfy -y --purge 'Conflicts: lxcfs, lxd, snapd, cloud-init' || \
systemd-nspawn -q -D "$dest" /usr/bin/apt-get -qq purge --autoremove snapd lxcfs lxd cloud-init
echo ""
echo "Ubuntu $CODENAME container was created successfully"
@smekkley
Copy link

Awesome, thank you for sharing the script.
It's a little bit ugly but I change to use edge instead.

VERSION=edge
APKTOOLS_VERSION=$(curl -s $MIRROR/edge/main/$ARCH/ | awk -F'=' 'match($0, /href="apk-tools-static-(.*).apk">/, a) {print a[1]}')

@mikhailnov
Copy link

Thank you, very useful scripts, saved a lot of time.

@mikhailnov
Copy link

mikhailnov commented Apr 3, 2019

@amit-tewari
Copy link

Starting alpine image on Ubuntu 20 gives

Sep 07 02:53:14 Gelato systemd-nspawn[79402]: getty: console: TIOCSCTTY: Operation not permitted
Sep 07 02:53:24 Gelato systemd-nspawn[79402]: getty: console: TIOCSCTTY: Operation not permitted
Sep 07 02:53:34 Gelato systemd-nspawn[79402]: getty: console: TIOCSCTTY: Operation not permitted
Sep 07 02:53:44 Gelato systemd-nspawn[79402]: getty: console: TIOCSCTTY: Operation not permitted
Sep 07 02:53:54 Gelato systemd-nspawn[79402]: getty: console: TIOCSCTTY: Operation not permitted

but

systemd-nspawn -M alpine -- /sbin/getty -nl /bin/ash 0 /dev/console

works.

printf 'console::respawn:/sbin/getty 38400 console\n' >>"$dest"/etc/inittab

does not seem to work.

@X0RW3LL
Copy link

X0RW3LL commented Nov 17, 2022

Thank you so much for this! I hope you don't mind me using bits of your scripts here: https://github.com/X0RW3LL/XenSpawn
Linked to this gist in the references section <3

@Jip-Hop
Copy link

Jip-Hop commented Jan 2, 2023

Thanks for this script! Building my own based on yours :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment