Pantavisor vs Docker: Why Docker Isn't Enough for Embedded Firmware

The Short Answer

Docker is great. Docker on embedded firmware is a poor fit.

Docker was designed for cloud and server workloads: ephemeral app containers, large hosts, network-attached storage, and an always-running dockerd daemon. Firmware on a 64–512 MB ARM device with eMMC, intermittent connectivity, and the requirement to never brick has different constraints. Pantavisor is built for those constraints from the ground up using LXC system containers.

Pantavisor still consumes Docker images β€” you don’t lose your registry investment β€” but the runtime, update model, and lifecycle are firmware-grade.

At a Glance

Aspect Docker Pantavisor
Runtime dockerd daemon + containerd LXC, no daemon
Footprint ~50–100 MB just for the engine ~1 MB Pantavisor + LXC
Container model Single-process app containers System containers (init + services + fs)
Kernel/BSP Lives on the host, not Docker’s concern A container in the same state
Update unit Docker image layers Content-addressed state objects
Atomic system update ❌ Per-container only βœ… Whole state revision
Automatic rollback on failure ❌ DIY βœ… Built-in (boot + status_goal)
Signed system state ⚠️ Image signing only βœ… PVS over state JSON
Offline / air-gapped use ⚠️ Possible but awkward βœ… Native (local clone, USB push, mirrored Pantahub)
Storage backend overlayfs required overlayfs / squashfs / dm-verity / raw block
Boot dependency Boots after host OS, host services Pantavisor is PID 1

Why Docker Hurts on Embedded

1. The Daemon Tax

dockerd is a long-running root daemon. It eats RAM at idle, owns its own image cache, and is a single point of failure for every container on the box. On a server you don’t notice; on a 256 MB device you do. Pantavisor has no daemon β€” pantavisor is PID 1, and each LXC container is a normal supervised process tree.

2. Kernel and BSP Are Outside the Picture

Docker treats the kernel as a fixed property of the host. To change kernel, drivers, or device tree you need a separate update mechanism (Mender, RAUC, A/B partitions, custom scripts). With Pantavisor, the BSP is just another container in the state JSON β€” kernel updates are the same operation as app updates.

3. No Atomic System Update

Updating multiple Docker containers at once is not atomic. If you update three containers and the second fails, you’re in a half-updated state. Pantavisor switches the entire system state atomically β€” every container in the new revision is in place, or none of them are.

4. Rollback Is Yours to Build

Docker has no concept of “the previous good system state.” When an update breaks the device, you implement rollback yourself. Pantavisor monitors each container against its declared status_goal; if any container fails to reach it, the device automatically reverts to the last good state revision β€” no host-side scripts required.

5. Storage Assumptions Don’t Hold

Docker expects overlayfs and ample writable space for layer caches. Industrial flash often is read-mostly, dm-verity protected, or organized as squashfs for size. Pantavisor’s volume model is flexible: containers can mount squashfs root volumes, dm-verity-checked overlays, or persistent permanent volumes β€” whatever the device’s storage strategy demands.

6. Offline and Air-Gapped Are Second-Class

Pulling Docker images on flaky cellular or in air-gapped networks is painful. Pantavisor’s content-addressed object store ships only changed hashes, supports local mirrors of Pantahub, USB-stick deployment, and full offline operation as first-class workflows.

What Docker Still Does Well

  • Developer ergonomics β€” docker run is unbeatable for local iteration.
  • Image format and registries β€” the OCI ecosystem is huge.
  • Cloud-native tooling β€” Kubernetes, CI runners, sidecars, etc.

Pantavisor doesn’t fight any of that. It treats Docker as an input format:

# Pull any Docker / OCI image and turn it into a Pantavisor container
pvr app add myapp --from=docker://nginx:latest

# Or in a Yocto recipe:
PVR_DOCKER_REF = "asac/alpine-dbus:latest"
inherit pvrexport

Your existing Dockerfiles, registries, and image build pipelines keep producing artifacts. Pantavisor packages them into LXC system containers and ships them as part of a signed, atomic state.

When Docker Alone Is Fine

  • Linux device with plenty of RAM/storage and a stable host OS you don’t update often.
  • Apps are stateless services and rollback is handled at the orchestrator level (k3s, Nomad).
  • You don’t need to update the kernel, drivers, or boot chain through the same pipeline.
  • Connectivity is reliable.

When You Want Pantavisor Instead

  • Real embedded constraints (low RAM, eMMC, possibly read-only rootfs).
  • The kernel/BSP must be updateable through the same OTA channel as apps.
  • Failed updates must never brick β€” automatic rollback is non-negotiable.
  • You need signed, auditable system states for compliance.
  • Devices are deployed in the field with intermittent or air-gapped connectivity.
  • You want one update mechanism for the whole system, not five glued together.

Architectural Summary

Docker on embedded:                    Pantavisor:
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Host OS (build it β”‚                 β”‚ Bootloader             β”‚
β”‚   yourself, OTA   β”‚                 β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚   it yourself)    β”‚                 β”‚ Pantavisor (PID 1)     β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€                 β”‚   β€’ mounts /trails/N/  β”‚
β”‚ dockerd daemon    β”‚                 β”‚   β€’ starts LXCs        β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€                 β”‚   β€’ watches status_goalβ”‚
β”‚ App container     β”‚                 β”‚   β€’ rolls back on fail β”‚
β”‚ App container     β”‚                 β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ App container     β”‚                 β”‚ bsp/  os/  app/  ...   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                 β”‚  (each = LXC container)β”‚
                                      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Key Takeaway

Docker ships apps to servers. Pantavisor ships firmware to devices.

Use Docker for what it’s great at β€” building images and running cloud workloads. Use Pantavisor when the target is a constrained, long-lived, possibly disconnected device that must update its kernel, services, and apps as one signed unit and never brick.

Next Steps