fix: macOS dev VM, CA certs, DNS fallback, Portainer Edge integration
- dev-vm.sh: rewrite for macOS (bsdtar ISO extraction, Homebrew mkfs.ext4 detection, direct kernel boot, TCG acceleration, port 8080 forwarding) - inject-kubesolo.sh: add CA certificates bundle from builder so containerd can verify TLS when pulling from registries (Docker Hub, etc.) - 50-network.sh: add DNS fallback (10.0.2.3 + 8.8.8.8) when DHCP client doesn't populate /etc/resolv.conf - 90-kubesolo.sh: serve kubeconfig via HTTP on port 8080 for reliable retrieval from host, add 127.0.0.1 and 10.0.2.15 to API server SANs - portainer.go: add headless Service to Edge Agent manifest (required for agent peer discovery DNS lookup) - 10-parse-cmdline.sh + init.sh: add kubesolo.edge_id/edge_key boot params - 20-persistent-mount.sh: auto-format unformatted data disks on first boot - hack/fix-portainer-service.sh: helper to patch running cluster Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
120
hack/dev-vm.sh
120
hack/dev-vm.sh
@@ -1,24 +1,29 @@
|
||||
#!/bin/bash
|
||||
# dev-vm.sh — Launch a QEMU VM for development and testing
|
||||
# Usage: ./hack/dev-vm.sh [path-to-iso-or-img] [--shell] [--debug]
|
||||
#
|
||||
# Works on both Linux (with KVM) and macOS (TCG emulation).
|
||||
# On macOS/Apple Silicon, x86_64 guests run under TCG (~5-15x slower than KVM).
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
VERSION="$(cat "$PROJECT_ROOT/VERSION")"
|
||||
ROOTFS_DIR="${ROOTFS_DIR:-$PROJECT_ROOT/build/rootfs-work}"
|
||||
DEFAULT_ISO="$PROJECT_ROOT/output/kubesolo-os-${VERSION}.iso"
|
||||
DEFAULT_IMG="$PROJECT_ROOT/output/kubesolo-os-${VERSION}.img"
|
||||
|
||||
IMAGE="${1:-}"
|
||||
IMAGE=""
|
||||
EXTRA_APPEND=""
|
||||
SERIAL_OPTS="-serial stdio"
|
||||
|
||||
# Parse flags
|
||||
shift || true
|
||||
# Parse all arguments — flags and optional image path
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--shell) EXTRA_APPEND="$EXTRA_APPEND kubesolo.shell" ;;
|
||||
--debug) EXTRA_APPEND="$EXTRA_APPEND kubesolo.debug" ;;
|
||||
--shell) EXTRA_APPEND="$EXTRA_APPEND kubesolo.shell" ;;
|
||||
--debug) EXTRA_APPEND="$EXTRA_APPEND kubesolo.debug" ;;
|
||||
--edge-id=*) EXTRA_APPEND="$EXTRA_APPEND kubesolo.edge_id=${arg#--edge-id=}" ;;
|
||||
--edge-key=*) EXTRA_APPEND="$EXTRA_APPEND kubesolo.edge_key=${arg#--edge-key=}" ;;
|
||||
*) IMAGE="$arg" ;;
|
||||
esac
|
||||
done
|
||||
|
||||
@@ -39,42 +44,103 @@ echo "==> Launching QEMU with: $IMAGE"
|
||||
echo " Press Ctrl+A, X to exit"
|
||||
echo ""
|
||||
|
||||
# Create a temporary data disk for persistence testing
|
||||
DATA_DISK=$(mktemp /tmp/kubesolo-data-XXXXXX.img)
|
||||
dd if=/dev/zero of="$DATA_DISK" bs=1M count=1024 2>/dev/null
|
||||
mkfs.ext4 -q -L KSOLODATA "$DATA_DISK" 2>/dev/null
|
||||
DATA_APPEND=""
|
||||
DATA_DISK=""
|
||||
|
||||
cleanup() { rm -f "$DATA_DISK"; }
|
||||
# Find mkfs.ext4 (Homebrew on macOS installs to a non-PATH location)
|
||||
MKFS_EXT4=""
|
||||
if command -v mkfs.ext4 >/dev/null 2>&1; then
|
||||
MKFS_EXT4="mkfs.ext4"
|
||||
elif [ -x "/opt/homebrew/opt/e2fsprogs/sbin/mkfs.ext4" ]; then
|
||||
MKFS_EXT4="/opt/homebrew/opt/e2fsprogs/sbin/mkfs.ext4"
|
||||
elif [ -x "/usr/local/opt/e2fsprogs/sbin/mkfs.ext4" ]; then
|
||||
MKFS_EXT4="/usr/local/opt/e2fsprogs/sbin/mkfs.ext4"
|
||||
fi
|
||||
|
||||
# Create and attach a formatted data disk for persistent K8s state.
|
||||
if [ -n "$MKFS_EXT4" ]; then
|
||||
DATA_DISK="$(mktemp /tmp/kubesolo-data-XXXXXX).img"
|
||||
dd if=/dev/zero of="$DATA_DISK" bs=1M count=2048 2>/dev/null
|
||||
"$MKFS_EXT4" -q -L KSOLODATA "$DATA_DISK" 2>/dev/null
|
||||
DATA_APPEND="kubesolo.data=/dev/vda"
|
||||
echo " Data disk: 2 GB ext4 (persistent)"
|
||||
else
|
||||
echo "ERROR: mkfs.ext4 not found. Install e2fsprogs:"
|
||||
echo " brew install e2fsprogs"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
EXTRACT_DIR=""
|
||||
|
||||
cleanup() {
|
||||
[ -n "$DATA_DISK" ] && rm -f "$DATA_DISK" "${DATA_DISK%.img}"
|
||||
[ -n "$EXTRACT_DIR" ] && rm -rf "$EXTRACT_DIR"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
COMMON_OPTS=(
|
||||
-m 2048
|
||||
-smp 2
|
||||
-nographic
|
||||
-net nic,model=virtio
|
||||
-net user,hostfwd=tcp::6443-:6443,hostfwd=tcp::2222-:22
|
||||
-drive "file=$DATA_DISK,format=raw,if=virtio"
|
||||
)
|
||||
# Build QEMU command
|
||||
QEMU_ARGS=(-m 2048 -smp 2 -nographic -cpu max)
|
||||
QEMU_ARGS+=(-net nic,model=virtio)
|
||||
QEMU_ARGS+=(-net user,hostfwd=tcp::6443-:6443,hostfwd=tcp::2222-:22,hostfwd=tcp::8080-:8080)
|
||||
|
||||
# Enable KVM if available
|
||||
if [ -n "$DATA_DISK" ]; then
|
||||
QEMU_ARGS+=(-drive "file=$DATA_DISK,format=raw,if=virtio")
|
||||
fi
|
||||
|
||||
# Enable KVM on Linux, fall back to TCG everywhere else
|
||||
if [ -w /dev/kvm ] 2>/dev/null; then
|
||||
COMMON_OPTS+=(-enable-kvm)
|
||||
QEMU_ARGS+=(-accel kvm)
|
||||
echo " KVM acceleration: enabled"
|
||||
else
|
||||
echo " KVM acceleration: not available (using TCG)"
|
||||
QEMU_ARGS+=(-accel tcg)
|
||||
echo " TCG emulation (no KVM — expect slower boot)"
|
||||
fi
|
||||
|
||||
case "$IMAGE" in
|
||||
*.iso)
|
||||
# -append only works with -kernel, not -cdrom.
|
||||
# Extract kernel + initramfs and use direct kernel boot.
|
||||
VMLINUZ=""
|
||||
INITRAMFS=""
|
||||
|
||||
# Prefer build artifacts if present (no extraction needed)
|
||||
if [ -f "$ROOTFS_DIR/vmlinuz" ] && [ -f "$ROOTFS_DIR/kubesolo-os.gz" ]; then
|
||||
VMLINUZ="$ROOTFS_DIR/vmlinuz"
|
||||
INITRAMFS="$ROOTFS_DIR/kubesolo-os.gz"
|
||||
echo " Using kernel/initramfs from build directory"
|
||||
else
|
||||
# Extract from ISO using bsdtar (works on macOS + Linux, no mount needed)
|
||||
EXTRACT_DIR="$(mktemp -d /tmp/kubesolo-extract-XXXXXX)"
|
||||
|
||||
echo " Extracting kernel/initramfs from ISO..."
|
||||
bsdtar -xf "$IMAGE" -C "$EXTRACT_DIR" boot/vmlinuz boot/kubesolo-os.gz 2>/dev/null || {
|
||||
echo "ERROR: Failed to extract kernel/initramfs from ISO."
|
||||
echo " Ensure bsdtar is available (ships with macOS, install libarchive on Linux)."
|
||||
echo " Or run 'make rootfs initramfs' to produce build artifacts."
|
||||
exit 1
|
||||
}
|
||||
|
||||
VMLINUZ="$EXTRACT_DIR/boot/vmlinuz"
|
||||
INITRAMFS="$EXTRACT_DIR/boot/kubesolo-os.gz"
|
||||
|
||||
if [ ! -f "$VMLINUZ" ] || [ ! -f "$INITRAMFS" ]; then
|
||||
echo "ERROR: ISO does not contain expected boot/vmlinuz and boot/kubesolo-os.gz"
|
||||
echo " ISO contents:"
|
||||
bsdtar -tf "$IMAGE" 2>/dev/null || true
|
||||
exit 1
|
||||
fi
|
||||
echo " Extracted kernel/initramfs from ISO"
|
||||
fi
|
||||
|
||||
qemu-system-x86_64 \
|
||||
"${COMMON_OPTS[@]}" \
|
||||
-cdrom "$IMAGE" \
|
||||
-boot d \
|
||||
-append "console=ttyS0,115200n8 kubesolo.data=/dev/vda $EXTRA_APPEND"
|
||||
"${QEMU_ARGS[@]}" \
|
||||
-kernel "$VMLINUZ" \
|
||||
-initrd "$INITRAMFS" \
|
||||
-append "console=ttyS0,115200n8 $DATA_APPEND $EXTRA_APPEND"
|
||||
;;
|
||||
*.img)
|
||||
qemu-system-x86_64 \
|
||||
"${COMMON_OPTS[@]}" \
|
||||
"${QEMU_ARGS[@]}" \
|
||||
-drive "file=$IMAGE,format=raw,if=virtio"
|
||||
;;
|
||||
*)
|
||||
|
||||
48
hack/fix-portainer-service.sh
Executable file
48
hack/fix-portainer-service.sh
Executable file
@@ -0,0 +1,48 @@
|
||||
#!/bin/bash
|
||||
# fix-portainer-service.sh — Create the missing headless Service for Portainer agent
|
||||
# Usage: ./hack/fix-portainer-service.sh
|
||||
#
|
||||
# The Portainer agent does a DNS lookup for "portainer-agent" to discover peers.
|
||||
# Without a Service, this lookup fails and the agent crashes.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
KUBECONFIG_URL="http://localhost:8080"
|
||||
|
||||
echo "==> Fetching kubeconfig from $KUBECONFIG_URL..."
|
||||
KUBECONFIG_FILE=$(mktemp)
|
||||
trap 'rm -f "$KUBECONFIG_FILE"' EXIT
|
||||
|
||||
curl -s "$KUBECONFIG_URL" > "$KUBECONFIG_FILE"
|
||||
|
||||
if [ ! -s "$KUBECONFIG_FILE" ]; then
|
||||
echo "ERROR: Failed to fetch kubeconfig. Is the VM running?"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "==> Creating headless Service for portainer-agent..."
|
||||
kubectl --kubeconfig "$KUBECONFIG_FILE" apply -f - <<'EOF'
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: portainer-agent
|
||||
namespace: portainer
|
||||
spec:
|
||||
clusterIP: None
|
||||
selector:
|
||||
app: portainer-agent
|
||||
ports:
|
||||
- name: agent
|
||||
port: 9001
|
||||
targetPort: 9001
|
||||
protocol: TCP
|
||||
EOF
|
||||
|
||||
echo "==> Restarting portainer-agent deployment..."
|
||||
kubectl --kubeconfig "$KUBECONFIG_FILE" rollout restart -n portainer deployment/portainer-agent
|
||||
|
||||
echo "==> Waiting for rollout..."
|
||||
kubectl --kubeconfig "$KUBECONFIG_FILE" rollout status -n portainer deployment/portainer-agent --timeout=120s
|
||||
|
||||
echo "==> Done. Checking pod status:"
|
||||
kubectl --kubeconfig "$KUBECONFIG_FILE" get pods -n portainer
|
||||
Reference in New Issue
Block a user