Draft for making OTA images
This commit is contained in:
@@ -50,12 +50,122 @@ rm -r "$ROOTFS/build"
|
|||||||
rm "$ROOTFS/etc/resolv.conf"
|
rm "$ROOTFS/etc/resolv.conf"
|
||||||
|
|
||||||
### Begin making full disk image for the device
|
### Begin making full disk image for the device
|
||||||
echo "##################################################### Packaging RootFS "$( du -sh "$ROOTFS/" )
|
#!/bin/bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
IMG=output.img
|
ROOTFS="${ROOTFS:?ROOTFS is required}"
|
||||||
SIZE=8GB
|
BOARD_ITB="${BOARD_ITB:-/build/board.itb}"
|
||||||
|
|
||||||
dd if=/dev/zero of="$IMG" bs=1 count=0 seek=$SIZE
|
IMG="${IMG:-output.img}"
|
||||||
|
DISK_SIZE="${DISK_SIZE:-8G}"
|
||||||
|
|
||||||
|
ROOTFS_IMG="${ROOTFS_IMG:-rootfs.ext4}"
|
||||||
|
ROOTFS_IMG_ZST="${ROOTFS_IMG_ZST:-rootfs.ext4.zst}"
|
||||||
|
ROOTFS_PART_SIZE_MIB="${ROOTFS_PART_SIZE_MIB:-2048}"
|
||||||
|
|
||||||
|
FAKE_DEV="/tmp/dev"
|
||||||
|
MNT_ROOTFS_IMG="/mnt/rootfs-img"
|
||||||
|
MNT_DATA="/mnt/data"
|
||||||
|
|
||||||
|
LOOP=""
|
||||||
|
ROOTFS_LOOP=""
|
||||||
|
TMP_LOOP=""
|
||||||
|
ROOTFS_TMP_LOOP=""
|
||||||
|
|
||||||
|
cleanup_fake_nodes() {
|
||||||
|
local prefix="$1"
|
||||||
|
[ -n "$prefix" ] || return 0
|
||||||
|
find "$FAKE_DEV" -maxdepth 1 -type b -name "${prefix}*" -exec rm -f {} \; 2>/dev/null || true
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
set +e
|
||||||
|
|
||||||
|
mountpoint -q "$MNT_ROOTFS_IMG" && umount "$MNT_ROOTFS_IMG"
|
||||||
|
mountpoint -q "$MNT_DATA" && umount "$MNT_DATA"
|
||||||
|
|
||||||
|
if [ -n "$ROOTFS_LOOP" ]; then
|
||||||
|
losetup -d "$ROOTFS_LOOP" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
if [ -n "$LOOP" ]; then
|
||||||
|
losetup -d "$LOOP" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$ROOTFS_LOOP" ]; then
|
||||||
|
cleanup_fake_nodes "$(basename "$ROOTFS_LOOP")"
|
||||||
|
fi
|
||||||
|
if [ -n "$LOOP" ]; then
|
||||||
|
cleanup_fake_nodes "$(basename "$LOOP")"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
mkdir -p "$FAKE_DEV" "$MNT_ROOTFS_IMG" "$MNT_DATA"
|
||||||
|
|
||||||
|
echo "##################################################### Packaging RootFS $(du -sh "$ROOTFS" | awk '{print $1}')"
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# 1. Build reusable rootfs ext4 image once
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
ROOTFS_BYTES=$(du -s -B1 "$ROOTFS" | awk '{print $1}')
|
||||||
|
EXTRA_BYTES=$((256 * 1024 * 1024))
|
||||||
|
IMG_BYTES=$(( ROOTFS_BYTES + ROOTFS_BYTES / 4 + EXTRA_BYTES ))
|
||||||
|
|
||||||
|
ALIGN=$((4 * 1024 * 1024))
|
||||||
|
IMG_BYTES=$(( (IMG_BYTES + ALIGN - 1) / ALIGN * ALIGN ))
|
||||||
|
|
||||||
|
MAX_BYTES=$(( ROOTFS_PART_SIZE_MIB * 1024 * 1024 ))
|
||||||
|
if [ "$IMG_BYTES" -ge "$MAX_BYTES" ]; then
|
||||||
|
echo "ERROR: estimated rootfs image size $IMG_BYTES exceeds slot size $MAX_BYTES" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -f "$ROOTFS_IMG" "$ROOTFS_IMG_ZST"
|
||||||
|
|
||||||
|
truncate -s "$IMG_BYTES" "$ROOTFS_IMG"
|
||||||
|
mkfs.ext4 -F -L rootfs "$ROOTFS_IMG"
|
||||||
|
|
||||||
|
ROOTFS_LOOP=$(losetup --find --show -P "$ROOTFS_IMG")
|
||||||
|
/sync-loop.sh "$ROOTFS_LOOP"
|
||||||
|
|
||||||
|
# For a raw ext4 image there is usually no partition, so mount the loop device directly.
|
||||||
|
mount "$ROOTFS_LOOP" "$MNT_ROOTFS_IMG"
|
||||||
|
|
||||||
|
(
|
||||||
|
cd "$ROOTFS"
|
||||||
|
tar cpf - --exclude='./var' .
|
||||||
|
) | (
|
||||||
|
cd "$MNT_ROOTFS_IMG"
|
||||||
|
tar xpf -
|
||||||
|
)
|
||||||
|
|
||||||
|
mkdir -p "$MNT_ROOTFS_IMG/var"
|
||||||
|
mkdir -p "$MNT_ROOTFS_IMG/boot"
|
||||||
|
cp "$BOARD_ITB" "$MNT_ROOTFS_IMG/boot/kernel.itb"
|
||||||
|
|
||||||
|
sync
|
||||||
|
umount "$MNT_ROOTFS_IMG"
|
||||||
|
|
||||||
|
losetup -d "$ROOTFS_LOOP"
|
||||||
|
cleanup_fake_nodes "$(basename "$ROOTFS_LOOP")"
|
||||||
|
ROOTFS_LOOP=""
|
||||||
|
|
||||||
|
e2fsck -fy "$ROOTFS_IMG"
|
||||||
|
resize2fs -M "$ROOTFS_IMG"
|
||||||
|
e2fsck -fy "$ROOTFS_IMG"
|
||||||
|
|
||||||
|
echo "##################################################### Compressing OTA Image"
|
||||||
|
zstd -19 -T0 -f "$ROOTFS_IMG" -o "$ROOTFS_IMG_ZST"
|
||||||
|
sha256sum "$ROOTFS_IMG" > "$ROOTFS_IMG.sha256"
|
||||||
|
sha256sum "$ROOTFS_IMG_ZST" > "$ROOTFS_IMG_ZST.sha256"
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# 2. Build full disk image
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
rm -f "$IMG"
|
||||||
|
truncate -s "$DISK_SIZE" "$IMG"
|
||||||
|
|
||||||
sgdisk -o "$IMG" \
|
sgdisk -o "$IMG" \
|
||||||
-n 1:2048:+64M -t 1:0700 -c 1:config \
|
-n 1:2048:+64M -t 1:0700 -c 1:config \
|
||||||
@@ -65,38 +175,38 @@ sgdisk -o "$IMG" \
|
|||||||
|
|
||||||
losetup -D
|
losetup -D
|
||||||
LOOP=$(losetup --find --show -P "$IMG")
|
LOOP=$(losetup --find --show -P "$IMG")
|
||||||
|
|
||||||
/sync-loop.sh "$LOOP"
|
/sync-loop.sh "$LOOP"
|
||||||
|
|
||||||
TMP_LOOP="/tmp$LOOP"
|
TMP_LOOP="$FAKE_DEV/$(basename "$LOOP")"
|
||||||
|
|
||||||
mkfs.vfat -F 32 -n MONOK8S_CFG "${TMP_LOOP}p1"
|
mkfs.vfat -F 32 -n MONOK8S_CFG "${TMP_LOOP}p1"
|
||||||
mkfs.ext4 -F "${TMP_LOOP}p2"
|
mkfs.ext4 -F -L rootfsB "${TMP_LOOP}p3"
|
||||||
mkfs.ext4 -F "${TMP_LOOP}p3"
|
mkfs.ext4 -F -L data "${TMP_LOOP}p4"
|
||||||
mkfs.ext4 -F "${TMP_LOOP}p4"
|
|
||||||
|
|
||||||
mkdir -p /mnt/img-root /mnt/data
|
dd if="$ROOTFS_IMG" of="${TMP_LOOP}p2" bs=4M conv=fsync
|
||||||
|
|
||||||
mount "${TMP_LOOP}p2" /mnt/img-root
|
# Grow each filesystem to fill its partition
|
||||||
mount "${TMP_LOOP}p4" /mnt/data
|
e2fsck -fy "${TMP_LOOP}p2"
|
||||||
|
resize2fs "${TMP_LOOP}p2"
|
||||||
|
|
||||||
# Put the real /var onto the data partition
|
# Populate data partition
|
||||||
cp -a "$ROOTFS/var" /mnt/data/
|
mount "${TMP_LOOP}p4" "$MNT_DATA"
|
||||||
mkdir -p /mnt/data/etc-overlay/work
|
|
||||||
mkdir -p /mnt/data/etc-overlay/upper
|
|
||||||
|
|
||||||
# Copy rootfs to root partition, but exclude /var
|
cp -a "$ROOTFS/var" "$MNT_DATA/"
|
||||||
cp -a "$ROOTFS"/. /mnt/img-root/
|
mkdir -p "$MNT_DATA/etc-overlay/work"
|
||||||
rm -rf /mnt/img-root/var
|
mkdir -p "$MNT_DATA/etc-overlay/upper"
|
||||||
mkdir -p /mnt/img-root/var
|
|
||||||
|
|
||||||
mkdir -p /mnt/img-root/boot
|
|
||||||
cp /build/board.itb /mnt/img-root/boot/kernel.itb
|
|
||||||
|
|
||||||
sync
|
sync
|
||||||
umount /mnt/img-root
|
umount "$MNT_DATA"
|
||||||
umount /mnt/data
|
|
||||||
|
|
||||||
losetup -d "$LOOP"
|
losetup -d "$LOOP"
|
||||||
|
cleanup_fake_nodes "$(basename "$LOOP")"
|
||||||
|
LOOP=""
|
||||||
|
|
||||||
echo "##################################################### Compressing Image"
|
echo "Built artifacts:"
|
||||||
|
echo " Full disk image: $IMG"
|
||||||
|
echo " Rootfs OTA image: $ROOTFS_IMG"
|
||||||
|
echo " Rootfs OTA compressed: $ROOTFS_IMG_ZST"
|
||||||
|
|
||||||
|
echo "##################################################### Compressing Full Disk Image"
|
||||||
gzip "/build/$IMG"
|
gzip "/build/$IMG"
|
||||||
|
|||||||
@@ -1,21 +1,29 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
DEVICE="$1"
|
DEVICE="$1"
|
||||||
FAKE_DEV="/tmp/dev"
|
FAKE_DEV="/tmp/dev"
|
||||||
|
|
||||||
mkdir -p "$FAKE_DEV"
|
mkdir -p "$FAKE_DEV"
|
||||||
|
PARENT_NAME=$(basename "$DEVICE")
|
||||||
|
|
||||||
echo "Refreshing partition table..."
|
echo "Refreshing partition table for $DEVICE..."
|
||||||
partx -u "$DEVICE" 2>/dev/null || partx -a "$DEVICE"
|
partx -u "$DEVICE" 2>/dev/null || partx -a "$DEVICE" || true
|
||||||
|
|
||||||
|
# Remove old fake nodes for this loop device first
|
||||||
|
find "$FAKE_DEV" -maxdepth 1 -type b -name "${PARENT_NAME}*" -exec rm -f {} \;
|
||||||
|
|
||||||
# Find partitions and their Major:Minor numbers
|
|
||||||
lsblk -rn -o NAME,MAJ:MIN "$DEVICE" | while read -r NAME MAJMIN; do
|
lsblk -rn -o NAME,MAJ:MIN "$DEVICE" | while read -r NAME MAJMIN; do
|
||||||
# Skip the parent loop0
|
# Skip the parent loop device itself
|
||||||
if [[ "$NAME" == "loop0" ]]; then continue; fi
|
if [[ "$NAME" == "$PARENT_NAME" ]]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
PART_PATH="$FAKE_DEV/$NAME"
|
PART_PATH="$FAKE_DEV/$NAME"
|
||||||
MAJOR=$(echo $MAJMIN | cut -d: -f1)
|
MAJOR="${MAJMIN%%:*}"
|
||||||
MINOR=$(echo $MAJMIN | cut -d: -f2)
|
MINOR="${MAJMIN##*:}"
|
||||||
|
|
||||||
echo "Creating node: $PART_PATH (b $MAJOR $MINOR)"
|
echo "Creating node: $PART_PATH (b $MAJOR $MINOR)"
|
||||||
|
rm -f "$PART_PATH"
|
||||||
mknod "$PART_PATH" b "$MAJOR" "$MINOR"
|
mknod "$PART_PATH" b "$MAJOR" "$MINOR"
|
||||||
done
|
done
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
ARG TAG=dev
|
ARG BUILD_BASE_TAG=dev
|
||||||
ARG DOCKER_IMAGE_ROOT=monok8s
|
ARG DOCKER_IMAGE_ROOT=monok8s
|
||||||
|
|
||||||
FROM --platform=$BUILDPLATFORM ${DOCKER_IMAGE_ROOT}/build-base:${TAG} AS build-base
|
FROM --platform=$BUILDPLATFORM ${DOCKER_IMAGE_ROOT}/build-base:${BUILD_BASE_TAG} AS build-base
|
||||||
|
|
||||||
ARG TAG
|
ARG TAG
|
||||||
ARG ALPINE_ARCH
|
ARG ALPINE_ARCH
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|||||||
pahole \
|
pahole \
|
||||||
parted \
|
parted \
|
||||||
perl \
|
perl \
|
||||||
|
pv \
|
||||||
python3 \
|
python3 \
|
||||||
qemu-user-static \
|
qemu-user-static \
|
||||||
podman \
|
podman \
|
||||||
@@ -36,6 +37,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|||||||
tar \
|
tar \
|
||||||
udev \
|
udev \
|
||||||
xz-utils \
|
xz-utils \
|
||||||
|
zstd \
|
||||||
dwarves \
|
dwarves \
|
||||||
gcc-aarch64-linux-gnu \
|
gcc-aarch64-linux-gnu \
|
||||||
binutils-aarch64-linux-gnu \
|
binutils-aarch64-linux-gnu \
|
||||||
|
|||||||
6
makefile
6
makefile
@@ -39,6 +39,7 @@ BUILD_VERSION ?= $(KUBE_VERSION)
|
|||||||
BUILD_DATE := $(shell date -u +%Y-%m-%dT%H:%M:%SZ)
|
BUILD_DATE := $(shell date -u +%Y-%m-%dT%H:%M:%SZ)
|
||||||
BUILD_GIT := $(shell git rev-parse --short HEAD 2>/dev/null || echo unknown)
|
BUILD_GIT := $(shell git rev-parse --short HEAD 2>/dev/null || echo unknown)
|
||||||
BUILD_INFO_FILE := $(OUT_DIR)/build-info
|
BUILD_INFO_FILE := $(OUT_DIR)/build-info
|
||||||
|
BUILD_BASE_TAG := $(shell docker image inspect monok8s/build-base:dev | jq -r '.[].Id' | cut -d':' -f2 | cut -c -8 || echo dev)
|
||||||
|
|
||||||
# ---- File groups -------------------------------------------------------------
|
# ---- File groups -------------------------------------------------------------
|
||||||
|
|
||||||
@@ -148,6 +149,8 @@ $(BUILD_BASE_STAMP): $(BUILD_BASE_DEPS) | $(OUT_DIR)
|
|||||||
-f docker/build-base.Dockerfile \
|
-f docker/build-base.Dockerfile \
|
||||||
--build-arg TAG=$(TAG) \
|
--build-arg TAG=$(TAG) \
|
||||||
-t $(DOCKER_IMAGE_ROOT)/build-base:$(TAG) .
|
-t $(DOCKER_IMAGE_ROOT)/build-base:$(TAG) .
|
||||||
|
@iid=$$(docker image inspect monok8s/build-base:$(TAG) | jq -r '.[].Id' | cut -d':' -f2 | cut -c -8); \
|
||||||
|
docker tag monok8s/build-base:$(TAG) monok8s/build-base:$$iid; \
|
||||||
touch $@
|
touch $@
|
||||||
|
|
||||||
$(KERNEL_IMAGE): $(KERNEL_DEPS) | $(OUT_DIR)
|
$(KERNEL_IMAGE): $(KERNEL_DEPS) | $(OUT_DIR)
|
||||||
@@ -191,6 +194,7 @@ $(BOARD_ITB): $(ITB_DEPS) | $(OUT_DIR)
|
|||||||
$(RELEASE_IMAGE): $(RELEASE_DEPS) | $(OUT_DIR)
|
$(RELEASE_IMAGE): $(RELEASE_DEPS) | $(OUT_DIR)
|
||||||
docker build \
|
docker build \
|
||||||
-f docker/alpine.Dockerfile \
|
-f docker/alpine.Dockerfile \
|
||||||
|
--no-cache \
|
||||||
--build-arg DOCKER_IMAGE_ROOT=$(DOCKER_IMAGE_ROOT) \
|
--build-arg DOCKER_IMAGE_ROOT=$(DOCKER_IMAGE_ROOT) \
|
||||||
--build-arg TAG=$(TAG) \
|
--build-arg TAG=$(TAG) \
|
||||||
--build-arg ALPINE_ARCH=$(ALPINE_ARCH) \
|
--build-arg ALPINE_ARCH=$(ALPINE_ARCH) \
|
||||||
@@ -198,6 +202,7 @@ $(RELEASE_IMAGE): $(RELEASE_DEPS) | $(OUT_DIR)
|
|||||||
--build-arg KUBE_VERSION=$(KUBE_VERSION) \
|
--build-arg KUBE_VERSION=$(KUBE_VERSION) \
|
||||||
--build-arg CRIO_VERSION=$(CRIO_VERSION) \
|
--build-arg CRIO_VERSION=$(CRIO_VERSION) \
|
||||||
--build-arg DEVICE_TREE_TARGET=$(DEVICE_TREE_TARGET) \
|
--build-arg DEVICE_TREE_TARGET=$(DEVICE_TREE_TARGET) \
|
||||||
|
--build-arg BUILD_BASE_TAG=$(BUILD_BASE_TAG) \
|
||||||
-t $(DOCKER_IMAGE_ROOT)/buildenv-alpine:$(TAG) .
|
-t $(DOCKER_IMAGE_ROOT)/buildenv-alpine:$(TAG) .
|
||||||
|
|
||||||
@cid=$$(docker create \
|
@cid=$$(docker create \
|
||||||
@@ -219,6 +224,7 @@ $(RELEASE_IMAGE): $(RELEASE_DEPS) | $(OUT_DIR)
|
|||||||
bash -lc '/build-rootfs.sh'); \
|
bash -lc '/build-rootfs.sh'); \
|
||||||
docker start -a $$cid; \
|
docker start -a $$cid; \
|
||||||
docker cp $$cid:/build/output.img.gz $@; \
|
docker cp $$cid:/build/output.img.gz $@; \
|
||||||
|
docker cp $$cid:/build/rootfs.ext4.zst $(OUT_DIR)/rootfs.ext4.zst; \
|
||||||
docker rm $$cid
|
docker rm $$cid
|
||||||
|
|
||||||
test -f $@
|
test -f $@
|
||||||
|
|||||||
Reference in New Issue
Block a user