Skip to content

Container Image Build

This workflow is used to build container images in a standardised way.

Usage

Basic usage of this action only requires the image_name input.

test-img-build:
  uses: hotosm/gh-workflows/.github/workflows/image_build.yml@1.6.0
  with:
    image_name: ghcr.io/${{ github.repository }}

This will build an image for the repository.

If multiple images are built in the same repository, it is possible to name the images under separate paths:

ghcr.io/${{ github.repository }}/backend
ghcr.io/${{ github.repository }}/frontend
ghcr.io/${{ github.repository }}/some-other-service

Defaults

  • Build an image using the root directory, and file Dockerfile.
  • Automatically tag your image, depending on the branch or version number.
  • Inject the build-args:
    • APP_VERSION=${{ github.ref_name }} (the current branch or tag)
    • COMMIT_REF=${{ github.sha }} (the current commit)
  • Cache your image in the Github Container Registry for future builds.
  • Push your image to the registry for future use.

Vulnerability Scanning

Two types of vulnerability scan are available.

Both are enabled by default.

Static Code Analysis of Dockerfile

Scanning of Dockerfiles for best practice security is done by checkov.

This can be disabled with the input parameter: scan_dockerfile: false.

CVE Scanning of Built Image

The built image is scanned for CVEs present in the installed software by Trivy.

This can be disabled with the input parameter: scan_image: false.

Multi Architecture Builds

There is basic support for building multi-architecture images.

By using the multi_arch: true option, builds can be made for AMD64 (default Linux/Windows), and ARM64 (newer MacOS M-chips).

Please note, however, that using multi_arch may increase your build time by up to 3x.

If speed is important, there is another workflow availble named image_build_multi that will build across multiple Github runners and should be faster (amd64 | arm/v6 | arm/v7 | arm64).

Note: you should carefully consider if multi-architecture builds are worth the performance tradeoff.

As of 2023, deployment on architectures other than AMD64 is rare. To accomodate MacOS users during app development, it is suggested they build the image themselves on their own architecture (often a single command).

Inputs

INPUT TYPE REQUIRED DEFAULT DESCRIPTION
build_target string false The target to built to
(default to end of the Dockerfile).
cache boolean false true Use GHCR caching. Default true.
Set this false if registry
is not ghcr.io.
context string false "." Root directory to start the
build from.
dockerfile string false "Dockerfile" Name of dockerfile, relative to
context dir.
extra_build_args string false Space separated list of extra
build args to use for
the image.
image_name string false Name of image, without tags.
Not required if image_tags specified.
image_tags string false Default=the images are automatically tagged.
Override tags with space separated
list.
multi_arch boolean false false Build a multi-arch image for
AMD64/ARM64.
push boolean false true Override prevent pushing the image.
registry string false "ghcr.io" Override GHCR to use an
external reg.
scan_dockerfile boolean false true Enable dockerfile vulnerability scanning, prior
to build.
scan_image boolean false true Enable image vulnerability scan, after
build.
skip_cve string false "CKV_DOCKER_8,CKV_DOCKER_2,CKV_DOCKER_3,CKV_DOCKER_5" Skip specific CVE from checkcov
(override rules).

Outputs

OUTPUT VALUE DESCRIPTION
image_name "${{ jobs.build-image.outputs.image_name }}" The final full image reference.
image_tag "${{ jobs.build-image.outputs.image_tag }}" The final image tag.

Secrets

No secrets.

Example Usage

Standalone

Multi-arch, cached, auto-tag, auto-push:

backend-build:
  uses: hotosm/gh-workflows/.github/workflows/image_build.yml@main
  with:
    context: src/backend
    build_target: prod
    image_name: ghcr.io/${{ github.repository }}/backend
    extra_build_args: |
      APP_VERSION=${{ github.ref_name }}
      COMMIT_REF=${{ github.sha }}

Manual tagging:

backend-build:
  uses: hotosm/gh-workflows/.github/workflows/image_build.yml
  with:
    context: src/backend
    build_target: prod
    image_tags: |
      "ghcr.io/hotosm/fmtm/backend:latest"
    extra_build_args: |
      APP_VERSION=0.1.0

Passing Variables

Example variable extraction from FMTM:

name: Extract Project Variables

on:
  workflow_call:
    inputs:
      environment:
        description: "The GitHub environment to extract vars from."
        type: string
        default: ""
    outputs:
      api_version:
        description: "Backend API Version."
        value: ${{ jobs.extract-vars.outputs.api_version }}

jobs:
  extract-vars:
    runs-on: ubuntu-latest
    environment: ${{ inputs.environment }}
    outputs:
      api_version: ${{ steps.extract_api_version.outputs.api_version }}

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Extract api version
        id: extract_api_version
        run: |
          cd src/backend
          API_VERSION=$(python -c 'from app.__version__ import __version__; print(__version__)')
          echo "api_version=${API_VERSION}" >> $GITHUB_OUTPUT

Then example variable passing from FMTM:

jobs:
  extract-vars:
    needs:
      - pytest
      - frontend-tests
    uses: ./.github/workflows/extract_vars.yml
    with:
      environment: ${{ github.ref_name }}

  backend-build:
    uses: hotosm/gh-workflows/.github/workflows/image_build.yml
    needs: extract-vars
    with:
      context: src/backend
      build_target: prod
      image_tags: |
        "ghcr.io/hotosm/fmtm/backend:${{ needs.extract-vars.outputs.api_version }}-${{ github.ref_name }}"
        "ghcr.io/hotosm/fmtm/backend:latest"
      extra_build_args: |
        APP_VERSION=${{ needs.extract-vars.outputs.api_version }}