Skip to content

Instantly share code, notes, and snippets.

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.13}
APKTOOLS_VERSION=2.12.5-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
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; }
trap 'rm -r $apkdir' EXIT
$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=2021.06.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)
wget "$MIRROR/iso/$ISO_DATE/archlinux-bootstrap-$ISO_DATE-x86_64.tar.gz" -O $tarfile
trap 'rm $tarfile' EXIT
mkdir -p "$dest"
tar -xzf $tarfile -C "$dest" --strip-components=1
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
for i in $(seq 0 10); do # https://github.com/systemd/systemd/issues/852
echo "pts/$i" >>"$dest/etc/securetty"
done
cat >"$dest"/setup.sh <<SCRIPT
pacman-key --init && pacman-key --populate archlinux
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:-focal}
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)
wget "http://cloud-images.ubuntu.com/${CODENAME}/current/${CODENAME}-server-cloudimg-amd64-root.tar.xz" -O $rootfs
trap 'rm $rootfs' EXIT
mkdir -p "$dest"
tar -xaf $rootfs -C "$dest"
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}
# packages that are useless inside container
systemd-nspawn -q -D "$dest" /usr/bin/apt-get -qq satisfy -y --purge 'Conflicts: lxcfs, lxd, snapd' || \
systemd-nspawn -q -D "$dest" /usr/bin/apt-get -qq purge --autoremove snapd lxcfs lxd
echo ""
echo "Ubuntu $CODENAME container was created successfully"
@smekkley

This comment has been minimized.

Copy link

@smekkley smekkley commented Oct 21, 2017

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

This comment has been minimized.

Copy link

@mikhailnov mikhailnov commented Apr 3, 2019

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

@mikhailnov

This comment has been minimized.

Copy link

@mikhailnov mikhailnov commented Apr 3, 2019

@amit-tewari

This comment has been minimized.

Copy link

@amit-tewari amit-tewari commented Sep 7, 2020

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.

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