penguin/monok8s

k8s image for Mono Gateway Dev Kit

commit aa57177db0bc4014f5d0f77e844429b2a778e377f3432068ef294ec925e29b75

author斟酌 鵬兄 <tgckpg@gmail.com>
date2026-04-27T15:58:56Z
subjectEnsure loop ready
commit aa57177db0bc4014f5d0f77e844429b2a778e377f3432068ef294ec925e29b75
Author: 斟酌 鵬兄 <tgckpg@gmail.com>
Date:   2026-04-27T15:58:56Z

    Ensure loop ready
---
 README.md              | 14 +++++++++++++
 alpine/build-rootfs.sh |  4 ++++
 alpine/utils.sh        | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 75 insertions(+)

diff --git a/README.md b/README.md
index 3c2ef7c..3b6c36a 100644
--- a/README.md
+++ b/README.md
@@ -59,6 +59,20 @@ Prerequisites
 make release
 ```
 
+### Common issues
+If you have encounter this error during build
+```
+chroot: failed to run command '/bin/sh': Exec format error
+```
+
+You need to install support for amd64 emulation
+
+For Debian
+``bash
+apt-get install -y qemu-user-static binfmt-support
+```
+
+### cluster-config
 The default configuration will boot as a first time control-plane.
 
 For control-plane
diff --git a/alpine/build-rootfs.sh b/alpine/build-rootfs.sh
index db78031..734efa6 100755
--- a/alpine/build-rootfs.sh
+++ b/alpine/build-rootfs.sh
@@ -2,6 +2,8 @@
 
 set -euo pipefail
 
+source /utils.sh
+
 /preload-k8s-images.sh || exit 1
 
 export CTL_BIN_LAYER=$( skopeo inspect docker-daemon:localhost/monok8s/node-control:dev | jq -r '.Layers[0] | sub("^sha256:"; "")' )
@@ -197,6 +199,8 @@ sgdisk -o "$IMG" \
   -n 3:0:+2560M   -t 3:8300 -c 3:rootfsB \
   -n 4:0:0        -t 4:8300 -c 4:data
 
+ensure_loop_ready
+
 losetup -D
 LOOP=$(losetup --find --show -P "$IMG")
 /sync-loop.sh "$LOOP"
diff --git a/alpine/utils.sh b/alpine/utils.sh
new file mode 100755
index 0000000..6d98989
--- /dev/null
+++ b/alpine/utils.sh
@@ -0,0 +1,57 @@
+#!/bin/bash
+
+ensure_loop_ready() {
+    # The loop kernel module is host-side. This only works if the container
+    # has permission and modprobe exists; otherwise the host must load it.
+    if ! grep -qw loop /proc/modules 2>/dev/null; then
+        modprobe loop 2>/dev/null || true
+    fi
+
+    # /dev/loop-control: char device 10:237
+    if [ ! -e /dev/loop-control ]; then
+        echo "Creating missing /dev/loop-control" >&2
+        mknod /dev/loop-control c 10 237 || {
+            echo "ERROR: cannot create /dev/loop-control" >&2
+            echo "Run container with --privileged, or pass --device=/dev/loop-control and loop devices." >&2
+            exit 1
+        }
+        chmod 600 /dev/loop-control || true
+    fi
+
+    if [ ! -c /dev/loop-control ]; then
+        echo "ERROR: /dev/loop-control exists but is not a character device" >&2
+        ls -l /dev/loop-control >&2 || true
+        exit 1
+    fi
+
+    # Create a reasonable pool of loop block devices.
+    # loopN block devices are major 7, minor N.
+    for i in $(seq 0 31); do
+        if [ ! -e "/dev/loop$i" ]; then
+            echo "Creating missing /dev/loop$i" >&2
+            mknod "/dev/loop$i" b 7 "$i" || {
+                echo "ERROR: cannot create /dev/loop$i" >&2
+                echo "Run container with --privileged, or pre-create/pass loop devices." >&2
+                exit 1
+            }
+            chmod 660 "/dev/loop$i" || true
+        fi
+
+        if [ ! -b "/dev/loop$i" ]; then
+            echo "ERROR: /dev/loop$i exists but is not a block device" >&2
+            ls -l "/dev/loop$i" >&2 || true
+            exit 1
+        fi
+    done
+
+    # Smoke test: ask losetup for a free loop device.
+    if ! losetup -f >/dev/null 2>&1; then
+        echo "ERROR: losetup cannot find/use a loop device" >&2
+        echo "Debug info:" >&2
+        ls -l /dev/loop-control /dev/loop* >&2 || true
+        grep -w loop /proc/modules >&2 || true
+        echo >&2
+        echo "Docker likely needs --privileged, or at minimum CAP_SYS_ADMIN plus loop devices." >&2
+        exit 1
+    fi
+}