A Look Into Nubix's Containerization Technology Leveraging WebAssembly
By Stephen Berard, Nubix CTO
Technologies such as Virtual Machines, Docker and Kubernetes have revolutionized application development in the data center and cloud over the past twenty years. Meanwhile, the development process for embedded devices that leverage constrained microprocessors (MCUs) has remained highly specialized, time consuming, and rigid to innovation. Embedded firmware is still predominantly monolithic in nature - much like how server applications were built before the cloud-native trend started.
Nubix addresses the traditional challenges of embedded development by providing a standardized mechanism and commercially-supported infrastructure for building, deploying, managing and securing containerized applications on constrained edge devices at scale. We implement cloud-native principles (e.g. platform independence, loosely-coupled microservices, CI/CD) while accommodating the constraints of MCUs.
Our device edge orchestration solution enables cloud, AI and IoT developers that don’t have embedded experience to build and deploy containerized apps for the billions of MCU-powered devices that make up the majority of the edge footprint by volume. These tiny, modular apps can serve functions such as TinyML/AI, security and connectivity in any number of industrial and consumer use cases. Target devices include the likes of smart sensors and cameras, IoT gateways, industrial control systems, drones, robots, appliances and toys.
In this blog, I’ll dive into details around our use of WebAssembly as a key enabling technology for Nubix containers. The modularity provided by Nubix containerization greatly improves the flexibility, portability, reliability, maintainability, and security of IoT and edge solutions, extending to constrained edge devices the same benefits that we take for granted in the data center today.
A Shift to the Edge
Over the past several years, edge computing has emerged as a key trend to address latency requirements, reduce bandwidth consumption, increase security and privacy, and enable multi-cloud strategies. Infrastructure providers and developers have been extending cloud-native tools such as Docker and Kubernetes out of the data center to reap their benefits at the edge, however there’s a practical limit to the applicability of these technologies.
While 256GB may be viewed as a “lightweight” memory footprint in a server architecture, 256MB is a typical bare minimum memory footprint for an edge node like an IoT edge gateway running embedded Linux. Meanwhile, the available footprint for a MCU-based device could be well under 256KB, necessitating the use of an RTOS instead of Linux, as well as careful attention to resource utilization. At Nubix, we refer to this as “crossing the Linux barrier”.
Thanks to Moore's Law, available processing and memory is ever-growing across the board, but these are fundamentally different computing paradigms in the edge continuum. In addition to available computing resources, there are also unique considerations around security and autonomy for edge devices deployed outside of physically-secure data centers and will likely be disconnected from a centralized controller for periods of time. All said, a one-size-fits-all approach to edge computing simply doesn’t work.
Embedded Development is Ripe for Modernization
Embedded firmware has traditionally been monolithic and customized for each target device to meet the resource constraints imposed by the hardware. The downside is that this makes it extremely difficult for developers to build intelligent, connected IoT and edge solutions that are easy to maintain, update and differentiate through software-defined innovation. When a code change is made in the traditional embedded model, it can be challenging to ensure that this revision doesn’t affect other parts of the overall compiled code. There’s also a risk of bricking entire devices during remote updates of monolithic firmware, thereby forcing a truck roll.
Additionally, the hard-coupling between embedded firmware and the underlying hardware makes it difficult to reuse code across different projects or devices because there’s no standardized way to package and distribute it. These challenges are multiplied when trying to leverage code from various different ecosystem partners - any change in the supply chain can have a major ripple effect in the field.
Meanwhile, MCU-based devices are becoming increasingly capable in terms of processing, memory and storage. The use of on-device TinyML/AI for functions such as object detection, voice recognition and filtering data is growing rapidly. More consumers are demanding on-device processing for privacy reasons. And in the era of the ecosystem, solution providers need a better way to integrate apps and domain knowledge from various partners without the risk of exposing IP in the form of raw source code. Cloud-native architecture provides this ability through loosely-coupled applications that can be built and updated independently.
The embedded development model is ripe for modernization, and at Nubix our mission is to apply the lessons we’ve learned in the cloud to the unique constraints of the embedded world.
Nubix’s first-generation solution for bringing containerization to constrained edge devices was built around the Lua scripting language. Lua was chosen at the time because it was efficient, portable, and suitable for industrial applications. We received positive feedback from early customers regarding the benefits of app containerization on embedded devices, including faster time to market, increased flexibility, improved security, lower risk during field updates, and better IP protection. However, we identified two key shortcomings with our initial implementation.
First, while Lua offered good overall performance, it was significantly heavier and slower than native code - a key consideration in the embedded and microcontroller space. Second, the architecture required everything to be written and/or re-coded in Lua to take advantage of the benefits. It was clear that we needed a better execution engine.
Over the past several years, it has become apparent that the efficiency, portability and security of WebAssembly makes it well-suited for a wide range of use cases beyond the browser. We’ve seen increasing efforts to leverage WebAssembly for cloud-native development in the data center, and growing exploration of its applicability in IoT and embedded systems.
WebAssembly is ideal for IoT and embedded edge devices because it’s lightweight and designed to be executed in a sandboxed environment. This provides a secure and isolated runtime for applications. This can be particularly valuable for devices that have limited resources or must use custom operating systems because it allows developers to write code in their preferred high-level language (e.g. C, Go, Rust) and then compile it to WebAssembly for execution on the device. Wasm also supports true isolation between containers on devices that don’t have Memory Management Units (MMUs), which is typical of MCU-based hardware.
Nubix began experimenting with WebAssembly in early 2021 to see how well it could be adapted to the embedded space. Our initial proof-of-concept leveraged the Wasm3 engine and yielded positive results. Based on these results, we began to reimplement our overall solution with WebAssembly. In 2022, we migrated to the WebAssembly Micro Runtime VM which provides a number of additional features.
OCI vs. Nubix Containers
Before we dive into what constitutes a Nubix container, let’s first start by describing conventional Open Container Initiative (OCI)-compliant containers such as Docker. An OCI container is a lightweight, portable environment that allows software to run in a consistent manner across different environments. These containers provide an isolated runtime environment that includes everything the application needs to run, such as libraries, configuration files, and system tools. OCI containers provide a powerful and flexible way to package and deploy software applications, enabling developers to easily create, distribute, and run applications in a consistent and reliable manner.
OCI containers, however, require operating system support such as kernel namespaces and control groups which are frequently provided by the Linux kernel. Unfortunately, this doesn’t work on embedded devices as such systems don’t have the ability to run Linux. Instead, they use an embedded or Real Time Operating System (RTOS).
This is where Nubix picks up. We’ve worked hard to make Nubix containers parallel the principles and resulting benefits of OCI containers as closely as possible, while addressing the specific constraints of embedded devices. The table below outlines the key attributes of each containerization technology.
Anatomy of a Nubix Container
As outlined in the table, a Nubix container is composed of several elements. First, there is the executable portion. This is a standard WebAssembly module that runs in our VM. At the moment, only a single Wasm module is supported, but we’re exploring extending this to support multiple modules and/or components via the WebAssembly Component Model. Second, is the configuration which contains all of the metadata such as the application container name, execution properties, variables, permissions, etc. Finally, a set of optional binary objects to be referenced by the Wasm modules can be included. A common use for these objects would be to store an AI/ML model.
A question we often get asked is around the overhead and performance characteristics of our WebAssembly-based containerization solution. While modularity inherently comes with some degree of resource “tax”, Nubix containers provide near-native performance. We accomplish this through the use of Ahead-of-Time (AoT) compilation which translates Wasm code into the native ISA (Infrastructure Set Architecture) of the target device. This process is performed transparently when apps are deployed on devices through the Nubix Orchestration Hub.
As mentioned in my last post, we recently completed replacing FreeRTOS with Zephyr as the reference hardware abstraction layer for our edge device runtime. With the combination of the Zephyr RTOS and our Wasm-based containerization engine, the Nubix Runtime enables containers and applications to run across a wide variety of edge hardware architecture (e.g. Cortex-M and Cortex-A class Arm, x86, RISC-V) with little or no change. This is accomplished by reflecting the underlying driver interfaces into the WebAssembly environment which allows code running in Nubix Containers to call a consistent device API regardless of the underlying physical device or communication bus.
Of note is that while Nubix containers are optimized for MCU-powered devices, they can also be an attractive alternative to OCI-compliant containers like Docker deployed more capable hardware due to their high efficiency. Applicability of each container technology is illustrated against the LF Edge taxonomy below.
Developing for Nubix Containers
OK, so we have Nubix containers - how do we build applications for this environment? One of our design goals was to make it extremely easy to containerize existing code. Unlike our initial design that leveraged Lua scripting, WebAssembly unlocks support for using a multitude of programming languages, including mixing containerized apps written in different languages on the same device.
As an example, a sensor connectivity app could leverage existing C code, whereas discrete, accompanying apps for analytics and cloud connectivity could be written in languages such as Go and Rust. In addition, we provide a POSIX-like programming environment and library support, as well as integration into existing CI/CD workflows. The result is an environment that’s very familiar to embedded and cloud engineers alike.
Today, Nubix provides pre-configured Docker containers with the full development toolchain already installed. This allows developers to get started quickly and without complicated installation steps. A full development environment can be started on a Windows, Linux, or OSX machine in one, simple command. We also provide support for Development Containers which allow you to leverage the development environment in Visual Studio Code or GitHub CodeSpaces.
Related to WebAssembly is the WebAssembly System Interface, or WASI for short. WASI provides a standardized system interface for WebAssembly modules, allowing them to interact with the host system and access system resources such as files, sockets, and threads. WASI is an exciting development and something we’re tracking very closely. Our intention is to be WASI-compliant in order to make it even easier to use the same code across multiple environments.
We have a lot of other exciting features coming soon, including common logging infrastructure, remote debugging, additional security elements, and more!
Nubix’s device edge orchestration solution modernizes embedded development by bringing cloud-native principles and containerization to constrained edge devices that don’t have the resources to support technologies like Docker and Kubernetes.
Our use of WebAssembly for our device containerization engine enables us to offer the same benefits as OCI-compliant containers on hardware that’s not capable of supporting Linux. With the on-device Nubix container runtime paired with our Orchestration Hub, developers can easily create, distribute, and run secure applications on constrained edge devices at scale.
Reach out to us if you’re interested in learning more or to see how our solution can bring the power of cloud-native development and containerization to your next embedded project!