GitOps with Mender and docker-compose: mender-application-update-pipeline

Introduction

Containers, and especially docker as the management tool are seeing an ever increasing interest and demand also in embedded Linux. Taking the next step from there are orchestrated containers, for example in a microservice architecture.

In the cloud world, docker compose is one of the most prominent tools for orchestration and management of such solutions. Transferring cloud native methods to IoT/edge use cases can provide great value, and to facilitate the usage in device fleets, Mender is providing an Application Update Module for docker compose.

As an extension to the tutorial on using the module on a Debian-based platform, this article explains how to set up a GitHub Actions based pipeline that builds an Application Update Module artifact upon pushing to the repository and deploys it through a Mender backend upon publishing a release.

This is meant to serve as a template to implement GitOps to OTA in your own project.

mender-app-update-pipeline

The example pipeline consists of the following parts:

  • build_dind.yml: the actual pipeline. It can be used as a template, where you adjust the environment variable declarations near the top to your requirements.
  • docker-compose.yml: the Docker Compose-style manifest of containers which you want to deploy. It is based on the tutorial on application updates in the Mender documentation, and showcases a simple traefik+whoami setup.
version: "3.3"
services:
  gateway:
    image: "traefik:v2.9"
    command:
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
    ports:
      - "8080:80"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
  whoami:
    image: "traefik/whoami"
    labels:
      - "traefik.enable=true"
      - 'traefik.http.routers.whoami.rule=Path("/whoami")'
      - "traefik.http.routers.whoami.entrypoints=web"

Requisites:

Implementation details

workflow:

the build_dind.yml file sets up an Ubuntu-22.04 based container, and installs the required packages:

  • docker
  • mender-artifact
  • app-gen script
    Additionally, it enables docker inside by requesting the service from the host, therefore the name “dind”, short for “Docker-in-Docker”. This is required for the app-gen script, which needs to run docker for obtaining the containers to package.
jobs:
  deploy_application_update:
    runs-on: ubuntu-22.04
    services:
      docker:
        image: docker:dind
        options: --privileged --shm-size=2g
        volumes:
          - /var/run/docker.sock:/var/run/docker.sock:ro
    container:
      image: ubuntu:22.04
    steps:
      # step implementations removed for clarity of explanation
      - name: Checkout
    
      - name: update APT

      - name: install prerequisites

      - name: prepare Mender APT repos
    
      - name: prepare Docker APT repos

      - name: update APT
    
      - name: install Docker

      - name: install mender-artifact

      - name: install app-update-module generation script
    
      - name: create artifact

triggers:

the example has three triggers configured.

name: build_dind_explicit

on:
  workflow_dispatch:
  release:
    types: [published]
  push:
    branches: 
      - main
  • workflow_dispatch: so the workflow can be interactively started through the GitHub Actions Web user interface.
  • push: the workflow runs to build the artifact upon each push to the main branch, so you have a quick feedback loop if the process is still functional
  • release: this trigger is limited to the published type. The flow is similar to the push/workflow_dispatch one, but extends it by uploading the artifact to the configured Mender Server and creates a deployment for the devices listed in the MENDER_DEVICES_LIST environment variable.
      # Only releases upload and deploy through Mender server
      - name: Upload Mender Artifacts to Mender server
        if: ${{ github.event_name == 'release' }}
        uses: mendersoftware/mender-gh-action-upload-artifact@master
        with:
          mender_pat: ${{ secrets.MENDER_SERVER_ACCESS_TOKEN }}
          mender_artifact: ${{ env.MENDER_ARTIFACT_NAME }}.mender
          mender_uri: ${{ env.MENDER_SERVER_URL }}
      - name: Create deployment on Mender server
        if: ${{ github.event_name == 'release' }}
        uses: mendersoftware/mender-gh-action-create-deployment@master
        with:
          mender_pat: ${{ secrets.MENDER_SERVER_ACCESS_TOKEN }}
          mender_uri: ${{ env.MENDER_SERVER_URL }}
          mender_deployment_name: ${{ env.MENDER_DEPLOYMENT_NAME }}
          mender_release_name: ${{ env.MENDER_RELEASE_NAME }}-${{ env.MENDER_RELEASE_VERSION }}
          mender_devices_list: ${{ env.MENDER_DEVICES_LIST }}

Usage

The repository is meant as a template for your own project. These are the minimal modifications for getting started:

  1. set up a target device with docker-compose and the Application Update Module plus dependencies, and accept it to your Hosted Mender account. Note down the device ide.
  2. create a personal access token (PAT) as described at Using the APIs | Mender documentation and store it in a safe place for reference
  3. set the MENDER_SERVER_ACCESS_TOKEN secret. In your GitHub settings, go to the “Actions”->“Secrets” section and create a new one with the name MENDER_SERVER_ACCESS_TOKEN and the above created PAT as value
  4. change the following in .github/workflows/build-dind.yml:
  • MENDER_ARTIFACT_NAME, MENDER_RELEASE_NAME, MENDER_RELEASE_VERSION, MENDER_DEPLOYMENT_NAME: to the desired artifact and application names and version
  • MENDER_DEVICES_LIST: to an array ([..]) of device ids that you want to deploy to, usually the one that you just noted down in the first step
  • DEVICE_TYPE: to the device_type of the devices you want to deploy to
  • PLATFORM: to the docker architecture identification string of your target device(s).
  1. change docker-compose.yml according to your application, and push to GitHub. This will trigger the artifact build
  2. publish a release through the GitHub UI. This will build the artifact, and deploy it to the configured device(s).

Conclusion

This tutorial respectively template provides a starting point for easily deploying a docker-compose based application through Mender, by automating artifact creation, uplaoding and deploying to a defined set of devices through GitHub Actions.


If this tutorial was useful to you, please press like, or leave a thank you note to the contributor who put valuable time into this and made it available to you. It will be much appreciated!

2 Likes