Compare commits

6 Commits

Author SHA1 Message Date
2da217c0ce conters-based updates 2026-08-03 21:10:49 -04:00
37583d820a removed application level update as covered by packege-based updates 2026-08-03 19:25:25 -04:00
be12197ac0 package-based updates adr 2026-08-03 19:11:42 -04:00
155cca5eeb General adr description 2026-08-03 17:39:54 -04:00
7a74d9fca3 full system image updates 2026-08-03 17:36:57 -04:00
2b49cbe010 Update Strategies 2026-08-03 16:02:00 -04:00
5 changed files with 1389 additions and 0 deletions

View File

@@ -0,0 +1,129 @@
# ADR-004: Full-System Image Updates
## Status
Accepted
## Context
An OTA architecture must define the unit of update.
One possible approach is to treat the complete software stack as a single release artifact and distribute it as a prebuilt, tested system image.
For firmware-based devices, a full image is often the only practical update unit. For embedded Linux and other more complex platforms, it is one of several available strategies.
## Decision
Use full-system image updates when the device software is released and maintained as a single product, and when reproducibility, a known system state, and reliable system-level rollback are more important than minimizing update size or supporting independent component lifecycles.
## Decision Drivers
Full-system image updates are preferred when:
- the software stack is released as a single product;
- the device must remain in one of a small number of predefined system states;
- system-level rollback is required;
- reproducibility is more important than minimizing update size;
- the device fleet is sufficiently homogeneous;
- image size and storage requirements are acceptable;
- centralized release and validation of the complete system are practical.
## Consequences
### Positive
- The image version identifies the version of the complete software system.
- The device runs a predefined system state rather than an arbitrary combination of component versions.
- The exact image installed on the device is the image that was validated before release.
- Dependency resolution is not required during installation.
- Diagnosis of the installed system version is simplified.
- The approach integrates naturally with A/B layouts and system-level rollback.
- The number of possible software configurations is reduced.
- The software can be built, tested, signed, released, and rolled back as a single product.
### Negative
- Even a small change requires a new system image release.
- Every image release requires full regression testing.
- Unchanged components are transferred and written again.
- Network traffic and installation time may increase.
- Additional device storage may be required, especially for A/B layouts.
- Individual components cannot easily maintain independent release cycles.
- Hardware-specific differences may require multiple variants of the same product release.
- Every image variant must be built, tested, signed, maintained, and assigned to the correct devices.
## Special Considerations
### Firmware
For many microcontroller-based devices, full-image replacement is the natural and often the only practical OTA model.
Such devices commonly do not provide:
- a filesystem;
- a package manager;
- independently deployable software components;
- a practical mechanism for updating only part of the firmware.
In this context, OTA normally means replacing the complete firmware image.
### Full-System Testing
Full-system image updates do not reduce the required scope of testing.
Even when only one component changes, the complete resulting image must be tested because the change may introduce regressions elsewhere in the system.
The advantage is not that fewer tests are required. The advantage is that the exact image installed on the device is the same image that passed validation.
## Limitations
Full-system image updates are most effective when one software release corresponds to one clearly defined product version.
The approach becomes more difficult to maintain when the fleet contains many devices that are functionally equivalent but differ in small hardware-dependent details, such as:
- peripheral hardware revisions;
- bundled peripheral firmware versions;
- microcode state;
- hardware-specific migration history;
- other small platform-dependent differences.
These differences may create several variants of the same release.
Each variant must be:
- built;
- regression-tested;
- signed;
- stored and maintained;
- assigned to the correct group of devices.
If the number of variants grows quickly, the operational advantages of a single full-system image decrease while release and validation costs increase.
## Applicability
This approach is a strong choice when:
- the software or firmware is treated as one deployable product;
- the cost of an inconsistent system state is high;
- physical recovery is difficult or expensive;
- reliable rollback is required;
- the fleet is relatively homogeneous;
- releases are centrally built and validated.
Other update strategies should be considered when:
- components have independent lifecycles;
- the fleet contains many small hardware variants;
- network usage is a primary constraint;
- available storage is severely limited;
- some components must be updated much more frequently than the rest of the system;
- full regression testing of every image variant is too expensive.
## Alternatives Considered
The following alternatives are addressed in separate ADRs:
- package-based updates;
- container-based updates;
- versioned filesystem trees;
- hybrid update strategies.

View File

@@ -0,0 +1,136 @@
# ADR-005: Package-Based Updates
## Status
Accepted
## Context
An OTA architecture must define the unit of update.
One possible approach is to update individual software components as independent packages.
Unlike full-system image updates, this approach treats the system image as a stable software platform on top of which application components evolve independently.
In embedded Linux, the platform is typically updated separately, while application components are distributed, maintained, and released as independent packages.
## Decision
Use package-based updates for components intentionally designed as independent deployment units that depend only on a specific version of the system platform.
Compatibility between components should be achieved by architecture rather than determined dynamically during installation.
## Decision Drivers
Package-based updates are preferred when:
- the system platform evolves independently from application components;
- application components have their own release lifecycle;
- individual functionality must be updated without releasing a new system image;
- minimizing OTA traffic is desirable;
- hardware variants can be represented by different sets of installed components;
- components are designed to be independent from one another.
## Consequences
### Positive
- Individual components can be updated independently.
- Small changes do not require a new system image.
- OTA download size is reduced.
- A single system image can support multiple hardware models.
- Device functionality can be defined by the installed package set.
- User data and runtime state are naturally preserved because updates affect only the software component rather than the entire system.
- Previous component versions can be retained for downgrade.
- Package authenticity, integrity, and delivery are delegated to the package manager.
### Negative
- Component independence must be designed into the architecture from the beginning.
- Every platform version requires its own package repository.
- The same logical component may exist as multiple binaries built for different platform versions.
- The build infrastructure must maintain multiple platform-specific repositories.
- A package manager does not replace an OTA manager responsible for update policy.
## Special Considerations
### Stable System Platform
Package-based updates do not eliminate the system image.
The system platform is updated independently and defines:
- available libraries;
- ABI compatibility;
- core system services;
- repository structure.
Each platform version uses its own repository containing packages built and validated specifically for that platform.
Compatibility between the platform and application components is therefore established by repository design rather than runtime dependency resolution.
### Component Independence
This approach depends on the application architecture.
Components should be designed to:
- update independently;
- avoid coordinated updates with unrelated components;
- depend only on the system platform;
- expose stable interfaces.
Relationships between packages may describe installation order or device composition, but should not create a tightly coupled application.
### OTA Manager and Package Manager
The package manager is responsible for:
- downloading packages;
- verifying signatures and integrity;
- executing installation scripts;
- replacing files;
- retaining previously installed versions.
The OTA manager is responsible for update policy, including when updates are allowed, network restrictions, user approval, and operational conditions.
Using a package manager alone does not constitute a complete OTA solution.
### Component Rollback
Each component can be upgraded and downgraded independently.
Most package managers retain previously installed versions, allowing an individual component to be rolled back without reverting the entire system.
## Limitations
Package-based updates are most effective when software is intentionally designed as a collection of independent components.
If strong coupling develops between components or multiple packages frequently require synchronized updates, the benefits of this approach diminish and maintenance complexity increases.
## Applicability
This approach is well suited when:
- the system platform changes less frequently than application components;
- device features evolve independently;
- OTA bandwidth should be minimized;
- individual fixes must be released quickly;
- multiple hardware models share the same system platform.
Another approach should be considered when:
- the device is effectively a single firmware image;
- the entire system must always be tested and released as one product;
- most components change together;
- inconsistent system states are unacceptable;
- almost every update affects the complete software stack.
## Alternatives Considered
The following alternatives are described in separate ADRs:
- full-system image updates;
- container-based updates;
- versioned filesystem trees;
- hybrid update strategies.

View File

@@ -0,0 +1,177 @@
# ADR-006: Container-Based Updates
## Status
Accepted
## Context
An OTA architecture must define the unit of update.
One possible approach is to distribute software as a container that includes an application together with the user-space environment required to run it.
Unlike a package-based update, a container is treated as a self-contained delivery unit that may include the application, libraries, runtime components, configuration, and other dependencies.
In embedded Linux, container-based delivery is usually less common than in server environments and should be introduced only when it solves a clear architectural or organizational problem.
## Decision
Use container-based updates only when an application or subsystem must be delivered and maintained as an independent software product with minimal dependence on the target platform's user-space environment.
Do not use containerization as a substitute for a well-designed system architecture.
## Decision Drivers
Container-based updates are preferred when:
- the software subsystem is owned and maintained by a different organization;
- the supplier must support multiple compatible target platforms;
- the application must be delivered with its own user-space environment;
- changes to the host platform should have minimal impact on the delivered subsystem;
- the application or subsystem is maintained as an independent software product;
- the additional storage and runtime overhead are acceptable.
## Consequences
### Positive
- The application is delivered together with its required user-space environment.
- Dependence on the host system's user-space libraries is reduced.
- A supplier can maintain a single delivery for multiple compatible platforms.
- Independent subsystems can follow their own release lifecycle.
- Conflicts between library versions used by separate subsystems are less likely.
- The ownership boundary between the subsystem supplier and the device integrator becomes explicit.
### Negative
- The delivered artifact is larger.
- Libraries and supporting components may be duplicated across containers.
- A container update typically replaces the container as a whole.
- Diagnosing and maintaining third-party containers is more difficult.
- The device integrator loses visibility and control over part of the delivered software.
- The container may become a black box whose internal composition is controlled by the supplier.
- The integrator may not know which library versions, build options, patches, tools, or auxiliary processes are present.
- Internal defects often cannot be corrected without supplier involvement.
- The container runtime becomes an additional part of the maintained platform.
## Special Considerations
### Independent Supplier
Container-based delivery is most useful when a subsystem is supplied by a third party.
It allows the supplier to distribute an almost complete software environment without adapting it to every customer's user-space platform.
For the system integrator, this may simplify initial integration. It also reduces control over the subsystem's internal design and maintenance.
Delivery convenience does not remove operational responsibility. The integrator must still supervise startup, resource usage, logging, health, updates, and interaction with the rest of the device.
### Containers as Black Boxes
Bundling a complete user-space environment transfers part of the control from the integrator to the supplier.
Even when familiar libraries are included, the integrator may not be able to determine:
- how they were built;
- which patches were applied;
- which optional features were enabled;
- which additional dependencies were included;
- which background processes are started;
- what changed between container releases.
This complicates auditing, debugging, security review, and impact analysis.
The less transparent the container contents are, the more the integrator depends on the supplier's release process, documentation, and long-term support.
### Containerization Does Not Replace Architecture
If the entire software stack is developed and maintained by one organization, the benefits of containerization are often limited.
A well-designed package-based architecture can frequently provide similar lifecycle independence without introducing a separate user-space environment for each component.
Containerization does not correct:
- tightly coupled components;
- unstable interfaces;
- incorrect state management;
- poor service lifecycle design;
- inadequate observability;
- weak diagnostics.
Wrapping a poorly designed component in a container does not make it independent.
### Fault Isolation
Containers are often presented as a fault-tolerance mechanism.
In most embedded Linux systems, user-space processes are already isolated by the operating system. A correctly designed service can fail without terminating unrelated services and can be restarted by a supervisor, watchdog, or service manager.
Restarting a container therefore does not necessarily provide stronger fault isolation than restarting a process, and may consume more time and resources.
Containerization also does not protect against a shared kernel failure. A kernel panic remains fatal to both containerized and non-containerized user-space architectures.
Systems that isolate complete operating systems under a hypervisor or a safety-certified RTOS use a different architectural model and are outside the scope of this ADR.
### Different Library Versions
Containers can be useful when independent subsystems require incompatible versions of the same libraries.
However, this does not always require full containerization.
In many embedded Linux systems, a component can ship with private libraries in its own directory and load them independently from the platform-wide versions.
Different library requirements alone are therefore not sufficient justification for introducing containers.
## Limitations
Containerization does not eliminate software maintenance.
It transfers part of the responsibility for the user-space environment from the device developer to the container supplier.
If the supplier does not provide timely bug fixes, security updates, or new compatible releases, the integrator may have little practical ability to maintain the container internals independently.
Container updates and rollbacks may also replace the entire bundled user space even when only one internal component changed.
This approach therefore requires:
- a high level of trust in the supplier;
- a transparent release process;
- documented container contents;
- long-term maintenance commitments;
- clear diagnostic and update procedures.
## Applicability
This approach is well suited when:
- the subsystem is supplied and maintained by an independent organization;
- the supplier must minimize dependence on the customer's user-space platform;
- the application or subsystem is an independently maintained product;
- a clear responsibility boundary between supplier and integrator is required;
- additional storage, memory, and runtime overhead are acceptable;
- independent delivery is more valuable than full control over the implementation.
Another approach should be considered when:
- the complete software stack is developed by one organization;
- components can be delivered as independent packages;
- storage, memory, or OTA download size are critical;
- full control over all device software is required;
- simple component-level rollback is important;
- containers are used only as packaging for ordinary services;
- expected fault tolerance is already provided by Linux process isolation and supervisor mechanisms.
## Alternatives Considered
The following alternatives are described in separate ADRs:
- full-system image updates;
- package-based updates;
- versioned filesystem trees;
- hybrid update strategies.
## Summary
Containerization primarily solves organizational problems related to the delivery and maintenance of independently owned software subsystems.
When all software components are controlled by one engineering organization, a well-designed package-based architecture often provides the same practical benefits with significantly less system complexity.

83
adr/readme.md Normal file
View File

@@ -0,0 +1,83 @@
# Architecture Decision Records
This directory contains Architecture Decision Records (ADRs) used throughout the OTA Reference Design.
Unlike ADRs maintained within a single commercial project, these documents are **not** a historical record of decisions made for one specific product.
Instead, they serve as **reference architectural decisions** illustrating how an experienced engineer might reason about common OTA design problems under different technical constraints.
## Purpose
Each ADR documents:
- the engineering context;
- the decision being considered;
- the factors driving that decision;
- the expected consequences;
- the situations where the decision is appropriate;
- the situations where another approach may be preferable.
The goal is not to declare one solution universally correct.
The goal is to explain **why** a particular decision would be reasonable for a particular class of systems.
## Relationship to the Documentation
The repository intentionally separates three different types of documents.
### Concept Articles (`docs/`)
Concept articles explain the design space.
They answer questions such as:
- What approaches exist?
- How do they work?
- What problems do they solve?
- What trade-offs do they introduce?
Their purpose is education.
### Architecture Decision Records (`adr/`)
ADRs answer a different question:
> Given a particular set of engineering constraints, what decision would be made, and why?
They intentionally focus on architectural reasoning rather than implementation details.
### Decision Matrix
After the individual ADRs, the series concludes with a decision matrix that compares the approaches and helps relate system constraints to architectural choices.
The matrix is not intended to automatically select a solution. Instead, it provides a structured way to evaluate trade-offs.
## Educational Nature
These ADRs are examples.
A real product may reach different conclusions depending on its:
- reliability requirements;
- hardware architecture;
- network constraints;
- operational model;
- regulatory requirements;
- maintenance strategy;
- business priorities.
For that reason, every ADR should be read as:
> "Given these assumptions, this is the architectural decision we would make."
rather than:
> "This is the only correct solution."
## Design Philosophy
Throughout this repository, architectural decisions follow the same principle:
> **Architecture should be driven by system constraints, not by technology preferences.**
The objective is to teach the engineering process behind OTA design rather than promote a specific framework, product, or update mechanism.

View File

@@ -0,0 +1,864 @@
# 02. Choosing an OTA Update Strategy: Full Images, Packages, or Something Else?
In the previous chapter, we defined an OTA update as the controlled delivery and application of a new version of software or data to a remote device.
The next natural question is:
> How should such an update actually be performed?
At first glance, the answer seems simple. There are full-image updates, packages, binary deltas, containers, atomic filesystem trees, and other well-known approaches. All that remains is to compare them and choose the best one.
But this framing starts too late.
Before choosing a technology, we need to answer a more fundamental question:
> **What exactly are we trying to update?**
The entire system? The operating system? A single application? A set of files? Configuration? Certificates? Maps? A machine-learning model?
The answer determines almost everything else: the update unit, storage requirements, verification method, activation mechanism, rollback capability, and acceptable downtime.
In addition, some commonly compared approaches describe different aspects of the process. A full image or a package defines **what the update unit is**. An A/B layout defines **where the new version is prepared and how the system switches between versions**. A binary delta defines **how the amount of transferred data is reduced**. A cryptographic signature defines **how the origin of the update is verified**.
These are not necessarily mutually exclusive choices.
For example, a device may use:
- full system images as the update unit;
- an A/B layout for safe activation;
- binary deltas to reduce network traffic;
- cryptographic signatures to verify authenticity;
- a separate mechanism for configuration updates.
Therefore, choosing an OTA strategy is not selecting one item from a short list. It is the design of several related mechanisms.
---
## 1. What Exactly Is Being Updated?
OTA is often associated exclusively with device firmware. For a small microcontroller, this may be a sufficiently accurate description: new firmware may indeed replace almost all executable content on the device.
An embedded Linux system is usually more complex.
It may include:
```text
Bootloader
Kernel
Device tree
Root filesystem
System libraries
System services
Applications
Configuration
Persistent data
Certificates
Content
```
These components have different lifecycles.
The kernel may be updated rarely. A user application may be updated every month. Configuration may change several times a day. A certificate may be replaced only before it expires. Maps or machine-learning models may have their own independent release cycle.
The first step is therefore to identify the possible update targets.
### 1.1. The Complete System
In this case, an update is treated as a transition from one complete device version to another:
```text
System version N
|
v
System version N + 1
```
The new version may include the kernel, root filesystem, system libraries, services, and applications.
The defining property of this approach is that the system is delivered and tested as a whole. The device does not assemble the new version itself from many independently changing components. It receives a predefined state.
This improves reproducibility:
> The system version installed on the device should match the version built and tested by the build system.
This is the level at which full-image updates, A/B layouts, recovery partitions, and atomic switching between versions are usually considered.
### 1.2. The Operating System
Sometimes the system layer must be updated without replacing the entire contents of the device.
Update targets may include:
- the kernel;
- system libraries;
- system services;
- drivers and modules;
- individual distribution packages.
This approach often relies on a package manager and the existing infrastructure of a Linux distribution.
In this case, the device does not receive a completely prepared new state. It transforms the current system into a new one by installing, removing, or replacing individual components.
### 1.3. Applications
In many products, the base platform changes rarely while application software has a much shorter release cycle.
For example:
```text
Embedded Linux
├── Device manager
├── Communication service
├── Web interface
├── User interface
└── Diagnostics
```
An update may affect only one service or application.
This avoids replacing the entire system for a small application-level change. However, it introduces a new question: is the new application version compatible with the installed libraries, configuration, data schema, and other services?
The smaller the update unit, the smaller the change, but the larger the number of version combinations that may need to be supported.
### 1.4. Data and Content
OTA can update more than executable code.
Examples include:
- configuration;
- calibration data;
- certificates and key material;
- maps;
- voice packages;
- dictionaries;
- machine-learning models;
- filtering rules;
- static user-interface resources;
- parameter databases or diagnostic-code databases.
Such data often cannot reasonably be included in a full system image every time it changes. It may require its own versioning, verification, compatibility, and rollback rules.
For example, a new machine-learning model may require a specific runtime version. A new configuration may be incompatible with an older application. A new certificate may require coordinated changes on both the client and server sides.
Therefore, even a data update remains an architectural problem rather than a simple file transfer.
### 1.5. Multiple Levels at the Same Time
A real product usually has more than one update unit.
For example:
```text
Operating system -> full system image
Applications -> packages or containers
Maps and ML models -> separate artifacts
Configuration -> small atomic documents
Certificates -> dedicated rotation mechanism
```
The operating system may be updated several times per year, applications monthly, data weekly, and configuration whenever necessary.
The question is therefore not:
> How is the device updated?
It is:
> **Which parts of the device are updated, how independently, and how often?**
---
## 2. What Decisions Make Up an OTA Strategy?
The term *update strategy* is often used too broadly. As a result, full images, A/B layouts, deltas, containers, and signatures appear in the same list even though they solve different problems.
It is useful to separate an OTA design into several independent questions.
### 2.1. Update Unit
What is the installable artifact?
- a full image;
- a filesystem;
- a package;
- a container;
- a data set.
### 2.2. Delivery Method
How is the artifact transferred to the device?
- in full;
- compressed;
- as a binary delta;
- in blocks;
- as a stream;
- through a local gateway or intermediate cache.
### 2.3. Installation Method
How is the new version prepared?
- written to an inactive partition;
- applied directly to the running filesystem;
- assembled as a new filesystem tree;
- unpacked into a separate directory;
- imported as a new container image.
### 2.4. Activation Method
When does the new version become active?
- immediately after a file is replaced;
- after a service restart;
- after a device reboot;
- after an atomic symlink or partition switch;
- after confirmation by an external system.
### 2.5. Recovery Method
What happens if the update fails?
- return to the previous partition;
- boot into a recovery system;
- roll back a transaction;
- reinstall the previous package;
- return to the previous filesystem tree;
- require manual service.
These decisions are related, but they are not the same.
For example, a full-image update may or may not use an A/B layout. A package update may be transferred in full or as a delta. A container may be only the application delivery mechanism, while the base operating system is updated with a separate system image.
---
## 3. Full-Image Updates
With a full-image update, the device receives a prebuilt image of the system or one of its major partitions.
The process usually looks like this:
```text
Build system
|
| produces tested image
v
Update server
|
| delivers image
v
Device
|
| writes image
v
New system version
```
Instead of changing individual components sequentially, the device receives a complete version.
### 3.1. Primary Advantage
The main advantage is a reproducible state.
If the image was built and tested as a whole, the device should end up in exactly that state after a successful installation.
With a correct implementation, this reduces the number of possible version combinations:
```text
Version A
Version B
Version C
```
instead of:
```text
Kernel A + library B + service C + application D
Kernel A + library C + service C + application D
Kernel B + library C + service D + application D
...
```
The more independently updated components a system has, the faster the number of possible states grows.
### 3.2. Advantages
- predictable and reproducible system state;
- convenient system-level testing;
- no dependency resolution on the device;
- natural compatibility with an A/B layout;
- relatively clear rollback mechanism;
- the system partition can remain immutable during normal operation;
- easier identification of the exact installed component set.
### 3.3. Disadvantages
- large artifact size;
- increased storage requirements;
- long downloads over slow connections;
- transfer of unchanged data;
- user data and configuration require separate handling;
- a small application change may require releasing a new system image.
### 3.4. Typical Uses
This approach is especially natural for appliance-like devices where the entire system is treated as one product:
- industrial controllers;
- network devices;
- automotive control units;
- medical devices;
- terminals;
- specialized embedded Linux systems.
It is particularly attractive where reliability and reproducibility matter more than minimizing update size.
---
## 4. Package-Based Updates
With a package-based approach, the system is updated by installing or replacing individual packages.
These may use standard Linux mechanisms such as:
- `deb`;
- `rpm`;
- `opkg`;
or a custom package format created for a specific product.
A package usually contains:
- files;
- metadata;
- a version;
- dependencies;
- installation instructions;
- sometimes pre-installation and post-installation scripts.
### 4.1. Primary Advantage
Packages allow only the changed components to be updated.
If one service has been fixed, there is no need to transfer and replace the entire filesystem.
This is especially convenient when the device is already based on a maintained Linux distribution and its components have relatively independent lifecycles.
### 4.2. Advantages
- smaller update size;
- reuse of an existing ecosystem;
- independent component release cycles;
- only required changes need to be installed;
- a familiar model for Linux engineers;
- convenient dependency management when the repository is tightly controlled.
### 4.3. Disadvantages
- a large number of possible system states;
- dependence on correct dependency resolution;
- installation scripts may fail after partial execution;
- system-wide atomicity is more difficult;
- rolling back a package does not always restore the previous state;
- data and configuration migrations may be irreversible;
- the result may depend on the initial state of the device.
The last point is especially important.
If two devices begin the update from different states, the same sequence of package operations does not necessarily produce exactly the same final state.
### 4.4. A Package Manager Does Not Exclude OTA
Using a package manager does not make a mechanism “not real OTA.”
OTA describes the remote delivery and controlled application of an update. A package manager can absolutely be part of such a system.
The critical questions are not whether the implementation uses `apt`, `rpm`, `opkg`, or a custom installer, but:
- who controls the repository;
- how package authenticity is verified;
- which version transitions are allowed;
- what happens if power is lost;
- how partial installation is detected;
- whether a working state can be recovered;
- how every supported update path is tested.
A package manager alone solves only part of the OTA problem.
---
## 5. Container-Based Updates
A container image may be used as the delivery and execution unit for an application.
In this model, the base operating system provides a container runtime, while application components are delivered separately.
```text
Host operating system
├── Container A
├── Container B
└── Container C
```
Updating an application may consist of downloading a new image and switching to it.
### 5.1. Advantages
- the application is delivered with a significant part of its dependencies;
- strong component isolation;
- convenient versioning;
- relatively simple return to a previous image;
- reuse of existing build and registry infrastructure;
- applications can have independent release cycles.
### 5.2. Disadvantages
- the container runtime becomes part of the trusted platform;
- storage and memory requirements increase;
- another operational layer is introduced;
- application state still requires separate management;
- container updates do not update the kernel, drivers, or base operating system;
- desktop or cloud practices cannot automatically be transferred to a constrained embedded device.
Containers do not replace OTA architecture. They may become one layer of it.
For example:
```text
Base OS -> A/B system images
Applications -> containers
Configuration -> signed documents
```
---
## 6. Atomic Filesystem Trees and Versioned System States
Between full images and traditional packages are approaches in which the system is represented as a versioned filesystem tree.
A new version is assembled separately, after which the device atomically switches to it. Unchanged objects may be reused, so a fully independent image does not always need to be transferred or stored.
Concepts in this class include:
- content-addressed storage;
- immutable filesystem trees;
- snapshot-based deployments;
- OSTree-like models.
The central idea is:
> The update is neither an in-place set of file changes nor necessarily a complete block image. It is a complete versioned filesystem state.
### 6.1. Advantages
- atomic switching between versions;
- reproducible system state;
- reuse of unchanged content;
- convenient rollback to a previous tree;
- fewer changes to the running system;
- a useful compromise between images and packages.
### 6.2. Disadvantages
- more complex storage model;
- additional build-tooling requirements;
- garbage collection and multi-version management;
- state outside the managed tree requires separate handling;
- integration with the bootloader and early boot may be non-trivial;
- the approach may be excessive for a simple device.
This mechanism can be attractive, but its benefits appear only when the entire system lifecycle is genuinely designed around immutable, versioned states.
---
## 7. Binary Delta Updates
A binary delta contains the difference between a known old version and a new version rather than the complete new artifact.
Conceptually:
```text
Old artifact + Delta = New artifact
```
This may significantly reduce the amount of transferred data, especially when only a small portion of the artifact has changed.
However, a delta is not a separate answer to the question of what is being updated.
It may be applied to:
- a system image;
- a partition;
- a package;
- a container layer;
- an individual file;
- a model or data set.
It is therefore more accurate to treat a binary delta as a **delivery optimization**, not as an update unit.
### 7.1. Advantages
- lower network traffic;
- faster download over slow connections;
- reduced mobile or satellite data cost;
- the ability to update large artifacts through a constrained channel.
### 7.2. Disadvantages
- the delta depends on a specific source version;
- multiple update paths may need to be stored or generated;
- corruption of the source artifact may make application impossible;
- the device requires resources to reconstruct the new version;
- both server-side and device-side complexity increase;
- the delta must be verified as strictly as the full artifact;
- savings may be small when changes are poorly localized.
For example, updating from version `1.0` to `1.1` may require one delta, while updating from `0.8` to `1.1` requires another.
With many supported versions, update paths multiply:
```text
0.8 -> 1.1
0.9 -> 1.1
1.0 -> 1.1
1.0 -> 1.0.1 -> 1.1
```
The more possible paths there are, the harder they are to create, test, and maintain.
Reduced network traffic is therefore purchased with additional system complexity.
---
## 8. Updating Individual Files and Data
The smallest update unit is an individual file or a small group of files.
This is a natural approach for:
- configuration;
- certificates;
- rules;
- calibration data;
- static content;
- models;
- maps;
- user-interface resources.
At first glance, such an update seems simple: download a file and replace the old one.
A reliable implementation still needs to answer:
- how the version is checked;
- how authenticity is verified;
- how integrity is verified;
- how compatibility is verified;
- how a partially written file is avoided;
- how replacement is made atomic;
- what happens if power is lost;
- how the previous version is preserved;
- who confirms successful activation.
Even a small file can render the device unusable if it contains critical configuration.
Artifact size does not determine the cost of failure.
---
## 9. Hybrid Strategies
In most complex products, the most reasonable solution is a combination of several mechanisms.
For example:
```text
Bootloader and base OS
-> signed full images
-> A/B installation
-> reboot-based activation
Applications
-> packages or containers
-> independent release cycle
Maps and ML models
-> separate artifacts
-> optional delta delivery
Configuration
-> small signed documents
-> atomic replacement
Certificates
-> dedicated rotation protocol
```
This allows different properties to be applied to different components.
For the base system, the priority may be reliability and reproducibility. For maps, it may be minimal network traffic. For applications, rapid release. For certificates, strict coordination and limited validity periods.
### 9.1. Advantages
- each data type receives an appropriate mechanism;
- the entire system does not need to be updated for a small change;
- reliability, bandwidth, and release speed can be optimized independently;
- the design reflects the real lifecycle of each component.
### 9.2. Disadvantages
- multiple mechanisms must be designed, tested, and maintained;
- compatibility modelling becomes more complex;
- identifying the complete product version becomes more difficult;
- dependencies may exist between separate update channels;
- rolling back one component may require rolling back others;
- observability and diagnostics become more complex.
A hybrid strategy must not become an accidental collection of unrelated mechanisms.
Each independent update channel should exist for a concrete reason:
- a different lifecycle;
- a different transfer cost;
- a different cost of failure;
- different activation requirements;
- a need for organizational independence.
Without such a reason, an additional mechanism only increases system complexity.
---
## 10. Why There Is No Best Strategy
The question:
> Which OTA strategy is best?
has no universal answer.
A full image may be an excellent choice for an industrial controller and too expensive for a device using satellite connectivity.
Packages may fit naturally into a Linux gateway and create an unacceptable number of states in a safety-critical system.
Containers may simplify independent application releases while adding a pointless operational layer to a small device.
A binary delta may dramatically reduce transfer cost while introducing more complexity than the rest of the updater.
The correct question is:
> **What constraints does our system have, and which update properties matter most?**
### 10.1. Reliability
What happens if power is lost in the middle of installation?
Must the device always return to the previous version?
Is manual recovery acceptable?
The more expensive physical access is, the more valuable atomic installation and automatic rollback become.
### 10.2. Storage Capacity
Is there enough space for two complete system images?
Can the device store the downloaded artifact while also constructing the new version?
How many previous versions must be retained?
Limited storage may exclude some approaches or require a more complex streaming installation process.
### 10.3. Connectivity Cost and Quality
Does the device use Ethernet, Wi-Fi, mobile, or satellite connectivity?
Is the connection stable or frequently interrupted?
Is traffic expensive?
Can downloads safely resume?
Over an expensive link, the complexity of delta updates may be justified. On a cheap local network, a full image may be simpler and cheaper to operate.
### 10.4. Update Frequency
Is the system updated once per year or several times per day?
Rare system updates and frequent data updates naturally require different mechanisms.
The more frequently a component changes, the more valuable an independent release cycle becomes.
### 10.5. Component Independence
Can the components really be updated independently?
Are their interfaces stable?
Is compatibility between versions maintained?
Independent delivery does not imply independent operation. If application version `5` requires library version `3`, the two must still be coordinated.
### 10.6. Cost of Failure
What happens if an update is unusable?
Does the device temporarily lose a minor feature? Stop a production line? Make a vehicle unavailable? Require a technician visit?
The same technical failure may have completely different consequences in different products.
### 10.7. Downtime Requirements
Can the device be rebooted?
How long may version activation take?
Is restarting one service acceptable?
Some systems may update overnight with a full reboot. Others must preserve their primary function almost continuously.
### 10.8. Support Lifetime
How many years will the device remain in service?
Must the system support updates from very old versions?
Will a team still be available to maintain a complex mechanism ten years from now?
The OTA architecture must not only be technically possible today. It must remain maintainable throughout the entire product lifecycle.
### 10.9. Team Capabilities
A complex solution does not become a good solution merely because it is technically elegant.
The team must be able to:
- build artifacts;
- test update paths;
- operate server infrastructure;
- investigate failed updates;
- manage cryptographic keys;
- maintain compatibility;
- recover devices.
If potential traffic savings require a mechanism the team cannot operate reliably, the optimization may increase the total cost of the product.
---
## 11. Strategy Is a Consequence of Constraints
OTA selection should not begin with a technology name.
It should begin with a model of the product:
```text
What is updated?
|
v
How often is it updated?
|
v
How expensive is failure?
|
v
What resources are available?
|
v
What recovery guarantees are required?
|
v
Which mechanism satisfies these constraints?
```
Therefore:
> **An OTA strategy is a consequence of system constraints, not a choice of the newest or most popular technology.**
The engineering process should look approximately like this:
1. Identify every independently updateable component.
2. Describe the lifecycle of each component.
3. Determine the cost of a failed update.
4. Record storage, memory, power, and connectivity constraints.
5. Define atomicity, activation, and rollback requirements.
6. Select an update unit for each component.
7. Only then choose specific technologies and tools.
The order matters.
If the process starts with a tool, the architecture will be forced to fit the tool's capabilities. If it starts with constraints, the tool can be selected for the actual problem.
---
## 12. Preliminary Comparison
The following table is not yet a complete decision matrix. It only summarizes the primary properties of the approaches discussed in this chapter.
| Approach | Primary Unit | Main Strength | Main Cost |
|---|---|---|---|
| Full image | System or partition | Reproducibility and predictable rollback | Artifact size and storage requirements |
| Packages | System component | Independent component updates | Many possible states and difficult rollback |
| Application | Individual service or bundle | Fast independent releases | Platform compatibility |
| Container | Application with dependencies | Isolation and controlled delivery | Additional runtime and operational complexity |
| Filesystem tree | Complete filesystem state | Atomicity with content reuse | More complex storage model |
| Binary delta | Difference between artifact versions | Reduced network traffic | Dependence on the source version |
| Individual files | Configuration or data | Small and targeted changes | Atomicity and compatibility must be designed explicitly |
| Hybrid model | Multiple update units | Optimization for different lifecycles | Overall system complexity |
There is intentionally no *best option* column.
The same approach may be strong or weak depending on context.
---
## 13. What Comes Next
This chapter describes the space of possible solutions, but it does not declare a single winner.
The next step will be a series of Architecture Decision Records in which each option is evaluated in the context of specific constraints.
Each ADR should answer not:
> What is this technology?
but:
> **Under which conditions would I choose it, and which consequences of that decision would I be prepared to accept?**
The following topics will be considered separately:
- when to choose full-image updates;
- when to choose package-based updates;
- when to update individual applications;
- when to use containers;
- when binary deltas are justified;
- when versioned filesystem trees are appropriate;
- how to design a hybrid strategy.
The results will then be summarized in a decision matrix.
The matrix should not select a solution automatically. Its purpose is to show which constraints push the architecture toward a particular approach and where trade-offs begin to conflict.
---
## Conclusion
An OTA update cannot be reduced to a choice between full images and packages.
A real system must separately define:
- what is updated;
- how independently it is updated;
- how it is delivered;
- where it is prepared;
- how it is activated;
- how it is verified;
- how it is rolled back;
- what happens when something fails.
Full images, packages, containers, filesystem trees, and individual files define different units of system management. A/B layouts, deltas, signatures, integrity checks, and recovery mechanisms add the properties required around those units.
A good OTA design therefore does not begin with a technology.
It begins with constraints, the product lifecycle, and an honest answer to the question:
> **What device state must we guarantee after every possible update outcome?**