실시간 시스템 업데이트는 특히 임베디드 시스템에서 중요한 역할을 한다. 이러한 업데이트 사례를 통해 Yocto 프로젝트 기반의 시스템이 어떻게 효과적으로 유지되고 있으며, 상황에 따라 대응하고 업데이트할 수 있는지 설명하겠다.
예제: Over-the-Air (OTA) 업데이트
OTA 업데이트는 일반적으로 원격에서 시스템 소프트웨어를 업데이트하는 방법이다. 이 사례에서는 Yocto 프로젝트를 사용하여 OTA 시스템을 설정하고 실시간으로 업데이트를 배포하는 과정을 살펴보겠다.
시스템 구성
OTA 업데이트를 지원하기 위해, 다음과 같은 시스템 구성 요소가 필요하다:
- 업데이트 서버: 업데이트 파일을 호스팅하고 장치와 통신을 관리한다.
- 클라이언트 장치: 업데이트를 수신하고 설치하는 임베디드 시스템.
- 통신 프로토콜: 일반적으로 HTTP/HTTPS를 사용하여 클라이언트와 서버 간의 통신을 관리한다.
서버 설정
업데이트 서버는 클라이언트가 최신 소프트웨어를 다운로드할 수 있도록 준비해야 한다. 이를 위해 기본적으로 웹 서버를 사용하며, 업데이트 파일 및 메타데이터를 저장하는 디렉터리를 설정한다.
mkdir -p /var/www/ota-updates
cp update-file.img /var/www/ota-updates/
Apache 또는 Nginx와 같은 웹 서버를 설정하여 이 디렉터리를 서비스한다.
클라이언트 설정
클라이언트 장치는 업데이트 서버와 연결하고 업데이트 파일을 다운로드 및 설치할 준비가 되어 있어야 한다. 이를 위해 Yocto 레시피를 작성하여 필요한 도구와 스크립트를 포함한다.
Yocto 레시피 추가
DESCRIPTION = "OTA Update client"
LICENSE = "CLOSED"
SRC_URI = "file://updater-script.sh"
S = "${WORKDIR}"
do_install() {
install -d ${D}${bindir}
install -m 0755 ${S}/updater-script.sh${D}${bindir}/updater
}
업데이터 스크립트 작성
updater-script.sh는 서버에서 업데이트 파일을 다운로드하고 이를 시스템에 적용하는 역할을 한다.
#!/bin/sh
SERVER_URL="http://yourserver.com/ota-updates"
UPDATE_FILE="update-file.img"
wget ${SERVER_URL}/${UPDATE_FILE} -O /tmp/${UPDATE_FILE}
dd if=/tmp/${UPDATE_FILE} of=/dev/mmcblk0p1
reboot
업데이트 적용
업데이트 과정은 아래와 같다:
- 업데이트 확인: 주기적으로 서버에서 새로운 업데이트가 있는지 확인한다.
- 파일 다운로드: 새로운 업데이트가 발견되면 클라이언트에서 해당 파일을 다운로드한다.
- 업데이트 적용: 다운로드한 파일을 통해 시스템을 업데이트한다.
- 시스템 다시 시작: 업데이트가 적용되도록 시스템을 재부팅한다.
주기적 업데이트 확인
crontab -e
크론 작업에 다음 명령을 추가한다:
0 * * * * /usr/bin/updater &>/dev/null
이를 통해 클라이언트 장치는 매 시간마다 업데이트를 확인하고 다운로드 및 적용할 수 있다.
무중단 업데이트 (A/B 시스템)
OTA 업데이트의 형식 중 하나는 A/B 시스템을 활용하는 것이다. 이 시스템은 현재 실행 중인 소프트웨어를 중단하지 않고도 안전하게 업데이트할 수 있다. A/B 시스템에서는 두 개의 파티션이 사용되며, 한 파티션에서 시스템이 실행되면서 다른 파티션에서 업데이트를 수행한다.
시스템 구성
A/B 시스템은 두 개의 루트 파일 시스템 파티션과 하나의 부트로더 파티션을 사용한다. 이를 통해 다음과 같은 방식으로 업데이트를 수행할 수 있다:
- 현재 실행 중인 파티션을 "A"로 설정
- 업데이트를 "B" 파티션에 적용
- 업데이트 후 부팅 설정을 "B"로 변경
- 시스템 재부팅 시 "B" 파티션에서 부팅
부트로더 설정
일반적으로 U-Boot와 같은 부트로더는 A/B 시스템을 지원한다. 첫 번째 단계는 U-Boot를 구성하여 둘 이상의 루트 파일 시스템 파티션을 인식하게 만드는 것이다.
bootcmd_a=load mmc 0:1 $kernel_addr_r Image; load mmc 0:1$fdt_addr_r my-device-tree.dtb; booti $kernel_addr_r -$fdt_addr_r
bootcmd_b=load mmc 0:2 $kernel_addr_r Image; load mmc 0:2$fdt_addr_r my-device-tree.dtb; booti $kernel_addr_r -$fdt_addr_r
bootcmd=${bootcmd_a}
partA=1
partB=2
current_part=1 # Default to partition A
업데이트 절차
업데이트는 다음의 단계로 진행된다:
- 업데이트 준비: 업데이트 파일을 "B" 파티션에 다운로드.
- 파티션 전환: 부트로더 설정을 변경하여 다음 부팅 시 "B" 파티션을 사용하도록 설정.
- 검증 및 복구: 업데이트 후 시스템이 정상적으로 부팅되지 않으면 "A" 파티션으로 복귀.
업데이트 스크립트
#!/bin/sh
UPDATE_URL="http://yourserver.com/ota-updates/new-update.img"
UPDATE_PARTITION="/dev/mmcblk0p2"
ACTIVE_PARTITION=$(fw_printenv current_part | cut -d= -f2)
if [ "$ACTIVE_PARTITION" = "1" ]; then
INACTIVE_PARTITION="/dev/mmcblk0p2"
NEW_PART=2
else
INACTIVE_PARTITION="/dev/mmcblk0p1"
NEW_PART=1
fi
wget $UPDATE_URL -O /tmp/new-update.img
dd if=/tmp/new-update.img of=$INACTIVE_PARTITION
fw_setenv bootcmd "bootcmd${NEW_PART}"
fw_setenv current_part $NEW_PART
reboot
검증 및 복구
업데이트 후 시스템이 정상적으로 부팅되지 않는 경우, 부트로더에 의해 이전 파티션으로 복귀할 수 있도록 설정하는 것이 중요하다. 이를 위해 watchdog 타이머나 보안 부팅 절차를 활용할 수 있다.
bootcmd=run bootcmd_a || run bootcmd_b || reset
정상적으로 부팅되었을 때만 성공적으로 업데이트를 완료했다고 리포트할 수 있도록 한다.
#!/bin/sh
# After a successful boot, ensure the watchdog is reset
touch /var/run/update-success
# Add heartbeat function to ensure the watchdog doesn't reset
while true; do
sleep 60
touch /var/run/update-success
done
부팅 후 시스템이 정상적으로 작동하면 완료 성공을 기록하고 다음 업데이트를 위해 시스템을 모니터링한다.