Created
February 3, 2024 12:47
-
-
Save mato/35477cf13a68411555546f650b8a391e to your computer and use it in GitHub Desktop.
Companion script to my FOSDEM 2024 presentation
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/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