Search by Tags

Using Multiple Containers with TorizonCore

 

Article updated at 30 Nov 2020
Compare with Revision




Select the version of your OS from the tabs below. If you don't know the version you are using, run the command cat /etc/os-release or cat /etc/issue on the board.



Remember that you can always refer to the Torizon Documentation, there you can find a lot of relevant articles that might help you in the application development.

Torizon 5.0.0

Introduction

A strong advantage of the Torizon platform is the possibility to work with microservices architecture. This software development technique provides great advantages such as modularity, scalability, integration, and distributed development. TorizonCore is the base operating system in which Torizon is built and provides Docker for microservices implementation using containers.

In this article, you will learn how to orchestrate multiple containers, for example, the ones from the List of Container Images for Torizon, and manage the inter-communication process from a sample implementation using Grafana, Collectd, and InfluxDB.

This article complies to the Typographic Conventions for Torizon Documentation.

IDE Extensions (not used in this example)

Since this article explains a concept, it will not use Toradex's Extensions for Visual Studio and Visual Studio Code. Nevertheless, the concept can be applied while using them, of course. The following resources can help you configure multi containers applications using our extensions:

Prerequisites

  • A Computer on Module with TorizonCore installed, as explained in the Quickstart Guide.

Working with Multiple Containers

Docker Compose

Compose is a tool for defining and running multi-container Docker applications. Compose uses a YAML (*.yml) file to configure the application’s services. With the Compose file, in a single command, you create and start all the services from your configuration. There are some advantages to create a docker-compose (.yml) to orchestrate the execution of your containers. These include:

  • With a docker-compose file you can have all the parameters to launch a single or multiple containers saved on a file.
  • You can provision a device (or a fleet of devices) in Torizon OTA and update its containers remotely over-the-air just by sending the YAML to the web application.
  • A developer can pre-provision his containers with a TorizonCore image, and have a single image to flash on production.

Communication Inter Containers

When executing a system with multiple containers, some methods can be applied for communication and message passing between containers. Some of these methods are files/directories sharing and IP sockets. In this example, we will show communication through IP sockets (The communication will be done through HTTP requests).

By default, Docker Compose sets up a single network for your app. Each container for a service joins the default network and is both reachable by other containers on that network, and discoverable by them at a hostname identical to the container name. For more information, please, refer to Networking in Compose page.

Example: Multi-Container Application with Grafana, Collectd, and InfluxDB

In this example, we will show a multi-container application that displays the performance data of a Toradex's Computer-on-Module (CoM) using the following open-source software: Grafana, Collectd, and InfluxDB.

Briefing

Grafana is a data query and presenting tool, which lets us build a graph chart based on InfluxDB. InfluxDB is our time-series database. Grafana sends a query to InfluxDB (port 8086) by an HTTP request.

Collectd is a Unix daemon that collects, transfers, and stores performance data of computers and network equipment and sends it to InfluxDB.

In summary, Collectd will produce data and store it in the database (controlled by InfluxDB). Grafana will consume the data in the database and display it. In this example, we want to have 1 Docker container for each of the components - Grafana, Collectd, and InfluxDB. Hence, the core of our application contains 3 containers and the main YAML (.yml) file.

It is possible to show Grafana on local video output, in addition to having it served over a network interface. To make this possible, we bring-up a Weston container and a Chromium container in kiosk mode. This is an optional part of the demo that uses 2 extra containers and an extra YAML (.yml) file. You can easily remove it if you want.


  • High-level Architecture - How Containers Interact Between Them and the External World

    High-level Architecture - How Containers Interact Between Them and the External World

Instructions

First, obtain the files of this example. To do that, clone the repository to your PC:

$ git clone https://github.com/toradex/torizon-samples

Copy grafana directory from your PC to your module using scp (replace X.X.X.X by your module’s IP-address):

$ scp -r ./torizon-samples/grafana/ torizon@X.X.X.X:/home/torizon/

Connect to your module's shell by using SSH:

$ torizon@X.X.X.X

In your module's terminal, change the current directory to the ”grafana” directory:

# cd /home/torizon/grafana

The muti-container orchestration and configuration for this example are provided in:

Note: you are advised to consult the Compose file reference and the article Share Compose configurations between files and projects when customizing the example or writing your own.

If you want to show Grafana on a local display, copy either docker-compose.override.armhf.yml for 32-bit targets or docker-compose.override.arm64.yml for 64-bit targets, as docker-compose.override.yml.

cp docker-compose.override.arm64.yml docker-compose.override.yml
cp docker-compose.override.armhf.yml docker-compose.override.yml

To execute the application defined by the YAML file, execute the following command. Compose automatically uses the files named docker-compose.yml and docker-compose.override.yml if no other files are specified with the -f option:

Note: The option -d or --detach runs the containers in the background in detached mode.

# docker-compose up -d

Release Versions

Often during development, the tag latest is used for bringing up containers or basing Dockerfiles (FROM <image>:<release version>). That is OK but often one wants to set a specific version to prevent things to break due to an updated that has not yet been validated, for instance.

This demonstration uses specific versions for Grafana (grafana:<release version>) and InfluxDB (influxdb:<release version>). consult the docker-compose.yml to see what are the latest versions being used by the current example.

Example Explained

Key snippets from the docker-compose.yml are explained below:

docker-compose.yml
# version 2.4 enables the declaration of cgroup rules
# only use newer if you don't need to use cgroup rules
version: '2.4'
 
# Declare the containers and their configuration
services:

  # You can add a node for each container. We focus on Grafana in this code snippet
  grafana:

    # container_name enables you to access this container using a hostname
    # such as http://grafana
    container_name: grafana
 
    # declare the networks attached to the container
    networks:
      - backend
      - frontend
 
    # declare bind-mounts, volume and tmpfs
    volumes:
      - "grafana-storage:/var/lib/grafana"
 
    # declare open ports (they must be exposed in the Dockerfile)
    ports:
      - "3000:3000"

    links:
      - influxdb
 
    # this is the actual Docker image to be used
    image: grafana/grafana:6.7.1
 
# declare Docker networks
networks:
  backend:
    internal: true
  frontend:
    internal: false
 
# declare volumes
volumes:
  grafana-storage:
  influxdb-grafana:

Key snippets from the docker-compose.override.arm64.yml are explained below:

docker-compose.override.arm64.yml
# this override brings up Grafana on a local display
version: "2.4"
services:
  weston:

    # pass environment variables to the container
    # in this example, you accept the NXP EULA with regards to use of Vivante
    # binaries for GPU-accelerated graphics
    environment:
      - ACCEPT_FSL_EULA=1
    container_name: weston
    image: torizon/weston-vivante:2
    # Required to get udev events from host udevd via netlink
    network_mode: host
    volumes:
      - type: bind
        source: /tmp
        target: /tmp
      - type: bind
        source: /dev
        target: /dev
      - type: bind
        source: /run/udev
        target: /run/udev
    cap_add:
      - CAP_SYS_TTY_CONFIG
 
    # Add device access rights through cgroup rules
    device_cgroup_rules:
      # ... for tty0
      - 'c 4:0 rmw'
      # ... for tty7
      - 'c 4:7 rmw'
      # ... for /dev/input devices
      - 'c 13:* rmw'
      # ... for /dev/dri devices
      - 'c 226:* rmw'
      # ... for /dev/galcore device on i.MX8
      - 'c 199:* rmw'
  
  kiosk:
    container_name: kiosk
 
    # pass environment variables to the container
    # in this example, you pass the machine name to the container to help
    # determine whether or not to enable GPU H/W Acceleration for chromium
    # which is enabled by default for all targets except the GPU-less SoMs
    # i.e. colibri-imx7-emmc and colibri-imx6ull-emmc
    environment:
      - MACHINE
    image: torizon/chromium:2
 
    # run a custom command, equivalent to CMD on a Dockerfile
    command: --window-mode http://grafana:3000
    security_opt:
      - seccomp:unconfined    
    networks:
      - frontend
    volumes:
      - type: bind
        source: /tmp
        target: /tmp
      - type: bind
        source: /var/run/dbus
        target: /var/run/dbus
      - type: bind
        source: /dev/galcore
        target: /dev/galcore
 
    # only bring-up this container if others are successfully started
    depends_on:
      - weston
      - grafana
      - influxdb
 
    # size of shared memory between containers
    shm_size: '256mb'

    device_cgroup_rules:
      # ... for /dev/galcore device on i.MX8
      - 'c 199:* rmw'

Key snippets from the docker-compose.override.armhf.yml are explained below:

docker-compose.override.armhf.yml
# this override brings up Grafana on a local display
version: "2.4"
services:
  weston:
    container_name: weston
    image: torizon/weston:2
    # Required to get udev events from host udevd via netlink
    network_mode: host
    volumes:
      - type: bind
        source: /tmp
        target: /tmp
      - type: bind
        source: /dev
        target: /dev
      - type: bind
        source: /run/udev
        target: /run/udev
    cap_add:
      - CAP_SYS_TTY_CONFIG
 
    # Add device access rights through cgroup rules
    device_cgroup_rules:
      # ... for tty0
      - 'c 4:0 rmw'
      # ... for tty7
      - 'c 4:7 rmw'
      # ... for /dev/input devices
      - 'c 13:* rmw'
      # ... for /dev/dri devices
      - 'c 226:* rmw'
  
  kiosk:
    container_name: kiosk
 
    # pass environment variables to the container
    # in this example, you pass the machine name to the container to help
    # determine whether or not to enable GPU H/W Acceleration for chromium
    # which is enabled by default for all targets except the GPU-less SoMs
    # i.e. colibri-imx7-emmc and colibri-imx6ull-emmc
    environment:
      - MACHINE
    image: torizon/chromium:2
 
    # run a custom command, equivalent to CMD on a Dockerfile
    command: --window-mode http://grafana:3000

    security_opt:
      - seccomp:unconfined    
    networks:
      - frontend
    volumes:
      - type: bind
        source: /tmp
        target: /tmp
      - type: bind
        source: /var/run/dbus
        target: /var/run/dbus
      - type: bind
        source: /dev/dri
        target: /dev/dri
 
    # only bring-up this container if others are successfully started
    depends_on:
      - weston
      - grafana
      - influxdb
 
    # size of shared memory between containers
    shm_size: '256mb'

    device_cgroup_rules:
      # ... for /dev/dri devices
      - 'c 226:* rmw'

How to Use the Example - Configure Grafana

Open a browser on your computer, on the same network as the board, and access the board IP address on port 3000 http://X.X.X.X:3000/ and log in with default (user: admin, password: admin).

Note: If you are using the optional local ui the Grafana login page will open automatically on a screen attached on the device board.

Click Add data source:

  • select InfluxDB as a data source type

  • set URL to http://influxdb:8086 (we use docker link, so we can access it by container name)

  • write the name of your database (“collectd“ in our case)


  • Grafana Config

    Grafana Config

  • Click Save & Test button, it should say "Data source is working."

Create a new Dashboard:


  • Create Dashboard Item

    Create Dashboard Item

  • Select Choose Visualization:

  • New Panel

    New Panel

  • Choose InfluxDB as a query:

  • Customize the panel the way you prefer.

How to Create User with Read-Only Permission

  • Click Server Admin > Users > New user

Torizon 4.0.0

Introduction

A strong advantage of the Torizon platform is the possibility to work with microservices architecture. This software development technique provides great advantages such as modularity, scalability, integration, and distributed development. TorizonCore is the base operating system in which Torizon is built and provides Docker for microservices implementation using containers.

In this article, you will learn how to orchestrate multiple containers and manage the inter-communication process from an example implementation using Grafana, Collectd, and InfluxDB.

This article complies to the Typographic Conventions for Torizon Documentation.

IDE Extensions (not used in this example)

Since this article explains a concept, it will not use Toradex's Extensions for Visual Studio and Visual Studio Code. Nevertheless, the concept can be applied while using them, of course.

For an example of Multi-Container application using the Visual Studio Extension For Torizon, see C / C++ Developer Workflow on Windows.

Working with Multiple Containers

Docker Compose

Compose is a tool for defining and running multi-container Docker applications. Compose uses a YAML file to configure the application’s services. With the Compose file, in a single command, you create and start all the services from your configuration.

Comunication Inter Containers

When executing a system with multiple containers, some methods can be applied for communication and message passing between containers. Some of these methods are files/directories sharing and IP sockets. In this example, we will show communication through IP sockets (The communication will be done through HTTP requests).

By default, Docker Compose sets up a single network for your app. Each container for a service joins the default network and is both reachable by other containers on that network, and discoverable by them at a hostname identical to the container name. For more information, please, refer to Networking in Compose page.

Example: Multi-Container Application with Grafana, Collectd, and InfluxDB

In this example, we will show a multi-container application that displays the performance data of a Toradex's Computer-on-Module (CoM) using the following open-source software: Grafana, Collectd, and InfluxDB.

Briefing

Grafana is a data query and presenting tool, which lets us build a graph chart based on InfluxDB. InfluxDB is our time-series database. Grafana sends a query to InfluxDB (port 8086) by an HTTP request.

Collectd is a Unix daemon that collects, transfers, and stores performance data of computers and network equipment and sends it to InfluxDB.

In summary, Collectd will produce data and store it in the database (controlled by InfluxDB). Grafana will consume the data in the database and display it. In this example, we want to have 1 Docker container for each of the components - Grafana, Collectd, and InfluxDB. Hence, the core of our application contains 3 containers and the main YAML (.yml) file.

It is possible to show Grafana on local video output, in addition to having it served over a network interface. To make this possible, we bring-up a Weston container and a Chromium container in kiosk mode. This is an optional part of the demo that uses 2 extra containers and an extra YAML (.yml) file. You can easily remove it if you want.

Instructions

First, obtain the files of this example. To do that, clone the repository to your PC:

$ git clone https://github.com/toradex/torizon-samples

Copy grafana directory from your PC to your module using scp (replace X.X.X.X by your module’s IP-address):

$ scp -r ./torizon-samples/grafana/ torizon@X.X.X.X:/home/torizon/

Connect to your module's shell by using SSH:

$ torizon@X.X.X.X

In your module's terminal, change the current directory to the ”grafana” directory:

# cd /home/torizon/grafana

The muti-container orchestration and configuration for this example are provided in:

Note: you are advised to consult the Compose file reference and the article Share Compose configurations between files and projects when customizing the example or writing your own.

To execute the application defined by the YAML file, just use the following command. Compose automatically uses the files named docker-compose.yml and docker-compose.override.yml if no other files are specified with the -f option:

Note: The option -d or --detach runs the containers in the background in detached mode.

# docker-compose up -d

Release Versions

Often during development, the tag latest is used for bringing up containers or basing Dockerfiles (FROM <image>:<release version>). That is OK but often one wants to set a specific version to prevent things to break due to an updated that has not yet been validated, for instance.

This demonstration uses specific versions for Grafana (grafana:<release version>) and InfluxDB (influxdb:<release version>). consult the docker-compose.yml to see what are the latest versions being used by the current example.

Example Explained

Key snippets from thedocker-compose.yml are explained below:

docker-compose.yml
# version 2.4 enables the declaration of cgroup rules
# only use newer if you don't need to use cgroup rules
version: '2.4'
 
# Declare the containers and their configuration
services:

  # You can add a node for each container. We focus on Grafana in this code snippet
  grafana:

    # container_name enables you to access this container using a hostname
    # such as http://grafana
    container_name: grafana
 
    # declare the networks attached to the container
    networks:
      - backend
      - frontend
 
    # declare bind-mounts, volume and tmpfs
    volumes:
      - "grafana-storage:/var/lib/grafana"
 
    # declare open ports (they must be exposed in the Dockerfile)
    ports:
      - "3000:3000"

    links:
      - influxdb
 
    # this is the actual Docker image to be used
    image: grafana/grafana:6.7.1
 
# declare Docker networks
networks:
  backend:
    internal: true
  frontend:
    internal: false
 
# declare volumes
volumes:
  grafana-storage:
  influxdb-grafana:

Key snippets from the docker-compose.override.yml are explained below:

docker-compose.override.yml
# this override brings up Grafana on a local display
version: "2.4"
services:
  weston:

    # pass environment variables to the container
    # in this example, you accept the NXP EULA with regards to use of Vivante
    # binaries for GPU-accelerated graphics
    environment:
      - ACCEPT_FSL_EULA=1
    container_name: weston
 
    # For armhf (i.MX 6- and i.MX 7-based modules) use this image:
    #image: torizon/arm32v7-debian-weston:latest
    # For i.MX 8-based modules use this image:
    image: torizon/arm64v8-debian-weston-vivante:latest
 
    # Required to get udev events from host udevd via netlink
    network_mode: host
    volumes:
      - type: bind
        source: /tmp
        target: /tmp
      - type: bind
        source: /dev
        target: /dev
      - type: bind
        source: /run/udev
        target: /run/udev
    cap_add:
      - CAP_SYS_TTY_CONFIG
 
    # Add device access rights through cgroup rules
    device_cgroup_rules:
      # ... for tty0
      - 'c 4:0 rmw'
      # ... for tty7
      - 'c 4:7 rmw'
      # ... for /dev/input devices
      - 'c 13:* rmw'
      - 'c 199:* rmw'
      # ... for /dev/dri devices
      - 'c 226:* rmw'

  kiosk:
    container_name: kiosk
 
    # For armhf (i.MX 6- and i.MX 7-based modules) use this image:
    #image: torizon/arm32v7-debian-kiosk-mode-browser:latest
    # For i.MX 8-based modules use this image:
    image: torizon/arm64v8-debian-kiosk-mode-browser:latest
 
    # run a custom command, equivalent to CMD on a Dockerfile
    command: --window-mode http://grafana:3000
    
    networks:
      - frontend
    volumes:
      - type: bind
        source: /tmp
        target: /tmp
      - type: bind
        source: /var/run/dbus
        target: /var/run/dbus
      - type: bind
        source: /dev/dri
        target: /dev/dri
 
    # only bring-up this container if others are successfully started
    depends_on:
      - weston
      - grafana
      - influxdb
 
    # size of shared memory between containers
    shm_size: '256mb'

    device_cgroup_rules:
      # ... for /dev/dri devices
      - 'c 226:* rmw'

How to Use the Example - Configure Grafana

Open a browser on your computer, on the same network as the board, and access the board IP address on port 3000 http://X.X.X.X:3000/ and log in with default (user: admin, password: admin).

Note: If you are using the optional local ui the Grafana login page will open automatically on a screen attached on the device board.

Click Add data source:

  • select InfluxDB as a data source type

  • set URL to http://influxdb:8086 (we use docker link, so we can access it by container name)

  • write the name of your database (“collectd“ in our case)


  • Grafana Config

    Grafana Config

  • Click Save & Test button, it should say "Data source is working."

Create a new Dashboard:


  • Create Dashboard Item

    Create Dashboard Item

  • Select Choose Visualization:

  • New Panel

    New Panel

  • Choose InfluxDB as a query:

  • Customize the panel the way you prefer.

How to Create User with Read-Only Permission

  • Click Server Admin > Users > New user