# Build Linux IoT and Edge archive Apps

Ionoid.io IoT and Edge Linux apps are archive files that bundle the application, libraries, files and other dependencies. Using some of Linux Containers Technology to implement file system isolation, devices are able to run multiple applications isolated from one another.

This section describes how to build archive Linux apps that can run on any Linux device. To be able to deploy the archive with Ionoid.io and run it on devices, the archive must then include the app YAML file inside the root directory / of the archive.

# Linux Containers Concept

Linux containers are a modern technology that packages the application and all its dependencies so the applications can run on any Linux system. Ionoid.io supports Linux containers by using the widely supported classic archive files format; this is motivated by the fact that IoT and Edge devices should have a long life time, and by using archive files for application packages, Ionoid.io ensures archive apps will continue to work in the future, as all the necessary tools to process them are standard open source tools.

At run-time when the archive file is deployed on devices, the app YAML file that is on the root directory / of the archive will be used to define how the application will run.

Ionoid.io makes minimal use of Linux containers technologies by just using file system isolation, where each deployed application will have its own correspondig directory, see previous chapter IoT Apps.

# Docker buildx Archive Apps

Docker offers the necessary tooling to build and export archive apps. The following steps demonstrates on how to pull a Node.js docker image for ARMv7 and export it into an archive app, that is then deployed directly using Ionoid.io deployment.

# Prerequisite

Before exporting Docker images, make sure to have all the required tools installed:

TIP

Run the following commands with sudo whenever it is necessary.

  • Install Docker and buildx for multi-architectures using the following tutorial: docker and buildx for multi-architecture images, then register Arm executables or other architectures to run on x64 machines.

  • Enable Docker experimental features by editing (create it if not present) the file /etc/docker/daemon.json with your favorite text editor (here we use nano):

    sudo nano /etc/docker/daemon.json
    

    Then add the experimental feature there:

    {
      "experimental": true
    }
    
  • Save the file and restart Docker:

    sudo systemctl restart docker
    
  • Install undocker which allows to extract Docker image layers to a directory:

    pip3 install undocker
    

    Use sudo if required.

# Steps to extract and export docker images: Node.js example

TIP

Run the following commands with sudo whenever it is necessary.

  1. Pull Node.js for ARMv7 image based on Alpine Linux:
docker pull --platform linux/arm/v7 node:current-alpine

The docker images command should return the line of the node repository:

REPOSITORY    TAG               IMAGE ID        CREATED         SIZE
node          current-alpine    013139600021    19 hours ago    107MB
  1. Extract the docker image layers, the following command will extract the image layers into the directory node-armv7/:
docker save node | undocker --no-whiteouts -d -i -o node-armv7 node:current-alpine

Where node:current-alpine is the repository:tag pair of desired image.

  1. Create the app.yaml file inside the node-armv7 directory with the following content:
name: node-armv7
version: v14.10.0
apps:
  node-armv7:
    command: /usr/local/bin/node --version

Where /usr/local/bin/node is the node executable binary path inside the node-armv7 directory (make sure it is the correct path).

  1. Tar compress application and produce the app archive from parent directory of node-armv7:
sudo tar --numeric-owner --create --auto-compress \
        --xattrs --file node-v14.10.0-armv7.tar.gz \
        --directory node-armv7 --transform='s,^./,,' .

The final size of app archive in this case is:

node-v14.10.0-armv7.tar.gz  36M

A copy of the built node.js archive can be found here

  1. Upload and deploy your application by following documentation at deploy IoT apps documentation

  2. Later you are able to update your application using the Delta Update Workflow

Example of a delta update of node.js from v14.10 to v14.10.1

Taking a real example of Node.js for Alpine and using docker container tags: node:14.10-alpine3.11 and node:14.10.1-alpine3.11 for ARMv7 platform, the following performs an update of node.js but also dependencies and Alpine packages:

# Lines starting with `#` are comments.

# Pull the containers, here we assume you build yours.
docker pull --platform linux/arm/v7 node:14.10-alpine3.11
docker pull --platform linux/arm/v7 node:14.10.1-alpine3.11

# Check the images
docker images

# Save the container image to a directory
docker save node | undocker --no-whiteouts -d -i \
        -o node-14.10-alpine3.11-armv7 node:14.10-alpine3.11
docker save node | undocker --no-whiteouts -d -i \
        -o node-14.10.1-alpine3.11-armv7 node:14.10.1-alpine3.11

# Add the app.yaml file
cp app.yaml node-14.10-alpine3.11-armv7/
cp app.yaml node-14.10.1-alpine3.11-armv7/


# Tar compress directories to an App archive
sudo tar --numeric-owner --create --auto-compress --xattrs --xattrs-include=* \
        --file node-14.10-alpine3.11-armv7.tar.gz \
        --directory node-14.10-alpine3.11-armv7/ --transform='s,^./,,' .
sudo tar --numeric-owner --create --auto-compress --xattrs --xattrs-include=* \
        --file node-14.10.1-alpine3.11-armv7.tar.gz \
        --directory node-14.10.1-alpine3.11-armv7/ --transform='s,^./,,' .

# Check app archive size
node-14.10-alpine3.11-armv7.tar.gz 37M
node-14.10.1-alpine3.11-armv7.tar.gz 38M


# Produce a delta update of Node from 14.10 to 14.10-1
# (this will update dependecies and some modules too)
# Add -f to force ovewrite previous app.xdelta if any.
xdelta3 -e -s node-14.10-alpine3.11-armv7.tar.gz node-14.10.1-alpine3.11-armv7.tar.gz \
        app.xdelta

# Check app.xdelta size
app.xdelta 11M

The produced app.xdelta size is 11M which represents 70% reduction of the update size. Here we performed an Node.js, its modules and other packages update.

Usually an incremental update of only some files of the app will result in few kilobytes or even less.

To update your application from a specified version to any other version directly, please follow the Delta Update workflow.

# The mkiot (make IoT) Tool

To generate the app archive we can use mkiot, which uses debootstrap and other tools to build an app archive.

The mkiot tool allows us to:

  1. Install a Linux distribution file system that will be used as a build image for the application,

  2. Build the application,

  3. Copy application files and other dependencies into image,

  4. Copy the app.yaml file into the image,

  5. Generate an artifact from the image.

Please follow mkiot installation documentation and install it on your Linux working station.

# Linux IoT Build Environments

This section describes how to generate IoT and Edge apps build environments using mkiot.

Building an IoT app can somehow be challening, usually we suggest to start with a full build enviroment, then try to optimize later using mkiot multi-stage builds to reduce the final image size.

Ionoid.io supports Debian and Alpine Linux images, more will be added soon.

Assuming mkiot is installed and ready, let's start building our environments and apps.

# Debian Environment

From the mkiot examples we use the Debian minimal buildspec.yaml:

sudo mkiot build examples/debian/buildspec.yaml

This will generate an artifact in tar archive format at:

./output/artifacts/debian-buster_armhf_2020-06-11.tar

If you want to generate a Debian environment with development tools and packages, you can use the Debian devtools buildspec.yaml example and edit it to add more commands or packages to be installed in commands:

sudo mkiot build examples/devtools/debian/buster/buildspec-devtools-armhf.yaml

This will generate an artifact in tar archive format at:

./output/artifacts/devtools_debian-buster_armhf.tar

# Alpine Environment

Under development, will be added soon.

# Node.js Apps

Node.js is an open source, cross-platform, JavaScript runtime environment that executes JavaScript code outside a web browser. See Wikipedia for more details.

We can build a Node.js environment using one of the supported distributions as a base image for the file system.

The following examples demonstrate how to use mkiot to build a Node.js environment that is targeted to ARMv7 architectures, as Node.js only supports ARMv7 and above, for further documentation please see the Node.js Download page.

# Node.js Debian Based Image

To have a Node.js environment from upstream Node.js package on a minimal Debian file system, run mkiot with the following Node.js minimal Debian buildspec.yaml:

sudo mkiot build examples/node.js/debian/buster/buildspec-node.js-minimal-debian-armhf.yaml

To have Node.js installed as a binary on a Debian file system, with extra packages like devtools , build essential or yarn, run mkiot build with the following Node.js devtools Debian buildspec.yaml:

sudo mkiot build examples/node.js/14/buster/buildspec-node.js-devtools-debian-armv7l.yaml

Produced artifacts will be inside ./output/artifacts/ in the current working directory.

To change the environment in order to update which packages or denpendecies should be installed or removed, please copy and edit the buildspec.yaml files. Make sure to copy in script file that is used during build to the right location too, according to mkiot script command.

# Node.js Alpine Based Image

To have a Node.js environment from upsteam Alpine Linux, run mkiot with the following Node.js minimal Alpine Linux buildspec.yaml

sudo mkiot build examples/node.js/alpine/buildspec-node.js_minimal_alpine_armhf.yaml

To have Node.js installed with some development tools to build npm packages, run mkiot build with the following Node.js build-base Alpine buildspec.yaml:

sudo mkiot build examples/node.js/alpine/buildspec-node.js_build-base_alpine_armhf.yaml

Produced artifacts will be inside ./output/artifacts/ in the current working directory.

To change the environment in order to update which packages or denpendecies should be installed or removed, please copy and edit the buildspec.yaml files. Make sure to copy in script file that is used during build to the right location too, according to mkiot script command.

# Node.js Apps Examples

# Node.js Debian based apps

  • Hello-world app can be built using:

    • hello-world.js app

    • app.yaml file

    • hello world buildspec files

    • In buildspec.yaml file, we add to the artifacts block the files block to copy the app.yaml and the app python file to the image:

         files:
             # copy app.yaml to root artifact /app.yaml
             - app.yaml /app.yaml
      
             # copy my application
             - hello-world.js  /usr/bin/hello-world.js
      
    • Then build this example from mkiot source:

         cd examples/apps/hello-world/node.js/
         sudo mkiot build debian/buster/hello-world_node-14.0_minimal_debian_armhf.yaml
      
    • This will generate the final artifact inside ./output/artifact/.

  • Node-RED - Low-code programming for event-driven applications

    • Node-RED is a programming tool for wiring together hardware devices, APIs and online services in new and interesting ways.

    • Node-RED artifacts can be built using the following build Node-RED documentation.

  • More applications will be added soon.

# Node.js Alpine based apps

  • More applications will be added soon.

# Python Apps

Python is an interpreted, high-level, general-purpose programming language. See Wikipedia for more details.

# Python Debian Based Image

The following examples demonstrate how to use mkiot to build a Python environment that is targeted to ARM architectures.

To have a python2 environment on minimal Debian, run mkiot build with the Python2 on minimal Debian buildspec.yaml file:

sudo mkiot build examples/python/debian/buster/buildspec-python2-minimal-debian-armhf.yaml

To have a python3 environment on minimal Debian, run mkiot build with the Python3 on minimal Debian buildspec.yaml file:

sudo mkiot build examples/python/debian/buster/buildspec-python3-minimal-debian-armhf.yaml

To have a python3 environment on Debian with some development packages, run mkiot build with the Python3 on devtools Debian buildspec.yaml file:

sudo mkiot build examples/python/debian/buster/buildspec-python3-devtools-debian-armhf.yaml

# Python Alpine Based Image

The following examples demonstrate how to use mkiot to build a Python environment based on Alpine Linux that is targeted to ARM architectures.

To have a python2 environment on minimal Alpine Linux, run mkiot build with the Python2 on minimal Debian buildspec.yaml file:

sudo mkiot build examples/python/debian/buster/buildspec-python2-minimal-debian-armhf.yaml

To have a python3 environment on minimal Debian, run mkiot build with the Python3 on minimal Debian buildspec.yaml file:

sudo mkiot build examples/python/debian/buster/buildspec-python3-minimal-debian-armhf.yaml

To have a python3 environment on Debian with some development packages, run mkiot build with the Python3 on devtools Debian buildspec.yaml file:

# Python Apps Examples

# Python Debian based app

  • Hello-world app can be built using:

    • hello-world.py app

    • app.yaml file

    • hello world buildspec files

    • In buildspec.yaml file, we add to the artifacts block the files block to copy the app.yaml and the app python file to the image:

         files:
             # copy app.yaml to root artifact /app.yaml
             - app.yaml /app.yaml
      
             # copy my application
             - hello-world.py  /usr/bin/hello-world.py
      
    • Then build this example from mkiot source:

         cd examples/apps/hello-world/python/
         sudo mkiot build debian/buster/hello-world_python3_minimal_debian_armhf.yaml
      
    • This will generate the final artifact inside ./output/artifact/.

  • Tensor flow app

# Python Alpine based app

Will be added soon.

Have Questions?

We're always happy to help with IoT projects or other questions you might have! Check our documentation, contact our support team at support@ionoid.io, or our sales team sales@opendevices.io. You can also ask questions on our forums or open an issue on Github.