Developing and Publishing a Flame App for Great Bear

This guide gives an example of how to develop the Flame application for Great Bear. Flame is an open source platform from Cisco that enables developers to compose and deploy Federated Learning training workloads easily.

By building a Flame app and running at the edge on Great Bear, you can:

  • train global machine learning models
  • keep data at the edge site, and
  • preserve privacy.

The Flame app itself runs as a ‘Flamelet’ in non-orchestration mode, which means that it reaches out to the Flame Control Plane and registers itself for a Federated Learning task.

In this tutorial you are going to clone the Flame open source repository, and build the associated docker image. You will then package the docker image with a Helm chart and add the relevant data to upload and run this as a Great Bear application.

Prerequisites

This guide assumes that:

  • You either have access to an already deployed instance of the Flame Control Plane running in the cloud, or that you have deployed your own Flame Control Plane.
  • You are familiar with using docker and creating docker images, creating Helm charts for Kubernetes, and deploying applications to Kubernetes clusters using Helm charts.
  • You have docker and helm installed.
  • You have the required access credentials for Great Bear. For more information on the development process for Great Bear, see Creating, Publishing and Deleting Applications.

Build and upload the Flame docker image

  1. First step is to clone the Flame open source repository:

    git clone https://github.com/cisco-open/flame.git
    
  2. Once the repository has been cloned, navigate into the fiab directory inside flame:

    cd flame/fiab
    
  3. Next, build the Flame docker image with the command:

    ./build-image.sh
    
  4. After the docker image is built, check that the image has been created by running:

    docker images | head -2
    

    Which should give output similar to the following:

    REPOSITORY   TAG      IMAGE ID       CREATED        SIZE
    flame        latest   2b53cc1e6644   1 minute ago   4.27GB
    
  5. In order to upload this image to Great Bear, you first need to tag it by running following command, replacing <tenant-id> with the Application Store Tenant ID provided to you by Cisco:

    docker tag flame repo.greatbear.io/<tenant-id>/flame:0.0.1
    
  6. Log in to the Great Bear system using docker. To do this, run the following command, replacing , and with the credentials provided to you by Cisco:

    docker login --username=<tenant-registry-username> --password=<tenant-registry-password> <tenant-registry-url>
    

    Alternatively, you can exclude the username and password from this command, and enter them when prompted.

  7. Push this image to the Great Bear repository. Run the following command, replacing , <application-name>, and <version-number> with the values used in the previous step:

    docker push <tenant-registry-url>/<application-name>:<version-number>
    

    In this case, use flame:0.0.1 for the application name and version.

Create the Great Bear Application Package (GBAP)

  1. With the Dockerfile created, you can now move onto creating the GBAP, used to publish our application to the Great Bear Application Store for subsequent deployment to Great Bear managed sites through the Great Bear Dashboard.

  2. Follow the steps to install and configure the Great Bear Packaging SDK tool.

  3. In a location of your choice create a new directory called flame-app where you will create and save the GBAP.

  4. Use the SDK tool to create a new GBAP instance within your flame-app application directory.

    gbear app create flame-app/GBAP
    

    Enter the chart name, name of the application, and the description of the application when prompted:

    Creating a GBAP with required fields....
    Enter the chart name:
    flame-app
    Enter the chart version [SemVer2 MAJOR.MINOR.PATCH], (leave empty for default: 0.0.1):
    
    Enter the application name:
    Flame App
    Enter the application description:
    Flame is a platform that enables developers to compose and deploy Federated Learning training workloads easily.
    Successfully created a GBAP in path flame-app/GBAP
    
  5. The SDK tool has now created a boiler plate GBAP filesystem tree:

    flame-app/GBAP
    ├── Chart.yaml
    ├── gbear
    │   └── appmetadata.yaml
    

Author the GBAP Assets

The GBAP contains the following two fundamental elements:

  1. A Helm Chart to describe a set of Kubernetes resources used to deploy the application at Great Bear managed sites.
  2. Great Bear specific application metadata (gbear/appmetadata), containing:
    • Properties used to render the application in the Great Bear Application Store
    • Properties used to define application parameters which can be overridden when deploying the Helm Chart.

For further details on the GBAP structure, see Great Bear Application Package Guide

Extend the GBAP Helm Chart

The final things that you need to build are the elements of the Helm Chart for deploying the container image to Great Bear sites as an application. Helm Charts describe Kubernetes applications and their components: rather than creating YAML files for every application, you can provide a Helm chart and use Helm to deploy the application for you. Therefore, the next steps are to create a very basic Helm Chart that will contain a template for the Kubernetes resource that will form your application, and a values file to populate the template placeholder values.

A Chart.yaml file is required for any Helm Chart, and contains high level information about the application (you can find out more in the Helm Documentation). You can set a number of Great Bear specific parameters in the Helm chart of your application.

  1. The Packaging SDK has created the root Chart file Charts.yaml within the GBAP filesystem tree.

    apiVersion: v2
    name: flame-app
    version: 0.0.1
    

Create the Helm values file

  1. Inside the flame-app/GBAP directory, create a file called values.yaml. This file contains the default values for our Flame application. It also defines the data needed for the application to pull the image, such as repository location and pull secrets. When creating this file, replace < tenant-registry-url > in the repository value with the URL provided to you by Cisco.

    # flame-app/values.yaml
    
    replicaCount: 1
    
    config:
      CONTROL_PLANE_API_SERVER_URL: ""
      CONTROL_PLANE_NOTIFIER_URL: ""
      FLAME_TASK_ID: ""
      FLAME_TASK_KEY: ""
    
    image:
      repository: < tenant-registry-url >/flame
      pullPolicy: Always
      tag: 0.0.1
    
    imagePullSecrets:
      - name: gbear-harbor-pull
    
    nameOverride: ""
    fullnameOverride: "flame-app"
    

Create the Helm template files

The next step is to create the template files that will:

  • create your Kubernetes deployment
  • the service endpoint for the deployment, and
  • some template helpers that are re-used throughout the chart.

Complete the following steps.

  1. Inside the flame-app/GBAP directory, create a new directory called templates

  2. In the new templates directory, create a file called _helpers.tpl, which will hold some template helpers that you can re-use throughout the chart. Your _helpers.tpl file should contain the following helpers:

    # flame-app/templates/_helpers.tpl
    
    {{/*
    Expand the name of the chart.
    */}}
    {{- define "app.name" -}}
    {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
    {{- end }}
    
    {{/*
    Create a default fully qualified app name.
    We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
    If release name contains chart name it will be used as a full name.
    */}}
    {{- define "app.fullname" -}}
    {{- if .Values.fullnameOverride }}
    {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
    {{- else }}
    {{- $name := default .Chart.Name .Values.nameOverride }}
    {{- if contains $name .Release.Name }}
    {{- .Release.Name | trunc 63 | trimSuffix "-" }}
    {{- else }}
    {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
    {{- end }}
    {{- end }}
    {{- end }}  
    
    {{/*
    Create chart name and version as used by the chart label.
    */}}
    {{- define "app.chart" -}}
    {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
    {{- end }}
    
    {{/*
    Common labels
    */}}
    {{- define "app.labels" -}}
    helm.sh/chart: {{ include "app.chart" . }}
    {{ include "app.selectorLabels" . }}
    {{- if .Chart.AppVersion }}
    app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
    {{- end }}
    app.kubernetes.io/managed-by: {{ .Release.Service }}
    {{- end }}
    
    {{/*
    Selector labels
    */}}
    {{- define "app.selectorLabels" -}}
    app.kubernetes.io/name: {{ include "app.name" . }}
    app.kubernetes.io/instance: {{ .Release.Name }}
    {{- end }}
    
    {{/*
    Create the name of the service account to use
    */}}
    {{- define "app.serviceAccountName" -}}
    {{- if .Values.serviceAccount.create }}
    {{- default (include "app.fullname" .) .Values.serviceAccount.name }}
    {{- else }}
    {{- default "default" .Values.serviceAccount.name }}
    {{- end }}
    {{- end }}
    
  3. In the templates directory, create the deployment.yaml file, which provides a basic manifest for creating the Kubernetes deployment your Flame application. It also sets the FLAME_TASK_ID and FLAME_TASK_KEY environment variables to the user-defined input when deploying the application, and runs the command to start the Flame app in non-orchestration mode with CONTROL_PLANE_API_SERVER_URL and CONTROL_PLANE_NOTIFIER_URL as arguments. It also defines and mounts a volume where the data from the Flame training can be placed. Therefore, in this case, the deployment.yaml should contain:

    # flame-app/deployment.yaml
    
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: {{ include "app.fullname" . }}
      labels:
        {{- include "app.labels" . | nindent 4 }}
    spec:
      replicas: 1
      selector:
        matchLabels:
          {{- include "app.selectorLabels" . | nindent 6 }}
      template:
        metadata:
          labels:
            {{- include "app.selectorLabels" . | nindent 8 }}
        spec:
          {{- with .Values.imagePullSecrets }}
          imagePullSecrets:
            {{- toYaml . | nindent 8 }}
          {{- end }}
          containers:
            - name: {{ .Chart.Name }}
              volumeMounts:
                - mountPath: /flame/data
                  name: volume-flamelet
              image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
              imagePullPolicy: Always
              env:
                - name: FLAME_TASK_ID
                  value: {{ .Values.config.FLAME_TASK_ID }}
                - name: FLAME_TASK_KEY
                  value: {{ .Values.config.FLAME_TASK_KEY }}
              command: ["/usr/bin/flamelet", "-a", "{{ .Values.config.CONTROL_PLANE_API_SERVER_URL }}", "-n", "{{ .Values.config.CONTROL_PLANE_NOTIFIER_URL }}", "--insecure"]
          volumes:
            - name: volume-flamelet
              hostPath:
                path: /home/vagrant/data
          restartPolicy: Always
    status: {}
    

Customise the Great Bear Application Metadata

  1. The SDK tool has generated the following boiler plate gbear/appmetadata.yaml file, the application metadata file to include the following properties, allowing the user to set their own values for CONTROL_PLANE_API_SERVER_URL, CONTROL_PLANE_NOTIFIER_URL, FLAME_TASK_ID and FLAME_TASK_KEY when they deploy the app via the Application Store.

    title: Flame App 
    description: Flame is a platform that enables developers to compose and deploy Federated Learning training workloads easily.
    icon: https://github.com/cisco-open/flame/raw/main/docs/images/logo.png
    configuration:
      - name: CONTROL_PLANE_API_SERVER_URL
        title: The URL or IP address to connect to the API Server component in the Flame Control Plane
        type: String
      - name: CONTROL_PLANE_NOTIFIER_URL
        title: The URL or IP address to connect to the Notifier component in the Flame Control Plane (Cloud Cluster)
        type: String
      - name: FLAME_TASK_ID
        title: A Task ID is linked to a Job ID and is generated when a job has been started
        type: String
      - name: FLAME_TASK_KEY
        title: A Task Key is an ID that the user can chose when deploying the flame app
        type: String
    

Validate the Application Package

  1. By now you should now have a complete application, and you can test that everything is setup correctly by running the following two commands in the flame-app/GBAP directory:

    helm lint
    
    helm install flame-app . --dry-run --debug
    

    Assuming everything is setup correctly and the previous helm commands do not report any errors, you can now move onto validate the complete GBAP structure.

  2. Now that we have finished authoring our GBAP assets and tested the embedded Helm Chart works, we can use the SDK tool to perform a final validation of the complete GBAP contents:

    $ gbear app validate flame-app/GBAP
    Validating Package: charts/
    -- Validating Application Metadata...
    -- Validating Chart Dependencies...
    -- Validating Kubernetes Resource Labels...
    Validation Complete:
    Application Metadata: Passed (Errors: 0, Warnings: 0)
    Chart Dependencies: Passed (Errors: 0, Warnings: 0)
    Kubernetes Resource Labels: Passed (Errors: 0, Warnings: 0)
    

For further details on GBAP validation, see Validate an Application Package.

Publish to the Great Bear Application Store

Assuming that the command above didn’t give errors, you can move onto publishing the flame app to Great Bear by Publish an Application Package.

Once published, the Flame application will be available in the Application Store:

Flame App Store Flame App Store