Skip to content

CI/CD with Bitbucket Pipelines

You can use Bitbucket Pipelines to build and publish container images for your OpenFaaS functions. As a final step, you may also wish to deploy the new images to the OpenFaaS gateway via the OpenFaaS CLI.

Build and deploy

This pipeline builds and pushes function images, then deploys them to the OpenFaaS gateway. The build and deploy are defined as separate steps so they can be tracked independently.

Pre-requisites:

  • A container registry accessible from the pipeline (e.g. Docker Hub, Bitbucket Packages, AWS ECR, or another private registry).
  • The OpenFaaS gateway must be accessible from the Bitbucket pipeline runner.

Add the following repository variables under Repository settings > Pipelines > Repository variables:

Variable Description Secured
DOCKER_USERNAME Username for the container registry e.g. Docker Hub username No
DOCKER_PASSWORD Password or access token for the container registry Yes
OPENFAAS_URL URL of the OpenFaaS gateway e.g. https://gw.example.com No
OPENFAAS_PASSWORD Password for the OpenFaaS gateway Yes

OpenFaaS for Enterprises

If you are using OpenFaaS for Enterprises, we recommend using Web Identity Federation using the OIDC token provided by Bitbucket Pipelines instead of sharing the admin password with your CI system. This avoids long-lived credentials and lets you scope access to specific namespaces, functions and actions.

See: Variables and secrets

Create a function

If you don't already have a function, you can scaffold one with the faas-cli. The following example creates a Python function, but any supported language template can be used:

export OPENFAAS_PREFIX="docker.io/username"

faas-cli new --lang python3-http import-csv

This generates a stack.yaml and a handler directory.

Update import-csv/handler.py so it echos the request body:

def handle(event, context):
    return {
        "statusCode": 200,
        "body": event.body
    }

You can edit the image field in your stack.yaml to use environment variable substitution so the registry and namespace aren't hard-coded.

The configuration.templates section declares the template repositories your functions depend on. In a CI pipeline, this means faas-cli template pull stack will automatically fetch the correct templates function templates.

version: 1.0
provider:
  name: openfaas
  gateway: http://127.0.0.1:8080
functions:
  import-csv:
    lang: python3-http
    handler: ./import-csv
    image: ${REGISTRY:-docker.io}/${NAMESPACE:-username}/import-csv:latest
configuration:
  templates:
    - name: python3-http
      source: https://github.com/openfaas/python-flask-template

Create the pipeline

Create a bitbucket-pipelines.yml file in the root of your repository:

image: atlassian/default-image:3

pipelines:
  branches:
    main:
      - step:
          name: Build and push
          services:
            - docker
          script:
            - curl -sLS https://cli.openfaas.com | sh

            # Login to the container registry
            - >-
              echo "$DOCKER_PASSWORD" |
              docker login --username "$DOCKER_USERNAME" --password-stdin

            # Build and push function images
            - faas-cli template pull stack
            - faas-cli build --tag=sha
            - faas-cli push --tag=sha

      - step:
          name: Deploy
          script:
            - curl -sLS https://cli.openfaas.com | sh

            # Login to the OpenFaaS gateway
            - >-
              echo "$OPENFAAS_PASSWORD" |
              faas-cli login --username admin --password-stdin

            # Deploy functions
            - faas-cli template pull stack
            - faas-cli deploy --tag=sha

The --tag=sha flag appends the Git commit SHA to the image tag so that each build produces a unique, traceable image. Both steps must use the same flag. Alternatives like --tag=branch and --tag=describe are also available, see Image tagging. You can also template the image field in your stack.yaml using environment variable substitution to tag images in whatever format you need.

Only the build step requires the Docker service since it builds container images. The deploy step only needs the faas-cli to communicate with the gateway's REST API.

If you are using a private registry, the OpenFaaS cluster must be able to pull images from it. See Configure OpenFaaS to pull from a private registry.

Optional: validate functions before merge

You can optionally add a build step that runs on pull requests to validate that functions build correctly before merging. This only builds the images without pushing them to a registry.

image: atlassian/default-image:3

pipelines:
  pull-requests:
    '**':
      - step:
          name: Build functions
          services:
            - docker
          script:
            - curl -sLS https://cli.openfaas.com | sh
            - faas-cli template pull stack
            - faas-cli build

When multiple functions are available in the stack.yaml file you can add --parallel to speed up the build by building multiple functions at once.