From c399908bc9751a2d2431e7aeea410dfaa0fb3c2e Mon Sep 17 00:00:00 2001 From: Jan Dubois Date: Fri, 24 May 2024 20:20:21 -0700 Subject: [PATCH 1/3] Exit early when not running from a ramdisk There is no point in creating the mnt.sh script if it is never called. Most of the diff is just whitespace changes because the indentation level of most of the file has been reduced. Signed-off-by: Jan Dubois --- .../boot/04-persistent-data-volume.sh | 141 +++++++++--------- 1 file changed, 70 insertions(+), 71 deletions(-) diff --git a/pkg/cidata/cidata.TEMPLATE.d/boot/04-persistent-data-volume.sh b/pkg/cidata/cidata.TEMPLATE.d/boot/04-persistent-data-volume.sh index b5353645234..072eb8a2913 100644 --- a/pkg/cidata/cidata.TEMPLATE.d/boot/04-persistent-data-volume.sh +++ b/pkg/cidata/cidata.TEMPLATE.d/boot/04-persistent-data-volume.sh @@ -6,6 +6,9 @@ set -eux -o pipefail # Restrict the rest of this script to Alpine until it has been tested with other distros test -f /etc/alpine-release || exit 0 +# Nothing to do unless we are running from a ramdisk +[ "$(awk '$2 == "/" {print $3}' /proc/mounts)" != "tmpfs" ] && exit 0 + # Data directories that should be persisted across reboots DATADIRS="/etc /home /root /tmp /usr/local /var/lib" @@ -39,82 +42,78 @@ for DIR in ${DATADIRS}; do done chmod +x /mnt.sh -# When running from RAM try to move persistent data to data-volume -# FIXME: the test for tmpfs mounts is probably Alpine-specific -if [ "$(awk '$2 == "/" {print $3}' /proc/mounts)" == "tmpfs" ]; then - mkdir -p /mnt/data - if [ -e /dev/disk/by-label/data-volume ]; then - # Find which disk is data volume on - DATA_DISK=$(blkid | grep "data-volume" | awk '{split($0,s,":"); sub(/\d$/, "", s[1]); print s[1]};') - # growpart command may be missing in older VMs - if command -v growpart >/dev/null 2>&1 && command -v resize2fs >/dev/null 2>&1; then - # Automatically expand the data volume filesystem - growpart "$DATA_DISK" 1 || true - # Only resize when filesystem is in a healthy state - if e2fsck -f -p /dev/disk/by-label/data-volume; then - resize2fs /dev/disk/by-label/data-volume || true - fi - fi - # Mount data volume - mount -t ext4 /dev/disk/by-label/data-volume /mnt/data - # Update /etc files that might have changed during this boot - cp /etc/network/interfaces /mnt/data/etc/network/ - cp /etc/resolv.conf /mnt/data/etc/ - if [ -f /etc/localtime ]; then - # Preserve symlink - cp -d /etc/localtime /mnt/data/etc/ - # setup-timezone copies the single zoneinfo file into /etc/zoneinfo and targets the symlink there - if [ -d /etc/zoneinfo ]; then - rm -rf /mnt/data/etc/zoneinfo - cp -r /etc/zoneinfo /mnt/data/etc - fi +mkdir -p /mnt/data +if [ -e /dev/disk/by-label/data-volume ]; then + # Find which disk is data volume on + DATA_DISK=$(blkid | grep "data-volume" | awk '{split($0,s,":"); sub(/\d$/, "", s[1]); print s[1]};') + # growpart command may be missing in older VMs + if command -v growpart >/dev/null 2>&1 && command -v resize2fs >/dev/null 2>&1; then + # Automatically expand the data volume filesystem + growpart "$DATA_DISK" 1 || true + # Only resize when filesystem is in a healthy state + if e2fsck -f -p /dev/disk/by-label/data-volume; then + resize2fs /dev/disk/by-label/data-volume || true fi - if [ -f /etc/timezone ]; then - cp /etc/timezone /mnt/data/etc/ + fi + # Mount data volume + mount -t ext4 /dev/disk/by-label/data-volume /mnt/data + # Update /etc files that might have changed during this boot + cp /etc/network/interfaces /mnt/data/etc/network/ + cp /etc/resolv.conf /mnt/data/etc/ + if [ -f /etc/localtime ]; then + # Preserve symlink + cp -d /etc/localtime /mnt/data/etc/ + # setup-timezone copies the single zoneinfo file into /etc/zoneinfo and targets the symlink there + if [ -d /etc/zoneinfo ]; then + rm -rf /mnt/data/etc/zoneinfo + cp -r /etc/zoneinfo /mnt/data/etc fi - # TODO there are probably others that should be updated as well - else - # Find an unpartitioned disk and create data-volume - DISKS=$(lsblk --list --noheadings --output name,type | awk '$2 == "disk" {print $1}') - for DISK in ${DISKS}; do - IN_USE=false - # Looking for a disk that is not mounted or partitioned - # shellcheck disable=SC2013 - for PART in $(awk '/^\/dev\// {gsub("/dev/", ""); print $1}' /proc/mounts); do - if [ "${DISK}" == "${PART}" ] || [ -e /sys/block/"${DISK}"/"${PART}" ]; then - IN_USE=true - break - fi - done - if [ "${IN_USE}" == "false" ]; then - echo 'type=83' | sfdisk --label dos /dev/"${DISK}" - PART=$(lsblk --list /dev/"${DISK}" --noheadings --output name,type | awk '$2 == "part" {print $1}') - mkfs.ext4 -L data-volume /dev/"${PART}" - mount -t ext4 /dev/disk/by-label/data-volume /mnt/data - # setup apk package cache - mkdir -p /mnt/data/apk/cache - mkdir -p /etc/apk - ln -s /mnt/data/apk/cache /etc/apk/cache - # Move all persisted directories to the data volume - for DIR in ${DATADIRS}; do - DEST="/mnt/data$(dirname "${DIR}")" - mkdir -p "${DIR}" "${DEST}" - mv "${DIR}" "${DEST}" - done - # Make sure all data moved to the persistent volume has been committed to disk - sync + fi + if [ -f /etc/timezone ]; then + cp /etc/timezone /mnt/data/etc/ + fi + # TODO there are probably others that should be updated as well +else + # Find an unpartitioned disk and create data-volume + DISKS=$(lsblk --list --noheadings --output name,type | awk '$2 == "disk" {print $1}') + for DISK in ${DISKS}; do + IN_USE=false + # Looking for a disk that is not mounted or partitioned + # shellcheck disable=SC2013 + for PART in $(awk '/^\/dev\// {gsub("/dev/", ""); print $1}' /proc/mounts); do + if [ "${DISK}" == "${PART}" ] || [ -e /sys/block/"${DISK}"/"${PART}" ]; then + IN_USE=true break fi done - fi - for DIR in ${DATADIRS}; do - if [ -d /mnt/data"${DIR}" ]; then - mkdir -p "${DIR}" - mount --bind /mnt/data"${DIR}" "${DIR}" + if [ "${IN_USE}" == "false" ]; then + echo 'type=83' | sfdisk --label dos /dev/"${DISK}" + PART=$(lsblk --list /dev/"${DISK}" --noheadings --output name,type | awk '$2 == "part" {print $1}') + mkfs.ext4 -L data-volume /dev/"${PART}" + mount -t ext4 /dev/disk/by-label/data-volume /mnt/data + # setup apk package cache + mkdir -p /mnt/data/apk/cache + mkdir -p /etc/apk + ln -s /mnt/data/apk/cache /etc/apk/cache + # Move all persisted directories to the data volume + for DIR in ${DATADIRS}; do + DEST="/mnt/data$(dirname "${DIR}")" + mkdir -p "${DIR}" "${DEST}" + mv "${DIR}" "${DEST}" + done + # Make sure all data moved to the persistent volume has been committed to disk + sync + break fi done - # Remount submounts on top of the new ${DIR} - /mnt.sh - # Reinstall packages from /mnt/data/apk/cache into the RAM disk - apk fix --no-network fi +for DIR in ${DATADIRS}; do + if [ -d /mnt/data"${DIR}" ]; then + mkdir -p "${DIR}" + mount --bind /mnt/data"${DIR}" "${DIR}" + fi +done +# Remount submounts on top of the new ${DIR} +/mnt.sh +# Reinstall packages from /mnt/data/apk/cache into the RAM disk +apk fix --no-network From 00b5d08cadeb68849bb6b402938ebbdd2af77e6e Mon Sep 17 00:00:00 2001 From: Jan Dubois Date: Fri, 24 May 2024 20:21:43 -0700 Subject: [PATCH 2/3] Make sure that sudo is installed for Alpine Because the cloud images only come with `doas`. Signed-off-by: Jan Dubois --- pkg/cidata/cidata.TEMPLATE.d/boot/10-alpine-prep.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pkg/cidata/cidata.TEMPLATE.d/boot/10-alpine-prep.sh b/pkg/cidata/cidata.TEMPLATE.d/boot/10-alpine-prep.sh index 92e8c86766b..051e9d5e72a 100644 --- a/pkg/cidata/cidata.TEMPLATE.d/boot/10-alpine-prep.sh +++ b/pkg/cidata/cidata.TEMPLATE.d/boot/10-alpine-prep.sh @@ -19,6 +19,11 @@ for REPO in main community; do fi done +# Alpine comes with doas instead of sudo +if ! command -v sudo >/dev/null 2>&1; then + apk add sudo +fi + # Alpine doesn't use PAM so we need to explicitly allow public key auth usermod -p '*' "${LIMA_CIDATA_USER}" From df69b2986a6f0928a0f3042341f04edb0483f516 Mon Sep 17 00:00:00 2001 From: Jan Dubois Date: Fri, 24 May 2024 20:24:14 -0700 Subject: [PATCH 3/3] Add alpine-image template It uses the official Alpine cloud images instead of the alpine-lima ISO. Signed-off-by: Jan Dubois --- examples/alpine-image.yaml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 examples/alpine-image.yaml diff --git a/examples/alpine-image.yaml b/examples/alpine-image.yaml new file mode 100644 index 00000000000..395c5717d48 --- /dev/null +++ b/examples/alpine-image.yaml @@ -0,0 +1,20 @@ +images: +- location: "https://dl-cdn.alpinelinux.org/alpine/v3.19/releases/cloud/nocloud_alpine-3.19.1-x86_64-bios-cloudinit-r0.qcow2" + arch: "x86_64" + digest: "sha512:f122b0e9e832cf90bda49ca73b800105ab4aa193bd340cba641e6acbda1da9aa5571de87870561380ac69bdb2dcd428590e7b4a898f7f62b559f5c12a4aefc01" +- location: "https://dl-cdn.alpinelinux.org/alpine/v3.19/releases/cloud/nocloud_alpine-3.19.1-aarch64-uefi-cloudinit-r0.qcow2" + arch: "aarch64" + digest: "sha512:d5e69cff0ecb0fd3850bd78f56f66131115934df27b2373c35a85a74b9def52822134dd43f90b4fabe239fdd4452026cb45f1c8f0b36a43af69335a26f0959b5" + +firmware: + legacyBIOS: true + +mounts: +- location: "~" +- location: "/tmp/lima" + writable: true + +# The built-in containerd installer does not support Alpine currently. +containerd: + system: false + user: false