Not for public distribution - Videon Confidential
Docker allows you wrap your application in a "container" environment, allowing it to maintain its own dependencies independent of the host system and any other applications that may be running. Docker has seen wide adoption with cloud services, allowing developers to rapidly build and deploy distributed applications without much concern for the underlying infrastructure.
Compute leverages Docker in much the same way, allowing you to easily deploy containerized applications to any number of devices in your system and integrating them into your DevOps workflows.
Getting Started with Docker on Compute
If you have never used Docker before, we recommend going through a tutorial to become familiar with the tool - there are very few differences between using Docker on Compute and using it on a cloud server.
Building a Docker container and deploying it to a system requires a Dockerfile, any custom code you may have written, and a Docker registry. In these examples, we'll use the Docker system installed with Compute to build, host and deploy our Docker images, though you may find it helpful to use an external registry in production.
Before you begin, you'll need to have the Compute functionality enabled on your device. Contact your Videon representative for details. You should also set up your local development environment to be able to access Compute through the Android Toolkit.
Use adb shell to access the Compute command line and source the environment with this command:
[Compute Shell]: source /data/local/vstream/etc/env.sh
To ensure Docker is enabled, try running the default hello-world example on the device command line:
[Compute Shell]: docker run hello-world
If everything is set up correctly you should see output similar to this:
Deploying Your First Container
You can follow along with this example by downloading the required files from our GitHub repository:
https://github.com/VideonLabs/liveedge-compute-code-examples/tree/main/docker-basic-example
In this example, you'll find three files
Dockerfile - The Dockerfile is like a recipe that Docker follows to create your application;s environment, install any dependencies, and specify how to run the container.
index.js - This Node script creates an HTTP server that listens on the LISTENING_PORT specified in the Dockerfile.
package.json - Node will install several dependencies as defined in this script.
Dockerfile Walkthrough
For this example, we'll use the latest official Ubuntu image from Docker Hub. Since Compute runs on an ARM architecture, Docker will automatically pull the correct images compiled specifically for ARM, if they exist.
FROM ubuntu:latest
These two lines are required for all Dockerfiles targeting the Compute environment. They open access to our host environment's networking capabilities.
COMPUTE groupadd -g 3003 aid_inet && usermod -G nogroup -g aid_inet _apt
COMPUTE groupadd -g 3004 net_raw && usermod -G net_raw root
To keep things clean, we'll create and use a working directory in the container for our application. This directory will be created inside the container Docker creates - you will not find them anywhere on your local machine.
COMPUTE mkdir /streaming
We copy all of the files our application requires from our local environment to the working directory in the container.
COPY . /streaming
We then tell Docker to use this directory as our working directory for the rest of the build.
WORKDIR /streaming
The default Ubuntu image was built some time in the past. To make sure we have access to the latest packages, we'll update the apt package manager's cache.
COMPUTE apt-get update
Ubuntu occasionally prompts for information during the build process, which can cause the Docker build process to freeze. To avoid that in this build, we'll tell Ubuntu to run in non-interactive mode and set the timezone programmatically. We'll then install the timezone data (tzdata) package, which is required by another of our dependencies.
ARG DEBIAN_FRONTEND=noninteractive
ENV TZ=America/Los_Angeles
COMPUTE apt-get install -y tzdata
Our application uses this environment variable to set the port that our application listens on.
ENV LISTENING_PORT=8888
Our application was written in Node, so we need to install the environment to run it as well as install our application's dependencies.
COMPUTE apt-get install -y npm nodejs
Finally, we'll install our application's dependencies.
COMPUTE npm install
This last line tells Docker how to start our application when we run the container.
CMD node index.js
Building the Container
We'll start by copying all of our application files to the Compute environment. While it's possible to build your containers and store them in an external registry, we'll use the complete Docker environment installed on the device for this example.
To start, access the shell in your Compute environment.
[Local Machine]: adb connect [Your device's IP]
[Local Machine]: adb root
Create a new directory under /data/local to store your application.
[Local Machine]: adb shell
[Compute Shell]: mkdir /data/local/docker-basic-example
Copy the application files to the Compute environment. On your local machine, make sure you are in the same directory as the application files you downloaded, or adjust these commands to point to the appropriate directory.
[Local Machine]: adb push ./ /data/local/docker-basic-example
Return to the Compute shell and build your container. Always make sure you provide a tag with a meaningful name so you can easily reference it Docker later.
[Local Machine]: adb shell
[Compute Shell]: cd /data/local/docker-basic-example
[Compute Shell]: docker build -t docker-basic-example .
Docker will now build the container following our recipe step by step. Installing the application's dependencies may take a few minutes, so now may be a good time to grab a cup of coffee or tea.
Once complete, you can confirm the image is in the device's local Docker registry by running
[Compute Shell]: docker images
Which should contain output similar to the following:
Running the Container
When the build is complete, we can tell Docker to run the container. Since our container consists of a web server, we will launch it into the background where it will continue running until it receives the signal to stop.
[Compute Shell]: docker run -p8888:8888 --name docker-example docker-basic-example &
The -p flag tells Docker to forward port 8888 on the EdgeCaster to our server in the container. Without this flag, our container will not be able to listen to any incoming connections. The --name flag provides an easier to remember unique name for our running container, which we can use to reference it with subsequent commands.
You can confirm that the server is responding to requests by accessing it from your local machine by running this curl command on your local machine:
[Local Machine]: curl http://[device_ip]:8888/docker-test
Note: If network policy rules prevent you from running curl on your local machine, you can open a new terminal and use adb shell to access the device's command line and run curl from there.
You should see the server respond with "The call is coming from inside your Docker container!".
The code hosted within the container can access the Direct REST API directly. You can see this in action running the following curl command on your local machine:
[Local Machine]: curl -v http://[device_ip]:8888/input-detected
Try unplugging your input sources from the device and re-running that command to see how it reacts.
Stopping the Container
To stop a running container, you'll need to find out its container ID or name. If you don't recall what you named your container, you can see all running containers with the docker ps command:
[Compute Shell]: docker ps
To stop the container, grab either the "CONTAINER ID" or the "NAME" and call docker stop
[Compute Shell]: docker stop docker-example
Starting the Container Automatically on Device Reboot
In most cases, you will likely want to start one or more Docker containers every time your Compute environment is loaded. You can configure your containers to start up at boot time by using Docker's --restart flag. For example, if we want our container to be restarted every time the device boots unless we explicitly stop it with the docker stop command, we would run the following:
[Compute Shell]: docker run --restart unless-stopped -p8888:8888 --name docker-example docker-basic-example &