Skip to content

Instantly share code, notes, and snippets.

@mato
Created February 3, 2024 12:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mato/35477cf13a68411555546f650b8a391e to your computer and use it in GitHub Desktop.
Save mato/35477cf13a68411555546f650b8a391e to your computer and use it in GitHub Desktop.
Companion script to my FOSDEM 2024 presentation
#!/bin/sh
#
# This script is a companion to my FOSDEM 2024 presentation,
# "Lift and shift: Modernising a legacy LAMP application with systemd-nspawn".
#
# Author: Martin Lucina <martin@lucina.net>
# License: Public domain.
#
if [ "$(id -u)" -ne 0 ]; then
echo "ERROR: This needs to run as root." 1>&2
exit 1
fi
# Points to the target directory of the rootfs we are operating on.
T=run/rootfs
# Sets the hostname used for the container.
T_HOSTNAME=ctr-lenny
# Ensure that any files we create in the rootfs have correct ownership.
fix_perms()
{
chown -h --reference="${T}" "$@"
}
# Run commands inside the container. This is intended for use during the roofs
# build process, and as such uses the host network namespace so that we can do
# apt-get.
in_target()
{
systemd-nspawn \
--directory="${T}" \
-M "${T_HOSTNAME}" \
--console=pipe \
--private-users=pick \
-E LANG=C -E DEBIAN_FRONTEND=noninteractive \
"$@" /bin/sh
}
set -e
mkdir -p build run
#
# Download and convert the lenny rootfs
# Note that the following two steps do NOT need to run as root, for the
# purposes of this example they do, just to make things easier and keep it
# self-contained.
#
if [ ! -d build/lenny-oci ]; then
skopeo copy -f oci docker://registry.docker.com/debian/eol:lenny oci:build/lenny-oci
fi
if [ ! -d build/lenny-bundle ]; then
oci-image-tool create --ref platform.os=linux build/lenny-oci build/lenny-bundle
fi
if [ ! -d ${T} ]; then
cp -pRdu --reflink=always build/lenny-bundle/rootfs ${T}
chown -hR root:root ${T}
fi
#
# The following steps get us from a rootfs capable of /bin/sh to one capable of
# a full system boot.
#
echo "${T_HOSTNAME}" >"${T}/etc/hostname"
fix_perms "${T}/etc/hostname"
touch "${T}/etc/os-release"
fix_perms "${T}/etc/os-release"
cat <<EOM >"${T}/etc/hosts"
127.0.0.1 localhost
127.0.1.1 ${T_HOSTNAME}
EOM
fix_perms "${T}/etc/hosts"
ln -sf ../proc/self/mounts "${T}/etc/mtab"
fix_perms "${T}/etc/mtab"
# Remove services that are only needed on a physical system.
REMOVE_INIT_SCRIPTS="mountkernfs.sh mountdevsubfs.sh hwclockfirst.sh hwclock.sh checkroot.sh mtab.sh checkfs.sh mountall.sh mountall-bootclean.sh mountoverflowtmp umountfs umountroot"
in_target <<EOF
for SCRIPT in ${REMOVE_INIT_SCRIPTS}; do
update-rc.d -f \${SCRIPT} remove
done
EOF
# We have no need to set a root password inside the container. The following
# lets us login from the console when booting the container without a password.
cat <<EOM >>"${T}/usr/local/sbin/autologin"
#!/bin/sh
echo "Press ENTER for autologin."
read LINE
exec /bin/login -f root
EOM
chmod +x "${T}/usr/local/sbin/autologin"
fix_perms "${T}/usr/local/sbin/autologin"
# Disable the gettys on the virtual consoles, we have none.
sed -i -e 's/^[0-9]:.*getty/# &/' "${T}/etc/inittab"
# Disable the default "ctrl-alt-del" handling (what happens when /sbin/init
# gets a SIGINT).
sed -i -e 's/^ca:/# &/' "${T}/etc/inittab"
# Start a getty with our autologin script on /dev/console.
# There will be no job control on the console; set things up so that if we
# press ^C, that results in an immediate shutdown of the container. YMMV.
cat <<EOM >>"${T}/etc/inittab"
co:2345:respawn:/sbin/getty -n -l /usr/local/sbin/autologin 38400 console
ca:12345:ctrlaltdel:/sbin/shutdown -t1 -a -h now
EOM
#
# The following steps set up basic networking for the container when booted with
# --network-veth.
#
# Needs to come before /etc/network/interfaces is created as root in target,
# i.e. before netbase is installed below.
cat <<EOM >"${T}/etc/network/interfaces"
auto lo
iface lo inet loopback
auto host0
allow-hotplug host0
iface host0 inet dhcp
EOM
fix_perms "${T}/etc/network/interfaces"
in_target <<EOF
apt-get -q update && \
apt-get -q -y install dhcp3-client net-tools ifupdown netbase
EOF
# dhclient remembering its lease is counter-productive, this forces it to always do
# a DHCPDISCOVER on host0.
ln -sf /dev/null "${T}/var/lib/dhcp3/dhclient.host0.leases"
fix_perms "${T}/var/lib/dhcp3/dhclient.host0.leases"
#
# From here on it's all application-dependent. You can use in_target + apt-get
# to install the LAMP stack, and it's configuration files.
#
# To actually access the application code, I use --bind-ro= to bind-mount a Git
# checkout from the host into the container's /var/www.
#
# Have fun!
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment