Custom CI To Build Compose App Targets¶
FoundriesFactory includes all you need to build a containerized application and securely deploy it on devices. In particular, it provides you with a git repository and the CI service that does all the necessary steps to build and delivery apps by leveraging the TUF compliant OTA service. You can learn more details about it by going through this tutorial.
The FoundriesFactory solution consists of a few loosely coupled services. It allows using the FoundriesFactory OTA framework directly, eliminating the need to host your App source code in the FoundriesFactory git repository and using the FoundriesFactory CI service. Therefore, you can host your App in any source code repository and build App by any other framework, yet still leverage the rest part of FoundriesFactory.
This section guides you through the steps of creating a custom CI pipeline in GitHub that:
- builds multi-arch container images and pushes them to FoundriesFactory Registry;
- builds FoundriesFactory Compose App and pushes it to the FoundriesFactory Registry;
- composes TUF Targets role metadata compliant with FoundriesFactory TUF requirements;
- adds the composed TUF Targets to FoundriesFactory Targets.
Prerequisites¶
- Your Factory has been successfully created.
- At least one successful Factory CI build and the corresponding Target with the tag and a hardware ID that you will use in the following guide.
- You have a GitHub repo with source code, Dockerfiles, and a Docker compose file that work.
Below is an example of how the prerequisites would look like:
Factory
lmp-demo
is setup and has been successfully created.The successfully built Target with the tag
custom-ci-devel
and the hardware IDraspberrypi4-64
.Fioctl targets show 1 -f lmp-demo APP HASH --- ---- ## Target: raspberrypi4-64-lmp-1 Created: 2022-11-30T00:20:31Z Tags: custom-ci-devel OSTree Hash: fe15cf8ad5e09136725ef996c93299d70fa0d20bfa2f10651437b8860b9edcdb
The GitHub repo that contains a working App implementation.
Creating And Setting the Access Token¶
The GitHub action needs to authenticate itself at the FoundriesFactory OTA service and the FoundriesFactory Registry.
Therefore, an access token must be created and added to the GitHub repo action tokens prior to running any CI pipelines.
You can create the token at FoundriesFactory WebApp.
The token must have containers:read-update
and targets:read-update
scopes to access the registry and the OTA service correspondingly.
Set Token in GitHub Repo¶
Go to https://github.com/foundriesio/<your repo>/settings/secrets/actions
and add a secret named FIO_TOKEN
and the value of the token obtained in the previous step.
Define GitHub Actions Workflow¶
The next step is to define a GitHub actions workflow in your repo or extend an existing one. The sample GitHub actions workflow provides an example of the workflow that communicates with FoundriesFactory to achieve the goal, i.e. the items listed at the end of the introductory section. The workflow does the following:
- Builds and pushes images to the registry.
- Stores the built image URIs (must be digest/hashed reference) so they can be referred from the App compose project.
- Builds and pushes Compose App by utilizing Foundries utility compose-publish.
- Composes and posts new Target(s) that refers to the App built in the step 3. The
fioctl targets add
command is utilized to accomplish it.
Learn App Repo Structure Details¶
It is important to understand the structure of the sample App before creating your own App and CI job that communicates with the FoundriesFactory services.
Docker files and build directories of the container images are located in sub-directories of <root>/docker
.
The name of each sub-directory corresponds to a container image name.
The compose project definition refers to the container images defined in the repository and built by the given CI job
by the following reference hub.foundries.io/lmp-demo/<app-name|dir>
.
The App compose file and supplementary files (if any) are placed under <root>/compose/<app-dir>
directory.
The container images hosted in the same repo as the given App and built by the repo CI job should be referred
in the compose file without any tag or hash, e.g. image: hub.foundries.io/lmp-demo/ha-app
.
Container images that are not hosted in the given repo (external
) and are not built by the given CI job must be referenced with a tag or a hash, e.g. image: ghcr.io/home-assistant/home-assistant:2022.11.4
.
FoundriesFactory Utilities: Usage Details¶
The compose-publish CLI utility does the following:
Pins images referenced from the App compose file.
- If an image is already pinned (digest, a reference with sha256 hash) it does nothing.
- If an image is referred by a tag it tries to get the image digest — a reference with sha256 hash. If it fails to obtain an image digest then the utility exists with an error.
- If an image reference has not tag nor hash it checks if it’s specified via
--pinned-images
input parameter. If no digest reference is found inpinned-images
the utility exists with an error.
Creates the compose App container image.
- Creates an archive (
tgz
) that contains the App compose file and its supplementary files. - Creates a container image manifest referring to the App archive as an image layer/blob.
- Creates an archive (
Pushes the App container image to the FoundriesFactory Registry.
The utility outputs the built and pushed App image digest to the file specified via -d
input parameter.
Then the published App can be referenced with a hashed URI — hub.foundries.io/<factory>/<app-name>@sha256:<hash>
.
Once the App is successfully built and pushed to the registry, a new Target referring to it can be created.
To do so the Fioctl command fioctl targets add
should be used.
Check The Workflow Result¶
Use fioctl targets list
and fioctl targets show
commands to check whether the new Targets are registered in the FoundriesFactory OTA service
and whether their content is correct.
Note
In some cases a user may want to keep their App source code in their private repo yet still use the FoundriesFactory CI service. If it is the case, then you can check out the following two approaches:
See also