Pre-provisioning Docker Containers onto a Torizon OS image
Introduction
In this article, we cover how to use TorizonCore Builder Tool to pre-provisioning Docker Containers onto a Torizon OS image to be deployed on several units in a production line using Toradex Easy Installer.
Development, Production Programming and Torizon Cloud
The workflow described in this article adds container images to a Toradex Easy Installer image that can be flashed to the hardware for production programming in a single process. It is different from how container are deployed as updates on our Torizon Cloud or during development with the Torizon IDE Extension. The use of each method is recommended in different situations.
In summary, here's when you should use each:
- Use the Torizon IDE Extension: to be used when you are developing and evaluating application containers, the IDE Extension allows you to quickly generate, develop, deploy and debug Docker application containers.
- Pre-provision container images onto Torizon OS: to be used when you are preparing your own custom Torizon OS image for production programming, allowing it to boot with your containers from the first time, without the need to pull those from the internet.
- Upload container images to Torizon Cloud: to be used when you want to update the application on a running fleet of Torizon OS devices, without the need to re-flash the devices. If you want to deploy simultaneously the OS and application with Torizon Cloud, you should use the synchronous update feature of our Torizon Cloud, instead of bundling containers to a Torizon OS image, as explained in this article.
Read the article Deploying Container Images to Torizon OS for a more comprehensive overview of all the methods for deploying containers to a Torizon OS image on various steps of the development cycle.
This article complies with the Typographic Conventions for Torizon Documentation.
Prerequisites
To complete these instructions you need:
- Prerequisites from Configure Build Environment for Torizon Containers installed.
- A Toradex SoM with Torizon installed.
- Having read the Torizoncore Builder - Getting Started article can be helpful.
- A Torizon OS image without evaluation containers downloaded.
- A Docker Compose file referencing the container images to be pre-provisioned (located on a local or a remote registry).
Installing TorizonCore Builder
To install TorizonCore Builder, read our statements on OS and shell compatibility, then follow the instructions below, in order.
Download the setup script into some writable directory in your system (here we use
~/tcbdir/
):$ mkdir -p ~/tcbdir/ && cd ~/tcbdir/
$ wget https://raw.githubusercontent.com/toradex/tcb-env-setup/master/tcb-env-setup.shnoteIf you did this before then you can skip this step unless you want to update the setup script. When you source the script (next step) it will show you a warning message if it determines an update is advisable.
Source the script:
$ cd ~/tcbdir/
$ source tcb-env-setup.shMake sure to do this from every shell instance that you intend to use with TorizonCore Builder. For advanced usage, run
source tcb-env-setup.sh -h
, or see the project README. The latter has information about using the early-access version of the tool for those interested.tip- Remember to source the setup script every time you start a new terminal (or shell instance).
- The setup script installs a Bash completion script for TorizonCore Builder, making it possible to autocomplete commands and parameters by just pressing the TAB key.
Beware that under Windows, you must pass extra parameters to the script when the use of the following commands is intended:
ostree serve
: consult the ostree serve reference.
Verify that the command
torizoncore-builder
is available:$ torizoncore-builder --help
Pre-provisioning Docker Containers onto a Torizon OS image
The process to preinstall or pre-provision Docker Containers onto that installer image comprises two stages:
Bundling the Docker Containers: This step creates a tarball containing all the containers as well as a Docker Compose file referencing those containers using a specific hash.
Applying the Docker Containers Bundle to a Torizon OS image: In this step, the tool takes a Toradex Easy Installer image of Torizon OS (with the Docker engine) and combines it with the previously bundled Docker Containers.
Bundling the Docker Container Images
The downloading (pulling) of Docker container images from the Docker registries is done with TorizonCore Builder bundle
command. This command takes a configuration Docker Compose YAML file as input and generates a directory, with name and location defined in the --bundle-directory
argument, with the bundled (downloaded from the Docker registries) Docker container images. You can learn more about this command at our command manual.
A sample Docker Compose YAML file can be downloaded, based on your device, by clicking one of the links below:
With a Docker Compose YAML file present in your working directory, execute the command below:
$ torizoncore-builder bundle docker-compose.yml --bundle-directory bundle
The container bundle tarball along with a modified version of the Docker Compose file will be located at the new directory bundle
in your working directory.
In case you are referencing multi-platform container images, the above command will likely fail because no platform was specified. To solve this, you should pass the --platform
switch selecting the appropriate platform which depends on the target device.
For devices based on i.MX6/i.MX7 based SoMs:
$ torizoncore-builder bundle --platform=linux/arm/v7 docker-compose.yml --bundle-directory bundle
And for those based on i.MX8 based SoMs:
$ torizoncore-builder bundle --platform=linux/arm64 docker-compose.yml --bundle-directory bundle
Pass the --platform switch to torizoncore-builder bundle
when working with multi-platform Docker images.
Applying Docker Container Images to a Custom Image
There are two possible approaches to apply the customization and generate a custom Toradex Easy Installer image, described in the next two sections Approach 1 and Approach 2. These approaches in some cases are interchangeable and in some not as described in the next sections.
To learn about TorizonCore Builder workflow and the different approaches to use the tool, with explanatory diagrams, please refer to the TorizonCore Builder - Workflow article.
Both approaches generate a custom Toradex Easy Installer image as output, so the approaches should be followed alternatively and not in sequence.
Approach 1: Applying Docker Container Images to a Custom Image Using the Build Command
TorizonCore Builder build command generates a custom Torizon OS image with the Docker container images ready to be installed with Toradex Easy Installer, named torizon-core-docker-colibri-imx6-Tezi_5.3.0.CUSTOM
in the example below. This is achieved using a configuration YAML file, tcbuild.yaml
as default. It requires a Toradex Easy Installer image of Torizon OS, torizon-core-docker-colibri-imx6-Tezi_5.3.0+build.7.tar
in this case, as input.
This is the recommended approach on production programming and on CI/CD (continuous integration / continuous development) pipelines.
To learn about TorizonCore Builder workflow and the different approaches to use the tool, with explanatory diagrams, please refer to the TorizonCore Builder - Workflow article.
Here there are two possible configuration YAML file approaches. The first is passing the directory with the pre-bundled Docker container images as a parameter and the second is passing the Docker Compose file as a parameter.
Pre-Bundled Container Images Directory As Parameter
The directory with the Docker container images is passed in output: bundle: dir
.
# Sample configuration file
input:
easy-installer:
local: images/torizon-core-docker-colibri-imx6-Tezi_5.3.0+build.7.tar
#Sample customization: insert pre-provisioned Docker container images with pre-bundled container images
output:
easy-installer:
local: torizon-core-docker-colibri-imx6-Tezi_5.3.0.CUSTOM
bundle:
dir: bundle/
Docker Compose File As Parameter
Alternatively to the configuration file above, one can pass the Docker Compose file YAML file instead of the directory with the Docker container images. This method does not require the use of the bundle
command prior to it, as it implicitly executes the bundle and the combine steps together in just one step. However, it downloads the Docker container images from the Docker registries, an operation that generally takes some time, every time the build
command is executed. The directory with the Docker Compose file is passed in output: bundle: compose-file
.
#Sample customization: insert pre-provisioned Docker container images
output:
easy-installer:
local: torizon-core-docker-colibri-imx6-Tezi_5.3.0.CUSTOM
bundle:
compose-file: custom/docker-compose.yml
Build The Custom Toradex Easy Installer Image
To generate the Torizon OS image, run the command below, in the same directory where the tcbuild.yaml file is:
$ torizoncore-builder build
...
1091 metadata, 12741 content objects imported; 412.2 MB content written
Pulling done.
Deploying OSTree with checksum 58629613a342197c31c5911d0874aac1b0fcb46b68a63f59760c03bacc4df08a
Deploying done.
Copy files not under OSTree control from original deployment.
Packing rootfs...
Packing rootfs done.
=>> Build command successfully executed!
In case of using a configuration file with a different name than tcbuild.yaml, run the command specifying the configuration file name:
$ torizoncore-builder build --file <configuration_file_name>
Approach 2: Applying Docker Container Images to a Custom Image Using Standalone Commands
In this second approach, instead of using a configuration YAML file and a one-step command, the generation of the custom Torizon OS image with the Docker container images is done using standalone commands, each performing one step towards this generation.
This approach is especially useful when making incremental changes, generating multiple images with different container images. As you will see, once you have a custom Toradex Easy Installer image without containers, generating images with different container images requires just the combine
command with a different --bundle-directory
argument.
To learn about TorizonCore Builder workflow and the different approaches to use the tool, with explanatory diagrams, please refer to the TorizonCore Builder - Workflow article.
To generate a custom Toradex Easy Installer image without the containers, that will be combined with the built Docker container images, follow the sequence of steps below.
Generate Custom Toradex Easy Installer Image Without Containers
You just need to execute this once. If the custom Toradex Easy Installer Image of Torizon OS without the containers has not changed this sequence of commands unpack
, union
and deploy
do not need to be executed again. Therefore, it is possible to jump to the combine
command.
If you have not unpacked an image yet, download a base Torizon OS image (preferably without containers) inside the TorizonCore Builder working directory, then run the command below to unpack it. In the example below the torizon-core-docker-colibri-imx6-Tezi_5.3.0+build.7.tar
image is used as a reference:
$ torizoncore-builder images unpack torizon-core-docker-colibri-imx6-Tezi_5.3.0+build.7.tar
If you want to change the Torizon OS base image, download the new image and run the images unpack
command again, passing the new image as the argument.
For more details about the images unpack
command, please check the images unpack command in the commands manual.
Instead of using the images unpack
you can use the images download
command. This command checks which is the connected Toradex SoM, downloads the compatible latest quarterly release of a Torizon OS image without containers, and unpacks this image.
$ torizoncore-builder images download --remote-host 192.168.1.117 --remote-username torizon --remote-password torizon
Change the arguments --remote-host
,--remote-username
and --remote-password
to your board IP Address, username and password, respectively.
For more details on how the images download
command works, please check the images download command in the commands manual.
Merge customizations to base Toradex Easy Installer image of Torizon - use whatever branch name you want. In this case, there are no customizations, like a new kernel module or a splash screen, but it is still appropriate to run this command as the branch name will be needed in the next command.
As an example, to commit changes into a branch named custom-branch
use the command below, accordingly with the TorizonCore Builder version:
$ torizoncore-builder union custom-branch
Applying changes from STORAGE/dt.
Commit 58629613a342197c31c5911d0874aac1b0fcb46b68a63f59760c03bacc4df08a has been generated for changes and is ready to be deployed.
$ torizoncore-builder union --union-branch=custom-branch
We recommend that you switch to the latest version of TorizonCore Builder to enjoy its simpler and more consistent user interface besides other improvements and bug fixes.
For more details about the union
command, please check the union command in the commands manual.
Use the previously created custom-branch
branch to generate a Torizon OS image, ready to be installed with the Toradex Easy Installer, that will be in the directory torizon-core-docker-colibri-imx6-Tezi_5.3.0.CUSTOM
in this case. This image, however, still does not have the containers:
$ torizoncore-builder deploy custom-branch --output-directory torizon-core-docker-colibri-imx6-Tezi_5.3.0.CUSTOM
Combine the Docker Containers Bundle with a Torizon OS image
At this point, you should have the following directory/file structure relative to your working directory:
├── bundle
├── docker-compose.yml
└── torizon-core-docker-colibri-imx6-Tezi_5.3.0.CUSTOM
├── image.json
├── ...
└── wrapup.sh
Now we can create a new image by combining the custom Toradex Easy Installer image without containers, generated in the anterior step, with the Docker container images, that were built with the bundle
command. To combine them, run the command below:
$ torizoncore-builder combine --image-directory torizon-core-docker-colibri-imx6-Tezi_5.3.0.CUSTOM --bundle-directory bundle --output-directory torizon-core-docker-colibri-imx6-Tezi_5.3.0.CUSTOM-WITH-CONTAINERS
The --image-directory
argument, torizon-core-docker-colibri-imx6-Tezi_5.3.0.CUSTOM
in this case, is the source image without containers. The --bundle-directory
argument, named bundle
in this case, is the directory with the built Docker container images. The --output-directory
argument, torizon-core-docker-colibri-imx6-Tezi_5.3.0.CUSTOM-WITH-CONTAINERS
in this case, is the directory containing the custom Toradex Easy Installer image with the Docker containers that will be generated by the combine
command.
Deploy The Custom Toradex Easy Installer Image
The custom Easy Installer image with the Docker container images can then be deployed (flashed) to the device using Toradex Easy Installer. This is the recommended approach for production programming. You can learn more about this by reading our article about production programming and provisioning at scale.
During development and once the device is on the field the most recommended way of deploying a custom image of Torizon OS (with customizations such as a splash screen, device tree overlays, etc) and Docker container images is doing it separately.
To more about the deployment of Docker container images and how to proceed in each situation, please refer to the Deploying Container Images to Torizon OS article. Also, to learn more about TorizonCore Builder workflow and how to proceed with a custom Torizon OS image on each situation, please refer to the TorizonCore Builder - Workflow article.
Remarks About Using Private Registries
If you are using a private Docker registry, you will need to pass other command-line options. For a quick reference, run torizoncore-builder bundle --help
or read the TorizonCore Builder Tool - The Bundle Command.
Torizoncore-builder uses a Docker-in-Docker (DIND) container instance to fetch images. Use the following command-line options to add the necessary files and settings to DIND:
Insecure Private Registries
If you are using an insecure private registry, use the torizoncore-builder bundle
command and the --dind-param
parameter to inform the DIND container of any insecure registries.
In this example, the registry running with IP address 192.168.0.30, port 5001 is to be accessed in this manner:
$ torizoncore-builder bundle --dind-param="--insecure-registry=192.168.0.30:5001" docker-compose.yml
Private Secure Registries
If you are using a secure private registry, Use the torizoncore-builder bundle
command and the --cacert-to
parameter to include the server Certificate Authority file (CAcert) to the DIND.
In this example, the registry running with the IP address 192.168.0.30, port 443 was created using the cacert.pem
as the CAcert file.
$ torizoncore-builder bundle --cacert-to 192.168.0.30:443 cacert.pem docker-compose.yml
Private Secure Registries with Auth
If you are using a secure private registry with Basic Auth, Use the torizoncore-builder bundle
command, along with the --cacert-to
parameter to include the server Certificate Authority file (CAcert) to the DIND, and the --login-to
parameter to define the Basic Auth Credentials.
In this example, the registry running with the IP address 192.168.0.30, port 443 was created using the cacert.pem
as the CAcert file, and it requires 'toradex' as username and 'test' as password.
$ torizoncore-builder bundle --cacert-to 192.168.0.30:443 cacert.pem --login-to 192.168.0.30:443 toradex test docker-compose.yml
For more information about Docker Private registries and how to deploy them, read the Deploy a registry server
For Torizon Cloud, you will also have to add the private registry credentials to the Torizon OS image. Read the article Using Private Registries With Torizon Cloud for more details.
Limitations and Known Issues
This section contains known issues and limitations of bundling containers with TorizonCore Builder.
- Not possible to use extended attributes (xattrs) inside a container: TorizonCore Builder does not support bundling containers with files that have xattrs set. It is not a good practice to use xattrs, since it isn't consistently supported by Docker. Instead, set capabilities and ACLs in your Docker Compose file.
Environment Variables
If the docker-compose.yaml
file has references to environment variables to be used when running the container in the SoM, it's expected that the literal string to be left untouched (i.e. not expanded) during the bundle command. However, if your Docker compose file is simillar to the one below, this is not the current behavior.
version: '2.4'
services:
hello-world:
image: hello-world:latest
environment:
- A=${FOO}
- B=${BAR}
Since the variables are not defined during the bundle process, ${FOO}
and ${BAR}
will be replaced by the empty string "" in the compose file.
It is possible to work around this problem by using $$
, as in the file below:
version: '2.4'
services:
hello-world:
image: hello-world:latest
environment:
- A=$${FOO}
- B=$${BAR}