embedded-deck
SWUpdate & RAUC — Üretim OTA Güncelleme · embedded-deck embedded-deck
GÖMÜLÜ LİNUX OTA SWUPDATE RAUC 2026

SWUpdate & RAUC
üretim OTA güncelleme.

Atomik güncelleme, rollback ve imzalama ile üretim kalitesinde OTA sistemi. SWUpdate handler mimarisinden RAUC bundle'larına, hawkBit bulut entegrasyonundan Yocto CI/CD pipeline'ına.

00 Üretim OTA gereksinimleri

Sahadaki gömülü cihazlara güvenilir yazılım güncellemesi göndermek, geliştirme ortamında test etmekten çok daha zorlu bir mühendislik problemidir. Bir güncelleme sistemi üretim ortamında arızalanmamalı, arızalanırsa kurtarabilmelidir.

Temel gereksinimler

Atomiklik
Güncelleme ya tamamen uygulanır ya da hiç uygulanmaz. Yarım kalan güncelleme cihazı bozmamalıdır.
Rollback
Güncelleme sonrası sistem boot edemezse veya doğrulama başarısız olursa önceki sürüme otomatik dönüş.
İmzalama
Güncelleme paketinin gerçek üreticiden geldiği kriptografik olarak doğrulanmalı. Sahte paket kabul edilmemeli.
Güç kesintisi güvenliği
Güncelleme sırasında herhangi bir noktada güç kesilse bile cihaz kurtarılabilir durumda kalmalı.
Bant genişliği verimliliği
Büyük imajlar için delta güncelleme (sadece değişen bloklar) önemli maliyet tasarrufu sağlar.
Uzaktan yönetim
Binlerce cihaza gruplar halinde rollout, anlık durum izleme ve hata raporlama.

Mevcut OTA yöntemleri karşılaştırması

YöntemAtomikRollbackİmzalamaÜretim uygunluğu
Manuel FTP/SCP kopyalamaHayırHayırHayırUygun değil
apt/opkg (paket yöneticisi)KısmiKısmiPaket imzasıSınırlı
SWUpdateEvetEvetRSA/ECDSATam uygun
RAUCEvetEvetX.509Tam uygun
OSTreeEvetEvetGPGTam uygun
SWUpdate mi RAUC mi?

SWUpdate, esnek handler sistemi ile karmaşık özel güncelleme iş akışlarına uygundur. RAUC, daha katı bundle formatı ile sadelik ve güvenlik odaklıdır. Yocto ekosistemiyle her ikisi de iyi entegre olur; meta-swupdate ve meta-rauc katmanları mevcuttur.

01 SWUpdate mimarisi

SWUpdate, C ile yazılmış bir daemon'dır. Güncelleme paketi (CPIO arşivi) işler, doğrular ve handler sistemi aracılığıyla cihaza uygular.

  ┌─────────────────────────────────────────────────────────────────┐
  │                        swupdate daemon                          │
  │                                                                 │
  │  ┌─────────┐  ┌──────────┐  ┌────────────┐  ┌──────────────┐  │
  │  │Mongoose │  │ SURICATTA│  │Lua/Python  │  │ DBus/Notif.  │  │
  │  │ Web UI  │  │ hawkBit  │  │ Scripting  │  │  Interface   │  │
  │  └────┬────┘  └────┬─────┘  └─────┬──────┘  └──────────────┘  │
  │       └────────────┴──────────────┘                            │
  │                       │                                        │
  │            ┌──────────▼──────────┐                             │
  │            │  swupdate core      │                             │
  │            │  - CPIO parse       │                             │
  │            │  - sw-description   │                             │
  │            │  - signature verify │                             │
  │            └──────────┬──────────┘                             │
  │                       │                                        │
  │     ┌─────────────────┼──────────────────┐                    │
  │     │                 │                  │                    │
  │  ┌──▼──────┐  ┌───────▼────────┐  ┌──────▼─────────┐         │
  │  │ ubivol  │  │ raw / rawfile  │  │  shellscript   │         │
  │  │ handler │  │    handler     │  │    handler     │         │
  │  └─────────┘  └────────────────┘  └────────────────┘         │
  └─────────────────────────────────────────────────────────────────┘
    

Yerleşik handler'lar

HandlerKullanımNotlar
ubivolUBI volume güncellemeNAND flash için ideal
rawHam blok yazma (/dev/mmcblk0p2)eMMC, SD kart için
rawfileDosya sistemi üzerine dosya kopyalamaTek dosya güncelleme
shellscriptÖzel shell scripti çalıştırmaEsneklik sağlar
luaLua scripti ile özel mantıkGüçlü ve güvenli
bootloaderU-Boot ortam değişkeni yazmaRollback için kritik
copymountedMount edilen fs üzerine tarOverlay/incremental güncelleme
deltalibzsync delta güncellemeBant genişliği tasarrufu

swupdate paket formatı

paket yapısı
update.swu (CPIO arşivi)
├── sw-description        # libconfig sözdizimi, güncelleme tarifi
├── sw-description.sig    # RSA/ECDSA imzası
├── rootfs.ext4.gz        # rootfs image
├── kernel.itb            # FIT image (kernel + dtb)
├── bootloader.bin        # U-Boot binary (opsiyonel)
└── post_install.lua      # Özel Lua scripti (opsiyonel)

## Paket oluşturma
for f in sw-description sw-description.sig rootfs.ext4.gz kernel.itb; do
    echo "$f"
done | cpio -ovH newc > update.swu

02 sw-description dosyası

sw-description, SWUpdate paketinin güncelleme tarifini içerir. libconfig sözdiziminde yazılır ve hangi image'ın nereye yazılacağını, doğrulama kontrollerini ve özel scriptleri tanımlar.

sw-description — tam örnek (A/B sistemi)
software =
{
    version = "2.1.0";
    description = "Üretim firmware v2.1.0";

    /* Donanım revizyonu kontrolü */
    hardware-compatibility = [ "1.0", "1.1", "1.2" ];

    stable: {
        images: (
            {
                /* Kernel FIT image */
                filename = "kernel.itb";
                type = "raw";
                device = "/dev/mmcblk0p3";   /* kernel_b */
                sha256 = "abc123def456...";
                installed-directly = false;
                compressed = false;
            },
            {
                /* Root filesystem */
                filename = "rootfs.ext4.gz";
                type = "raw";
                device = "/dev/mmcblk0p4";   /* rootfs_b */
                sha256 = "def456abc789...";
                compressed = true;
            }
        );

        scripts: (
            {
                filename = "post_install.lua";
                type = "lua";
            }
        );

        /* Bootloader değişkeni — A/B geçişi */
        bootenv: (
            {
                name = "boot_slot";
                value = "b";
            },
            {
                name = "bootcount";
                value = "0";
            }
        );
    };
}

Çoklu donanım profili

sw-description — donanım profilleri
software =
{
    version = "2.1.0";

    /* Her donanım revizyonu için farklı image */
    hardware: "rev-1.0" {
        images: (
            {
                filename = "rootfs-rev1.ext4.gz";
                type = "raw";
                device = "/dev/mmcblk0p2";
                sha256 = "aaa111bbb222...";
                compressed = true;
            }
        );
    };

    hardware: "rev-2.0" {
        images: (
            {
                filename = "rootfs-rev2.ext4.gz";
                type = "raw";
                device = "/dev/mmcblk0p2";
                sha256 = "ccc333ddd444...";
                compressed = true;
            }
        );
    };
}

swupdate çalıştırma

swupdate komutları
## Yerel dosyadan güncelleme
swupdate -i update.swu -v

## Daemon modunda çalıştır (hawkBit için)
swupdate -f /etc/swupdate.cfg &

## İmza doğrulama ile
swupdate -i update.swu -k /etc/swupdate.pem -v

## Web sunucusunu etkinleştir (port 8080)
swupdate -w "--port 8080" &

## HTTP URL'den doğrudan indir ve uygula
swupdate -d "-u http://update-server/v2.1.0.swu"

03 SWUpdate Lua handler

Lua handler, sw-description'da script type ile tanımlanan özel güncelleme mantığını uygulamak için kullanılır. SWUpdate API'sine tam erişim sağlar.

post_install.lua — örnek handler
-- post_install.lua
local swupdate = require("swupdate")
local posix    = require("posix")

local INFO    = swupdate.INFO
local WARNING = swupdate.WARNING
local ERROR   = swupdate.ERROR

-- Güncelleme öncesi doğrulama
function preinst(image)
    swupdate.notify(INFO, "Pre-install: " .. image.filename)

    -- Disk alanı kontrolü (min 100 MB)
    local stat    = posix.statvfs("/")
    local free_mb = (stat.f_bavail * stat.f_bsize) / (1024 * 1024)
    if free_mb < 100 then
        swupdate.notify(ERROR, "Yetersiz disk: " .. free_mb .. " MB")
        return false
    end

    swupdate.notify(INFO, "Disk alanı yeterli: " .. free_mb .. " MB")
    return true
end

-- Güncelleme sonrası adımlar
function postinst(image)
    swupdate.notify(INFO, "Post-install başlıyor")

    -- Bootloader ortam değişkenini güncelle
    local rc = os.execute("fw_setenv boot_slot b")
    if rc ~= 0 then
        swupdate.notify(ERROR, "fw_setenv başarısız!")
        return false
    end

    os.execute("fw_setenv bootcount 0")

    -- Güncelleme logunu kaydet
    local log = io.open("/data/update_log.txt", "a")
    if log then
        log:write(os.date() .. " — v2.1.0 kuruldu\n")
        log:close()
    end

    swupdate.notify(INFO, "Post-install tamamlandı")
    return true
end

return {
    pre  = preinst,
    post = postinst,
}

Özel C handler — FPGA bitstream yazma

fpga_handler.c
#include "swupdate.h"
#include "handler.h"
#include "util.h"

/* FPGA bitstream yazma handler'ı */
static int fpga_handler(struct img_type *img,
                        void __attribute__((__unused__)) *data)
{
    int fd;

    TRACE("FPGA bitstream yazma: %s", img->fname);

    /* FPGA manager sysfs üzerinden yaz */
    fd = open("/sys/class/fpga_manager/fpga0/firmware", O_WRONLY);
    if (fd < 0) {
        ERROR("FPGA manager açılamadı: %s", strerror(errno));
        return -EFAULT;
    }

    long long written = copyfile(img, &fd, img->size, &img->offset,
                                  0, 0, NULL);
    close(fd);

    if (written < 0) {
        ERROR("FPGA yazma hatası");
        return written;
    }

    INFO("FPGA bitstream başarıyla yazıldı: %lld byte", written);
    return 0;
}

/* Başlangıçta handler'ı kaydet */
__attribute__((constructor))
static void fpga_handler_init(void)
{
    register_handler("fpga", fpga_handler, IMAGE_HANDLER, NULL);
}

04 hawkBit entegrasyonu

hawkBit, Bosch tarafından geliştirilen açık kaynak bir IoT yazılım güncelleme sunucusudur. SWUpdate'in suricatta modülü ile entegre çalışır ve binlerce cihaza rollout yönetimi sağlar.

hawkBit Docker kurulumu

hawkbit-docker-compose.yml
version: "3"

services:
  hawkbit:
    image: hawkbit/hawkbit-update-server:latest
    ports:
      - "8080:8080"
    environment:
      - SPRING_DATASOURCE_URL=jdbc:mariadb://db:3306/hawkbit
      - SPRING_DATASOURCE_USERNAME=hawkbit
      - SPRING_DATASOURCE_PASSWORD=hawkbit
      - HAWKBIT_SERVER_SECURITY_DOS_FILTER_ENABLED=false
    depends_on:
      - db
      - rabbitmq

  db:
    image: mariadb:10.11
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: hawkbit
      MYSQL_USER: hawkbit
      MYSQL_PASSWORD: hawkbit
    volumes:
      - dbdata:/var/lib/mysql

  rabbitmq:
    image: rabbitmq:3-management
    ports:
      - "15672:15672"

volumes:
  dbdata:

SWUpdate suricatta konfigürasyonu

/etc/swupdate.cfg — hawkBit bağlantısı
globals:
{
    verbose  = true;
    loglevel = 3;
    syslog   = true;
};

suricatta:
{
    url       = "http://hawkbit-server:8080";
    id        = "device-001";
    tenant    = "DEFAULT";
    polldelay = 45;        /* saniye */

    /* Kimlik doğrulama token'ı */
    /* targettoken = "abc123..."; */

    /* TLS için */
    /* sslkey  = "/etc/swupdate/device.key";  */
    /* sslcert = "/etc/swupdate/device.crt";  */
    /* cafile  = "/etc/swupdate/ca.crt";      */

    retry       = 3;
    retry_sleep = 1000;
};

identify:
{
    name  = "firmware-version";
    value = "2.0.0";
};

Rollout oluşturma — DDI API

hawkbit_rollout.py — pilot rollout
#!/usr/bin/env python3
import requests

BASE  = "http://hawkbit-server:8080"
AUTH  = ("admin", "admin")

# Distribution set oluştur
ds = requests.post(f"{BASE}/rest/v1/distributionsets",
    json=[{"name": "firmware-v2.1.0", "version": "2.1.0",
           "type": "os"}], auth=AUTH).json()[0]
ds_id = ds["id"]

# Rollout — %10 pilot grubu
rollout = requests.post(f"{BASE}/rest/v1/rollouts",
    json={
        "name": "rollout-v2.1.0",
        "distributionSetId": ds_id,
        "targetFilterQuery": "tag==production",
        "deploymentGroups": [
            {
                "name": "pilot-10pct",
                "targetPercentage": 10,
                "successCondition": {"condition": "THRESHOLD",
                                     "expression": "80"},
                "errorCondition":   {"condition": "THRESHOLD",
                                     "expression": "5"},
                "successAction":    {"expression": "NEXTGROUP"},
                "errorAction":      {"expression": "PAUSE"}
            },
            {
                "name": "full-rollout",
                "targetPercentage": 100,
                "successCondition": {"condition": "THRESHOLD",
                                     "expression": "90"},
                "errorCondition":   {"condition": "THRESHOLD",
                                     "expression": "5"},
                "successAction":    {"expression": "NEXTGROUP"},
                "errorAction":      {"expression": "PAUSE"}
            }
        ],
        "type": "forced"
    }, auth=AUTH).json()

rollout_id = rollout["id"]
# Rollout başlat
requests.post(f"{BASE}/rest/v1/rollouts/{rollout_id}/start", auth=AUTH)
print(f"Rollout başlatıldı: ID={rollout_id}")

05 RAUC mimarisi

RAUC (Robust Auto-Update Controller), atomik A/B partition güncellemesi için tasarlanmış bir framework'tür. Güvenlik odaklı tasarımı ve net slot kavramıyla öne çıkar.

  ┌───────────────────────────────────────────────────────────┐
  │                   RAUC Bundle (.raucb)                    │
  │  ┌──────────────────────────────────────────────────┐    │
  │  │  manifest.raucm (X.509 imzalanmış)               │    │
  │  │  rootfs.img.verity  │  kernel.img  │  boot.img   │    │
  │  └──────────────────────────────────────────────────┘    │
  └──────────────────────────┬────────────────────────────────┘
                             │  rauc install bundle.raucb
                   ┌─────────▼──────────┐
                   │    RAUC Service     │
                   │    (DBus daemon)    │
                   └─────────┬──────────┘
                             │
             ┌───────────────┼──────────────────┐
             │               │                  │
  ┌──────────▼──────────┐    │    ┌─────────────▼────────────┐
  │  Slot A (aktif)      │    │    │  Slot B (pasif — hedef)  │
  │  /dev/mmcblk0p2      │    │    │  /dev/mmcblk0p3          │
  │  rootfs_a, kernel_a  │    │    │  rootfs_b, kernel_b      │
  └──────────────────────┘    │    └──────────────────────────┘
                              │
                   ┌──────────▼──────────┐
                   │  Bootloader (U-Boot) │
                   │  boot_slot=b        │
                   │  BOOT_ORDER=B A     │
                   └─────────────────────┘
    

RAUC temel kavramlar

Bundle
Güncelleme paketi. İmzalanmış manifest + payload image'larından oluşan squashfs arşivi (.raucb uzantısı).
Slot
Güncellenebilir bir partition veya MTD aygıtı. Her slot bir sınıfa (rootfs, kernel) aittir.
Slot class
Aynı tipteki slot'ların grubu. Güncelleme sırasında aktif olmayan slot hedef alınır.
Bootloader adaptation
RAUC hangi slot'un boot edileceğini bootloader üzerinden kontrol eder. barebox, U-Boot, GRUB desteklenir.
casync delta
Delta güncelleme desteği. Sadece değişen chunk'lar indirilir, bant genişliği tasarrufu sağlanır.

RAUC sistem konfigürasyonu

/etc/rauc/system.conf
[system]
compatible=My-Board-v1
bootloader=uboot

[keyring]
path=/etc/rauc/ca.cert.pem

[handlers]
post-install=/usr/lib/rauc/post-install.sh

[slot.rootfs.0]
device=/dev/mmcblk0p2
type=ext4
bootname=A
parent=kernel.0

[slot.rootfs.1]
device=/dev/mmcblk0p3
type=ext4
bootname=B
parent=kernel.1

[slot.kernel.0]
device=/dev/mmcblk0p5
type=raw
bootname=A

[slot.kernel.1]
device=/dev/mmcblk0p6
type=raw
bootname=B

06 RAUC bundle oluşturma

RAUC bundle, imzalanmış bir manifest ve payload image'larından oluşur. X.509 sertifikaları ile imzalanır; doğrulama cihazda yerleşik CA sertifikasıyla yapılır.

X.509 sertifika altyapısı

sertifika oluşturma
## CA oluştur (üretimde HSM kullanın!)
openssl req -x509 -newkey rsa:4096 -keyout ca.key.pem \
    -out ca.cert.pem -days 3650 -nodes \
    -subj "/CN=RAUC CA/O=My Company/C=TR"

## İmzalama sertifikası oluştur
openssl genrsa -out developer.key.pem 2048
openssl req -new -key developer.key.pem \
    -out developer.csr.pem \
    -subj "/CN=RAUC Developer/O=My Company/C=TR"

## CA ile imzala
openssl x509 -req -in developer.csr.pem \
    -CA ca.cert.pem -CAkey ca.key.pem \
    -CAcreateserial -out developer.cert.pem -days 365

## CA sertifikası cihaza gömülür:
## /etc/rauc/ca.cert.pem

manifest.raucm

manifest.raucm
[update]
compatible=My-Board-v1
version=2.1.0
description=Üretim firmware v2.1.0
build=20260412T123456

[bundle]
format=verity

[image.rootfs]
filename=rootfs.ext4
digest=sha256:abc123def456789...
size=67108864

[image.kernel]
filename=kernel.img
digest=sha256:789abc012def345...
size=8388608

Bundle oluşturma scripti

bundle_build.sh
#!/bin/bash
set -euo pipefail

VERSION="2.1.0"
BUNDLE_DIR="bundle_tmp"
BUNDLE_OUT="firmware-${VERSION}.raucb"

mkdir -p "${BUNDLE_DIR}"
cp rootfs.ext4   "${BUNDLE_DIR}/"
cp kernel.img    "${BUNDLE_DIR}/"
cp manifest.raucm "${BUNDLE_DIR}/"

## Bundle oluştur ve imzala
rauc bundle \
    --cert=developer.cert.pem \
    --key=developer.key.pem   \
    "${BUNDLE_DIR}"            \
    "${BUNDLE_OUT}"

rauc info "${BUNDLE_OUT}"
echo "Oluşturuldu: ${BUNDLE_OUT} ($(du -sh ${BUNDLE_OUT} | cut -f1))"

rm -rf "${BUNDLE_DIR}"

Bundle kurma

rauc komutları
## Bundle bilgisini görüntüle
rauc info firmware-2.1.0.raucb

## Slot durumunu görüntüle
rauc status

## Bundle'ı kur (pasif slot'a)
rauc install firmware-2.1.0.raucb

## Kurulum sonrası slot durumu
rauc status
## [slot.rootfs.1]  device=/dev/mmcblk0p3  state=inactive  boot_good=0

## Reboot → yeni slot denenir
reboot

07 A/B partition yönetimi

A/B partition şeması, üretim sistemlerinde kesintisiz güncellemeyi mümkün kılar. RAUC, bootloader ile iş birliği yaparak hangi slot'un aktif olduğunu ve rollback durumunu yönetir.

U-Boot bootcount mekanizması

U-Boot bootcount logic (pseudocode)
## U-Boot ortam değişkenleri
boot_slot=b    # Sonraki boot için hedef slot
bootlimit=3    # Max deneme sayısı
bootcount=1    # Mevcut deneme sayısı
boot_a_ok=1    # A slot'u iyi mi?
boot_b_ok=0    # B slot'u iyi mi? (yeni kuruldu)

## U-Boot boot logic (include/configs/my_board.h içinde):
##
## if (bootcount >= bootlimit) {
##     /* Tüm denemeler tükendi, güvenli slot'a dön */
##     boot_slot = boot_a_ok ? "a" : "b";
##     saveenv(); reset();
## }
## bootcount++;
## saveenv();
## /* Hedef slot'u yükle */
## if (boot_slot == "b") {
##     load_kernel_b(); load_dtb_b();
##     bootargs += " root=/dev/mmcblk0p3";
## } else {
##     load_kernel_a(); load_dtb_a();
##     bootargs += " root=/dev/mmcblk0p2";
## }

RAUC post-install hook

/usr/lib/rauc/post-install.sh
#!/bin/sh
# RAUC çevre değişkenleri otomatik olarak ayarlanır:
# RAUC_SLOT_NAME, RAUC_SLOT_BOOTNAME, RAUC_BUNDLE_VERSION
set -e

BOOT_NAME="${RAUC_SLOT_BOOTNAME}"   # A veya B
BOOT_LC=$(echo "${BOOT_NAME}" | tr '[:upper:]' '[:lower:]')

echo "RAUC post-install: slot=${RAUC_SLOT_NAME} boot=${BOOT_NAME}"

## Bootloader ortam değişkenlerini ayarla
fw_setenv boot_slot   "${BOOT_LC}"
fw_setenv bootcount   0
fw_setenv "boot_${BOOT_LC}_ok" 0

echo "Bootloader güncellendi. Sonraki boot: slot ${BOOT_NAME}"

mark-good — başarılı boot onayı

rauc mark komutları
## Başarılı boot onayı (systemd servisi çağırır)
rauc mark good booted

## Manuel: belirli slot'u kötü işaretle → rollback tetikle
rauc mark bad rootfs.1

## Slot durumu özeti
rauc status --output-format=json | python3 -m json.tool

## Aktif slot
rauc status | grep "booted slot"

Otomatik mark-good — systemd

rauc-mark-good.service
[Unit]
Description=RAUC Mark Booted Slot as Good
After=network-online.target app-healthcheck.service
Wants=network-online.target

[Service]
Type=oneshot
# Uygulama sağlık kontrolü geçtikten sonra çalışır
ExecStart=/usr/bin/rauc mark good booted
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target
KRİTİK

rauc mark good booted komutu, sistemin başarıyla başladığını ve uygulamanın çalıştığını doğruladıktan sonra çağrılmalıdır. Erken çağrılırsa hatalı bir güncelleme kalıcı hale gelir. Uygulama sağlık kontrollerini geçtikten sonra çağırın.

08 Pratik: Yocto + RAUC + hawkBit CI/CD

Tam bir üretim OTA pipeline'ı: Yocto meta-rauc katmanı ile RAUC entegrasyonu, GitLab CI ile otomatik bundle üretimi ve hawkBit üzerinden rollout.

Yocto meta-rauc entegrasyonu

bblayers.conf — katman ekle
BBLAYERS ?= " \
  ${BSPDIR}/sources/poky/meta \
  ${BSPDIR}/sources/poky/meta-poky \
  ${BSPDIR}/sources/meta-openembedded/meta-oe \
  ${BSPDIR}/sources/meta-openembedded/meta-python \
  ${BSPDIR}/sources/meta-rauc \
  ${BSPDIR}/sources/meta-my-machine \
  "
local.conf — RAUC ve wic imajı
## RAUC ve hawkBit agent ekle
IMAGE_INSTALL:append = " rauc rauc-hawkbit-updater"

## A/B wic imajı için
IMAGE_FSTYPES:append = " wic"
WKS_FILE = "my-board-ab.wks"

## RAUC sertifikası (keyring)
RAUC_KEYRING_FILE = "${LAYERDIR}/files/ca.cert.pem"
my-board-ab.wks — A/B partition şeması
## my-board-ab.wks — wic partition tanımı

# Boot partition (ortak, U-Boot + env)
part /boot --source bootimg-partition --ondisk mmcblk0 \
    --fstype=vfat --label boot --active --align 4096 --size 64M

# Slot A — rootfs (aktif)
part /     --source rootfs --ondisk mmcblk0 \
    --fstype=ext4 --label rootfs_a --align 4096 --size 512M

# Slot B — rootfs (güncelleme hedefi)
part       --ondisk mmcblk0 \
    --fstype=ext4 --label rootfs_b --align 4096 --size 512M

# Kernel A
part       --ondisk mmcblk0 \
    --fstype=ext4 --label kernel_a --align 4096 --size 16M

# Kernel B
part       --ondisk mmcblk0 \
    --fstype=ext4 --label kernel_b --align 4096 --size 16M

# Kalıcı veri (güncellemeden etkilenmez)
part /data --ondisk mmcblk0 \
    --fstype=ext4 --label data --align 4096

GitLab CI/CD pipeline

.gitlab-ci.yml — tam OTA pipeline
stages:
  - build
  - bundle
  - sign
  - deploy

variables:
  YOCTO_MACHINE:  "my-board"
  BUNDLE_VERSION: "${CI_COMMIT_SHORT_SHA}"
  HAWKBIT_URL:    "http://hawkbit-server:8080"

## Yocto imajı ve RAUC bundle derle
build-image:
  stage: build
  image: crops/poky:debian-11
  script:
    - source oe-init-build-env
    - bitbake core-image-minimal
    - bitbake rauc-bundle
  artifacts:
    paths:
      - build/tmp/deploy/images/${YOCTO_MACHINE}/*.raucb
      - build/tmp/deploy/images/${YOCTO_MACHINE}/*.wic.gz
    expire_in: 7 days
  only:
    - main
    - tags

## Bundle'ı CI imzalama anahtarıyla imzala
sign-bundle:
  stage: sign
  image: debian:12-slim
  before_script:
    - apt-get install -y rauc openssl
  script:
    - UNSIGNED="build/tmp/deploy/images/${YOCTO_MACHINE}/rauc-bundle.raucb"
    - SIGNED="firmware-${BUNDLE_VERSION}.raucb"
    ## Gizli anahtarlar CI/CD secret değişkenlerinden gelir
    - echo "${RAUC_SIGNING_KEY}"  | base64 -d > /tmp/signing.key.pem
    - echo "${RAUC_SIGNING_CERT}" | base64 -d > /tmp/signing.cert.pem
    - rauc resign
        --key=/tmp/signing.key.pem
        --cert=/tmp/signing.cert.pem
        "${UNSIGNED}" "${SIGNED}"
    - rauc info "${SIGNED}"
  artifacts:
    paths:
      - firmware-*.raucb
    expire_in: 30 days
  only:
    - tags

## hawkBit'e yükle ve pilot rollout başlat
deploy-hawkbit:
  stage: deploy
  image: python:3.11-slim
  before_script:
    - pip install requests
  script:
    - python3 ci/hawkbit_upload.py
        --bundle "firmware-${BUNDLE_VERSION}.raucb"
        --server "${HAWKBIT_URL}"
        --version "${BUNDLE_VERSION}"
  environment:
    name: production
    url: ${HAWKBIT_URL}
  only:
    - tags

CI bundle yükleme scripti

ci/hawkbit_upload.py
#!/usr/bin/env python3
import requests, argparse

def upload(server, bundle_path, version):
    auth = ("admin", "admin")
    base = f"{server}/rest/v1"

    ## 1. Software module oluştur
    sm = requests.post(f"{base}/softwaremodules",
        json=[{"name": f"firmware-{version}",
               "version": version, "type": "os"}],
        auth=auth).json()[0]
    sm_id = sm["id"]

    ## 2. Bundle dosyasını yükle
    with open(bundle_path, "rb") as f:
        requests.post(f"{base}/softwaremodules/{sm_id}/artifacts",
            files={"file": (bundle_path, f, "application/octet-stream")},
            auth=auth)

    ## 3. Distribution set oluştur
    ds = requests.post(f"{base}/distributionsets",
        json=[{"name": f"firmware-{version}", "version": version,
               "type": "os", "modules": [{"id": sm_id}]}],
        auth=auth).json()[0]

    print(f"Bundle hazır — DS ID={ds['id']}  version={version}")
    return ds["id"]

if __name__ == "__main__":
    p = argparse.ArgumentParser()
    p.add_argument("--bundle")
    p.add_argument("--server")
    p.add_argument("--version")
    args = p.parse_args()
    upload(args.server, args.bundle, args.version)
ÖZET

SWUpdate ve RAUC, üretim kalitesinde OTA güncelleme için tüm gereksinimleri karşılar: atomik güncelleme, kriptografik imzalama, otomatik rollback ve güç kesintisi güvenliği. RAUC'un verity bundle formatı ve dm-verity entegrasyonu özellikle güvenlik odaklı projelerde öne çıkar. Yocto + meta-rauc + GitLab CI + hawkBit kombinasyonu, endüstriyel IoT projeleri için olgun bir CI/CD pipeline'ı sunar.