Table of Content
Table of Content
In this article, we will show you how to build and update an IoT application as a Docker container on a fleet of IoT devices using SocketXP’s Over-the-Air(OTA) update feature.
SocketXP is an IoT device management platform that can be used to remotely manage, monitor, access, update and control IoT or any embedded Linux devices at massive scale.
SocketXP’s OTA update feature is extremely useful when you have to deploy software update on a fleet of IoT devices in your customer’s network behind a NAT router or Firewall or out in the field connected via a cellular network.
The OTA update feature can be used to update the following types of artifacts:
- Firmware
- Software packages (Debian, RPM)
- Application binaries
- Docker containers
- Program files
- Config files
- Execute a script or command
on multiple remote devices.
Download and Install SocketXP Agent
Before you can deploy software updates on remote IoT fleet, you need to download and install SocketXP agent on the IoT devices.
Follow our instructions to download and install SocketXP agent on the IoT devices.
You can also follow the instructions in our Getting Started guide to setup the SocketXP agent in your IoT fleet.
Now that your IoT fleet is registered and connected to the SocketXP Cloud Gateway, let’s move on to deploy software updates on the IoT fleet using SocketXP OTA update feature.
Creating and Deploying OTA Updates
Creating and deploying Docker container OTA updates using the tool is a two step process:
- Create and upload an artifact workflow script to the SocketXP Artifact Registry
- Deploy the artifact workflow script on a group of devices
The basic concept behind this two-step approach is to reuse the uploaded artifact to deploy OTA updates on different group of devices.
The workflow script will download Docker container images from a third-party container registry and update the Docker containers running in the target IoT devices.
Simple IoT App Example:
We will be using a simple C program to demonstrate SocketXP’s OTA update capabilities. We will build a Docker container using the compiled C program binary.
Note: We are using a C program for our example but the IoT app can be created using any programming language or script. Eg: Java, C++, Golang, Python, Javascript, C# etc.
The app will print “Hello, OTA update!” every 10 minutes.
We also assume that the app is running as a Linux systemd service in the IoT devices.
/*
* To build: gcc myapp.c -o myapp
* To run: ./myapp
* Output: "Hello, OTA update!"
*/
#include <stdio.h>
#include <unistd.h>
int main() {
while (1) {
printf("Hello, OTA update!\n");
fflush(stdout); // Ensure immediate output
sleep(600); // in seconds
}
return 0;
}
The above C program, the build script and the Dockerfile we will use for this demo can be downloaded from our official git repository here:
Build the App Binary
First, let’s clone the git repository using the link provided above:
$ git clone https://github.com/ampaslabs/ota-update-build-artifacts
For this exercise, we will use the example in the container folder. So let’s get into the container folder.
~/$ cd ota-update-build-artifacts/container
Let’s look into the contents of the container folder.
~/ota-update-build-artifacts/container$ ls
myapp update.sh
~/ota-update-build-artifacts/container$ ls myapp/
Dockerfile makefile myapp.c
The container folder contains the following three items:
A
myappfolder containing ourappcode written in the the C language and amakefileto compile the app and build the app binary. Themyappfolder also includes a Dockerfile that has the necessary instructions to build a Docker container. Themakefilewill eventually build a Docker container image using the Dockerfile and push the image to theDockerHub Registryusing the login credentials provided by the user.An
update.shshell script – the workflow script that runs in the target devices and updates the myapp Docker container.No
make_artifact.shshell script exists for this example because we’ll not build atar.gzstyle artifact using the Docker image. The docker images are uploaded to a thirdy-party container registry (Eg:DockerHub). We will just upload theupdate.shworkflow script to the SocketXP Artifact Registry as a “script” type artifact and deploy container OTA updates using the workflow script.
Create a New Version of the App:
Let’s get into the myapp directory and start building our app.
Before we do that, we will edit the myapp.c file and make it to print "Hello, OTA update! Version 1.0.0". Let’s call it as the version 1.0.0 of the app.
/*
* To build: gcc myapp.c -o myapp
* To run: ./myapp
* Output: "Hello, OTA update!"
*/
#include <stdio.h>
#include <unistd.h>
int main() {
while (1) {
printf("Hello, OTA update! Version 1.0.0\n");
fflush(stdout); // Ensure immediate output
sleep(600); // in seconds
}
return 0;
}
Next build the app and package the app binary into a Docker container image using the "make all" command.
~/ota-update-build-artifacts/container$ cd myapp
~/ota-update-build-artifacts/container/myapp$ make all
gcc -o myapp myapp.c
docker build -t test-user/myapp:1.0.0 .
[+] Building 0.9s (8/8) FINISHED docker:default
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 284B 0.0s
=> [internal] load metadata for docker.io/library/ubuntu:latest 0.9s
...
...
...
~/ota-update-build-artifacts/container/myapp# ls
Dockerfile makefile myapp myapp.c
~/ota-update-build-artifacts/container/myapp$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
test-user/myapp 1.0.0 28a75833fed7 5 minutes ago 101MB
Login to your DockerHub account and verify if the new Docker image version 1.0.0 got pushed to the registry.
Now that we have finished creating a Docker container image for the app, let’s create an OTA update workflow script that specifies how to download and update the newly created containers on IoT devices.
Workflow Script - update.sh
The OTA update workflow script contains all the instructions required to update the myapp Docker container running in the IoT devices.
Let’s quickly look at the contents of the update.sh workflow script.
~/ota-update-build-artifacts/container$ cat update.sh
#!/bin/bash
#================================================
# MyApp Container Update Workflow Script
#================================================
DOCKER_USER="dockerhub-username"
DOCKER_REPO="myapp"
NEW_VERSION="1.0.0"
OLD_VERSION="0.0.1"
CONTAINER_NAME="myapp"
# Function to check if a container is running and healthy
check_container_status() {
local container_id="$1"
local status=$(docker inspect --format='{{.State.Health.Status}}' "$container_id" 2>/dev/null)
local state=$(docker inspect --format='{{.State.Running}}' "$container_id" 2>/dev/null)
if [[ "$state" == "true" ]]; then
if [[ -z "$status" ]]; then
return 0 # Running, no healthcheck
elif [[ "$status" == "healthy" ]]; then
return 0 # Running and healthy
else
return 1 # Running, but unhealthy
fi
else
return 1 # Not running
fi
}
# Function to rollback to the previous version
rollback() {
echo "Rolling back to version $OLD_VERSION..."
# Stop and remove the new container
docker stop "${CONTAINER_NAME}-${NEW_VERSION}" 2>/dev/null
docker rm "${CONTAINER_NAME}-${NEW_VERSION}" 2>/dev/null
# Delete the new image
docker image rm "$DOCKER_USER/$DOCKER_REPO:$NEW_VERSION" 2>/dev/null
# Run the old container
docker start "$${CONTAINER_NAME}-${OLD_VERSION}" 2>/dev/null
}
# Main update process
echo "Updating to version $NEW_VERSION..."
# Pull the new image
docker pull "$DOCKER_USER/$DOCKER_REPO:$NEW_VERSION"
# Stop the old container
docker stop "$${CONTAINER_NAME}-${OLD_VERSION}" 2>/dev/null
# Run the new container
docker run -d --name ${CONTAINER_NAME}-${NEW_VERSION} "$DOCKER_USER/$DOCKER_REPO:$NEW_VERSION"
# Check container status
sleep 30 # Give the container time to start and healthcheck to run. Adjust as needed.
container_id=$(docker ps -q --filter name=${CONTAINER_NAME}-${NEW_VERSION})
if [[ -n "$container_id" ]] && check_container_status "$container_id"; then
echo "Update successful!"
# Clean up the old container and image
docker rm ${CONTAINER_NAME}-${OLD_VERSION} 2>/dev/null
docker image rm "$DOCKER_USER/$DOCKER_REPO:$OLD_VERSION" 2>/dev/null
else
echo "Update failed! Rolling back..."
rollback
echo "Rollback complete."
fi
Explanation:
What the update.sh workflow script does is:
Downloads the new version of the
myappDocker container image1.0.0on the device.Stops the old version (0.0.1) of the
myappDocker container already running in the device. It doesn’t remove the old container yet, but keeps it as a backup. The backup will be restored on failure.Creates a new container named
myapp-1.0.0using the newly downloaded Docker image.Verifies if the newly created container is running successfully. If the new version is running successfully, it will remove the old version of the container in the device.
If the new version of the container fails to run due to an error, the script will stop the container and remove it. The old version of the container will be restored.
Upload the artifact
We will upload the workflow script update.sh directly to the SocketXP Artifact Registry as a script type artifact.
Login to your SocketXP account using the web potal and go to the OTA update page. In the Artifacts table, click the “Upload new artifact” button.
A new window will popup as show below.

Select the artifact type as "script".
Browse and select the update.sh file.
Specify the appropriate version for the artifact, 1.0.0 in this example.
Specify the destination folder in the target device where the script should be downloaded and executed. For example: /tmp or /home/user/myapp or /usr/bin
Specify the command to execute the script in the target device. For example: /bin/bash update.sh
Finally, click the “Upload” button to upload the artifact to the cloud registry.
You’ll see a message saying “File uploaded successfully”
Deploy the Artifact
Now that the artifact has been uploaded to the SocketXP Artifact Registry in the cloud, let’s deploy the artifact on target devices.

From the Artifacts table, view and select the artifact you have just uploaded.
Note: If you don’t see your artifact yet, click the “Refresh” button to reload the table data.
Click the “+” icon next to the artifact to create a new deployment.
A new window will popup, as shown below.

Give a name for the deployment, say for example, “deploy-version-1.0.0-to-test-devices”.
Specify the target device ID or the device group or select a tag to deploy the artifact on.
Note: You can deploy the artifact on a single device ID, or a device group or a device tag. If you want to deploy the artifact on more than one device group or device tag, repeat the “Create New Deployment” process for the different group or tag.
Finally, click the “Create Deployment” button.
Now, go to the “Deployments” tab, hit the refresh button.

View and select the deployment we just created to see its progress.
Click the “More Info < >” button to view and monitor the progress of the deployment on each target devices (in the device group or tag).
Click the “Refresh” button to view the progress.

You can check the stdout and stderr logs generated by the update process, by clicking the “view log” buttons.
Let’s login into one of the devices to check if the myapp deployment is successful.
$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES cdc95577be33 test-user/myapp:1.0.0 "/usr/bin/myapp" 5 minutes ago Up 5 minutes myapp-1.0.0
We can also view the app logs using docker logs command.
$ docker logs myapp-1.0.0 Hello, OTA update! Version 1.0.0
Congratulations! We have successfully updated the myapp Docker container in the remote IoT devices using SocketXP OTA update.
Now that you have learnt how to create and publish a Docker container as OTA updates to remote devices, you can learn to create OTA updates for the following artifacts:
- App Binary
- Debian Package
- Firmware
- Config File
- Script File
