주요 콘텐츠로 건너뛰기

왜 SWUpdate?

현장 업데이트는 불가피합니다. SWUpdate 는 펌웨어, 루트 파일 시스템, 애플리케이션 레이어를 업데이트할 수 있는 강력한 모듈식 솔루션을 제공하며, 모두 롤백 기능이 내장되어 있습니다.
오픈 소스이며 문서화가 잘 되어 있고 A/B 파티션 레이아웃과 원활하게 통합됩니다.

웹 브라우저 GUI SWUpdate

아키텍처 개요

SWUpdate 은 몇 가지 주요 구성 요소로 이루어져 있습니다:

  • 업데이트 데몬(swupdate) - 장치에서 실행되어 업데이트를 적용합니다.
  • 업데이트 핸들러 - 업데이트할 대상(rootfs, 파일, 스크립트 등)을 정의합니다.
  • 클라이언트 인터페이스 - 웹 인터페이스, REST API 또는 로컬 CLI
  • sw-description 파일 - 업데이트 패키지의 구조와 로직을 정의합니다.

업데이트 흐름 예시

  1. 다음이 포함된 업데이트 패키지(.swu)를 빌드합니다:
    • 새 루트 파일시스템 이미지
    • 새 루트 파일시스템 이미지 sw-description 파일
    • 선택적 스크립트(사용자 지정 또는 확인용)
      2.swupdate 정의된 장치에 업데이트를 씁니다.
  2. 업데이트 후 스크립트가 성공 여부를 확인하거나 필요한 경우 롤백을 트리거합니다.

이 예제에서는 공식 Raspberry Pi OS 트릭시 이미지를 두 개의 파일로 분할했습니다:

  • 2025-10-01-raspios-trixie-arm64.boot.vfat
  • 2025-10-01-raspios-trixie-arm64.root.ext4

이 파일은 sw-description 파일에서 참조하여 .swu 패키지를 생성합니다:

software =
{
    version = "0.1.0";
    description = "Firmware update for XXXXX Project";

    hardware-compatibility: [ "1.0", "1.2", "1.3"];

    images: (
        {
            filename = "2025-10-01-raspios-trixie-arm64.boot.vfat";
            device = "/dev/mmcblk0p1";
            compressed = "zlib";
            installed-directly = true;
        },
        {
            filename = "2025-10-01-raspios-trixie-arm64.root.ext4";
            device = "/dev/mmcblk0p2";
            compressed = "zlib";
            installed-directly = true;
        }
    );

    scripts: (
        {
          type: "lua",
          filename: "repair-disk-uuid.lua"
        }
    ),
}

다음 Lua 스크립트는 파티션 UUID를 조정합니다. cmdline.txtfstab 를 플래시합니다:

#!/usr/bin/lua

-- helper: run shell command and capture output
function run(cmd)
  local f = io.popen(cmd)
  local out = f:read("*a")
  f:close()
  return (out:gsub("%s+$", ""))
end

-- detect PARTUUIDs
local root_part = "/dev/mmcblk0p2"
local boot_part = "/dev/mmcblk0p1"
local root_uuid = run("blkid -s PARTUUID -o value " .. root_part)
local boot_uuid = run("blkid -s PARTUUID -o value " .. boot_part)

print("Rootfs PARTUUID: " .. root_uuid)
print("Boot   PARTUUID: " .. boot_uuid)

-- mount points
os.execute("mkdir -p /mnt/root /mnt/boot")
os.execute("mount " .. root_part .. " /mnt/root")
os.execute("mount " .. boot_part .. " /mnt/boot")

-- update cmdline.txt
local cmdline_path = "/mnt/boot/cmdline.txt"
local file = io.open(cmdline_path, "r")
local text = file:read("*a")
file:close()

text = text:gsub("root=PARTUUID=[^ ]+", "root=PARTUUID=" .. root_uuid)

file = io.open(cmdline_path, "w")
file:write(text)
file:close()

-- update /etc/fstab
local fstab_path = "/mnt/root/etc/fstab"
local fstab = io.open(fstab_path, "r")
local content = fstab:read("*a")
fstab:close()

-- replace root line
content = content:gsub("PARTUUID=[^%s]+%s+/%s", "PARTUUID=" .. root_uuid .. " /")
-- replace boot line (/boot or /boot/firmware)
content = content:gsub("PARTUUID=[^%s]+%s+/boot", "PARTUUID=" .. boot_uuid .. " /boot")

fstab = io.open(fstab_path, "w")
fstab:write(content)
fstab:close()

os.execute("sync")
os.execute("umount /mnt/boot")
os.execute("umount /mnt/root")

print("All PARTUUIDs updated successfully.")

사용 swugenerator 를 사용하여 업데이트:(https://github.com/sbabic/swugenerator).

업데이트 적용

생성된 .swu 파일을 테스트하려면 다음과 같이 하세요:

  1. CM5를 복구 시스템으로 부팅합니다.
  2. 마운트 지점을 생성합니다:
sudo mkdir -p /mnt/update
  1. 업데이트 파일이 포함된 NFS 공유를 마운트합니다:
sudo mount -t nfs :/path/to/share /mnt/update
  1. 업데이트를 적용합니다:
sudo swupdate -i /mnt/update/update.swu

통합 가능성

로컬 UI 또는 백엔드 API에서 업데이트 트리거하기

  • 보안 강화를 위한 업데이트 서명 및 확인
  • 사용 SWUpdate’s 테스트 또는 디버깅을 위한 웹 인터페이스 사용
  • systemd 서비스와 결합하여 복구 및 롤백 자동화

이 스택에 적합한 이유

와 함께 rpi-image-genrpi-sb-provisioner, SWUpdate 를 사용하면 그림이 완성됩니다:

  • 빌드 → rpi-image-gen (이미지 생성)
  • 배포 → rpi-sb-provisioner (디바이스 프로비저닝)
  • 유지 관리 → → SWUpdate (OTA 업데이트 및 수명 주기 관리)

그 결과 유연하고 개방적이며 유지 관리가 가능한 임베디드 플랫폼이 탄생합니다. Linux 유연하고 개방적이며 유지 관리가 가능한 임베디드 플랫폼이 탄생했습니다. Yocto.