Last month, GitHub announced new improved CI/CD with GitHub Actions. Since then, I have experimented with the new Action workflows and created an Action that wraps the faas-cli
so that you can easily build and deploy your functions directly from GitHub.
My initial interactions with the new GitHub Actions were not great, they really meant it when they said “public beta”. BUT!!! Having said that, there is clearly a lot of promise in GitHub Actions. People seem to love it. The integration into the UI is great. And, while the first week was tough, the documentation and starter workflows have seen a lot of improvements. Today, I want to introduce the OpenFaaS Actions that I wrote and show you how to set up a simple “build & deploy” workflow for your OpenFaaS functions.
Back at the beginning of the year, I wrote a short walk-through on the OpenFaaS blog showing how to cleanly split Python functions into multiple modules. Today, we will extend that example repo with a GitHub Action Workflow to make sure that the latest version of the function is available to deploy.
TL;DR
If you are a GitHub Actions expert already and just want to see the workflow files:
name: CI
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Login to Docker Hub
uses: actions/docker/login@master
env:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
- uses: LucasRoesler/openfaas-action/template_store_pull@v0.1.0
name: Fetch Template
with:
name: "python3-flask"
- uses: LucasRoesler/openfaas-action/build@v0.1.0
name: Build
with:
path: "wordcount.yml"
tag: "sha"
- uses: LucasRoesler/openfaas-action/push@v0.1.0
name: Push image
if: "success() && github.ref == 'refs/heads/master' "
with:
path: "wordcount.yml"
tag: "sha"
The OpenFaaS Actions
Currently, the OpenFaaS Action repo defines 6 common actions that expose the faas-cli
commands of the same name:
login
- login to an OpenFaaS clusterbuild
- build the functions in the named function stack configurationshrinkwrap
- assemble the function build context, merging the function implementation with the template, but don’t build ittemplate pull
- pull the function templates from the named template repotemplate store pull
- pull the named function template from the template storepush
- push the built function docker image to a docker registry
It also provides a generic cli
action that allows you to pass any command to the faas-cli
. This is the escape hatch that allows you to use the faas-cli
directly instead of via the pre-defined actions described above.
What is an Action?
Each step in the above workflow “uses” a different GitHub Action. These are predefined … well… actions that can be performed, in this cases
- clone the project,
- login to docker hub,
- fetch the python function template,
- build the function, and
- push the function image.
Each of these actions is effectively a Docker image, a command, and some optional metadata. For example, the template pull Action is just this bit of yaml
name: 'OpenFaaS CLI Template Repo Pull Action'
description: 'Pull templates from a remote repository'
author: 'Lucas Roesler'
inputs:
repository_url:
description: 'repository to pull templates from, defaults to the core templates'
required: false
runs:
using: 'docker'
image: 'docker://openfaas/faas-cli:0.9.2'
args:
- 'faas-cli'
- 'template'
- 'pull'
- '${{ inputs.repository_url }}'
In which I specify that it runs the faas-cli template pull
command in the prebuilt openfaas/faas-cli:0.9.2
image.
Setup the workflow
Configure you repo secrets
Before we dive into the GitHub Action Workflow, we need to configure two secrets for the repo DOCKER_USERNAME
and DOCKER_PASSWORD
. This is done in the Secrets section of the Settings tab, like this:
Write the workflow
In your GitHub repo, select the Actions tab to get started. If you do not have any actions yet, it will look just like this
This is a custom workflow, so select “Setup a workflow yourself”, which brings you to an editor
Now we simply need to update the steps to use the new OpenFaaS Actions.
For this example, we want the workflow to
-
“clone the project”,
This step is the simplest and uses an the official GitHub action
- uses: actions/checkout@v1
-
“login to docker hub”,
this again uses an official Action, but requires some secret parameters which are passed via the env, which we configure in the next section,
- name: Login to Docker Hub uses: actions/docker/login@master env: DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
-
“fetch the python function template”,
This is the first OpenFaaS step and calls the
faas-cli template store pull
command, but is as simple as the docker login. This time we need to specify the name of the template we want to pull. Unlike the docker login action, these are passed by thewith
section because the OpenFaaS action has predefined input parameters- uses: LucasRoesler/openfaas-action/template_store_pull@v0.1.0 name: Fetch Template with: name: "python3-flask"
Before going further, the action name specifies a folder/action
template_store_pull
in my action repoLucasRoesler/openfaas-action
at a specific SHA/tagv0.1.0
. All actions have this structure, which makes it easy to find and review what the code is actually going to do before you use it or to find inspiration for your own actions. -
“build the function”,
The
faas-cli build
action requires the relative path to the stack YAML file and it also accepts the tag flag for the build command:Override latest tag on function Docker image, accepts ‘latest’, ‘sha’, or ‘branch’ (default “latest”)
- uses: LucasRoesler/openfaas-action/build@v0.1.0 name: Build with: path: "wordcount.yml" tag: "sha"
-
“push the function image”,
Finally, with the the functions built, we can also push them to the Docker Hub using the
faas-cli push
. This step also uses the step conditional statement to ensure that it only runs when the build step was success AND when the workflow is running on the master branch.- uses: LucasRoesler/openfaas-action/push@v0.1.0 name: Push image if: "success() && github.ref == 'refs/heads/master' " with: path: "wordcount.yml" tag: "sha"
Altogether, the workflow should look like
name: CI
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Login to Docker Hub
uses: actions/docker/login@master
env:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
- uses: LucasRoesler/openfaas-action/template_store_pull@v0.1.0
name: Fetch Template
with:
name: "python3-flask"
- uses: LucasRoesler/openfaas-action/build@v0.1.0
name: Build
with:
path: "wordcount.yml"
tag: "sha"
- uses: LucasRoesler/openfaas-action/push@v0.1.0
name: Push image
if: "success() && github.ref == 'refs/heads/master' "
with:
path: "wordcount.yml"
tag: "sha"
Save and Run the Workflow
Save the workflow using the “Start Commit” button, if you are feeling brave you can commit the workflow directly to master
, but you can also easily test the workflow from any branch
Once it is committed, you can see the workflow results and logs in the Actions tab
Next Steps
This is just an experiment while GitHub Actions is in beta. But the next step will of course be a GitHub Action to keep the OpenFaaS action up-to-date with the faas-cli
releases.
Additionally, there is some interesting work currently going on that should help simplify this workflow even more. We want to add the ability to save the template dependencies to the project repository so that we can pull all of the dependencies with a single command faas-cli template pull stack
. For a standard OpenFaaS project using the default stack.yml
, the basic workflow will be completely standardized and require almost no configuration, like this
name: CI
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Login to Docker Hub
uses: actions/docker/login@master
env:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
- uses: LucasRoesler/openfaas-action/template_pull_stack@v0.1.0
name: Fetch Template
- uses: LucasRoesler/openfaas-action/build@v0.1.0
name: Build
with:
tag: "sha"
- uses: LucasRoesler/openfaas-action/push@v0.1.0
name: Push image
if: "success() && github.ref == 'refs/heads/master'"
with:
tag: "sha"
Ultimately, I want to make the OpenFaaS experience on GitHub as easy as possible.
If you have any questions, feedback, or you want to help:
- Open an issue or PR on the OpenFaaS Actions repo, or
- Join the OpenFaaS Slack community