Skip to content

Build and Publish Docker Image #1508

Build and Publish Docker Image

Build and Publish Docker Image #1508

name: Build and Publish Docker Image
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
on:
schedule:
- cron: '0 10 * * *'
# If any commit message in your push or the HEAD commit of your PR contains the strings
# [skip ci], [ci skip], [no ci], [skip actions], or [actions skip]
# workflows triggered on the push or pull_request events will be skipped.
# https://github.blog/changelog/2021-02-08-github-actions-skip-pull-request-and-push-workflows-with-skip-ci/
push:
branches: [ master ]
# Publish semver tags as releases.
tags: [ 'v[0-9]+.[0-9]+.[0-9]+' ]
# If any commit message in your push or the HEAD commit of your PR contains the strings
# [skip ci], [ci skip], [no ci], [skip actions], or [actions skip]
# workflows triggered on the push or pull_request events will be skipped.
# https://github.blog/changelog/2021-02-08-github-actions-skip-pull-request-and-push-workflows-with-skip-ci/
pull_request:
branches: [ master ]
env:
# https://hub.docker.com/r/athenz/authorization-proxy/tags
DOCKER_REGISTRY_URL: docker.io
DOCKER_REGISTRY_ORG: athenz
DOCKER_REGISTRY_IMAGE: authorization-proxy
# DOCKER_REGISTRY_USER: values for docker login is stored in repository variables
# DOCKER_REGISTRY_TOKEN_NAME: values for docker login is stored in repository variables
TAGS_CONFIG: |
# If branch is master, main or default branch, push the latest tag image:
type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', github.event.repository.default_branch) }}
type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'master') }}
type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'main') }}
# If the event is a tag release in semver syntax, push the latest tag image:
type=semver,pattern=latest
# If it is PR version, push the pr-<pr-number> tag image:
type=ref,event=pr
type=semver,pattern=v{{version}}
# Any cron builds (scheduled workflows) push the nightly tag image:
type=schedule,pattern=nightly
jobs:
set_matrix:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set.outputs.matrix }}
suffixes: ${{ steps.set.outputs.suffixes }}
steps:
- id: set
run: |
# We define BUILD_MATRIX so that we have multiple platform supported,
# maybe Windows as well in the future:
MATRIX_JSON='{
"include": [
{ "platform": "linux/amd64", "runner": "ubuntu-latest", "suffix": "-amd64" },
{ "platform": "linux/arm64", "runner": "ubuntu-24.04-arm", "suffix": "-arm64" }
]
}'
# Store JSON data:
echo "matrix=$(echo "$MATRIX_JSON" | jq -c .)" >> $GITHUB_OUTPUT
# Store Suffix list:
echo "suffixes=$(echo "$MATRIX_JSON" | jq -r '.include[].suffix' | xargs)" >> $GITHUB_OUTPUT
build:
needs: set_matrix
runs-on: ${{ matrix.runner }}
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.set_matrix.outputs.matrix) }}
permissions:
actions: none
checks: none
contents: read
deployments: none
issues: none
discussions: none
packages: write # for ghcr read permission
pull-requests: none
repository-projects: none
security-events: none
statuses: none
steps:
# A GitHub Action to expose useful environment variables.
# https://github.com/FranzDiebold/github-env-vars-action
-
name: GitHub Environment Variables Action
id: env
# uses: https://github.com/FranzDiebold/github-env-vars-action/tags
uses: FranzDiebold/github-env-vars-action@v2
# This action checks-out your repository under $GITHUB_WORKSPACE, so your workflow can access it.
# https://github.com/actions/checkout
-
name: Checkout repository
id: checkout
# You may pin to the exact commit or the version.
# uses: https://github.com/actions/checkout/tags
uses: actions/checkout@v4
# This action sets up a go environment for use in actions by:
# - Optionally downloading and caching a version of Go by version and adding to PATH.
# - Registering problem matchers for error output.
# https://github.com/actions/setup-go
-
name: Setup Golang
id: setup-go
# You may pin to the exact commit or the version.
# uses: https://github.com/actions/setup-go/tags
uses: actions/setup-go@v4
with:
# Fix the following warning: Both go-version and go-version-file inputs are specified, only go-version will be used
go-version: "stable"
# go-version-file: './go.mod'
cache: true
# A GitHub Action for golang tests
-
name: Golang Tests
id: go-tests
run: |
go version
rm -rf example
go test -v -race -covermode=atomic -coverprofile=coverage.out ./...
go tool cover -html=coverage.out -o coverage.html
# https://github.com/apache/skywalking-eyes
# issue: go version hard-coded: https://github.com/apache/skywalking-eyes/blob/5dfa68f93380a5e57259faaf95088b7f133b5778/header/action.yml#L47-L51
- name: Check License Header
if: matrix.platform == 'linux/amd64' # Only required once for any platform, and will do the most general amd64
uses: apache/skywalking-eyes/header@main
with:
log: "info" # optional: set the log level. The default value is `info`.
config: ".licenserc.yaml" # optional: set the config file. The default value is `.licenserc.yaml`.
token: "" # optional: the token that license eye uses when it needs to comment on the pull request. Set to empty ("") to disable commenting on pull request. The default value is ${{ github.token }}
mode: "check" # optional: Which mode License-Eye should be run in. Choices are `check` or `fix`. The default value is `check`.
# The Github action runs CIS Dockerfile benchmark against dockerfiles in repository (CIS 4.1, 4.2, 4.3, 4.6, 4.7, 4.9, 4.10)
# https://github.com/sysdiglabs/benchmark-dockerfile
-
name: Sysdig Benchmark Dockerfile
id: sysdig
if: matrix.platform == 'linux/amd64' # Only required once for any platform, and will do the most general amd64
# You may pin to the exact commit or the version.
# uses: https://github.com/sysdiglabs/benchmark-dockerfile/tags
uses: sysdiglabs/[email protected]
with:
# Directory of dockerfiles (default "./")
directory: "./"
# list of disallowed packages separated by comma (default ")
#disallowedPackages: ''
# list of trusted base images separated by comma (default "", meaning trust any base image)
trustedBaseImages: ""
# The Github action runs CIS Dockerfile benchmark against dockerfiles in repository (CIS 4.1, 4.2, 4.3, 4.6, 4.7, 4.9, 4.10)
# https://github.com/sysdiglabs/benchmark-dockerfile
# TODO: Skipping CIS 4.1 check until https://github.com/yahoojapan/authorization-proxy/pull/95 is fixed.
-
name: Post Sysdig Benchmark Dockerfile
id: postsysdig
if: matrix.platform == 'linux/amd64' # Only required once for any platform, and will do the most general amd64
run: |
echo ${{ toJSON(steps.sysdig.outputs.violation_report) }} | \
jq -r .
echo ${{ toJSON(steps.sysdig.outputs.violation_report) }} | \
jq -r '.cis_docker_benchmark_violation_report[] | select(.rule!="CIS 4.1 Create a user for the container") | .violations[]' | \
wc -l | \
xargs -I% test 0 -eq %
# GitHub Action to install QEMU static binaries.
# https://github.com/docker/setup-qemu-action
-
name: Set up QEMU
id: qemu
# You may pin to the exact commit or the version.
# uses: https://github.com/docker/setup-qemu-action/tags
uses: docker/setup-qemu-action@v3
# GitHub Action to set up Docker Buildx.
# https://github.com/docker/setup-buildx-action
-
name: Set up Docker Buildx
id: buildx
# You may pin to the exact commit or the version.
# uses: https://github.com/docker/setup-buildx-action/tags
uses: docker/setup-buildx-action@v3
- name: Login to Temporary Registry (GitHub Container Registry)
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Lowercase image id name to follow the docker name rule
run: |
IMAGE_ID=ghcr.io/${{ github.repository }}
echo "GHCR_IMAGE_ID=$(echo $IMAGE_ID | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV
- name: Build and Push to GHCR (Staging)
uses: docker/build-push-action@v4
with:
context: .
push: true
# tag i.e) ghcr.io/athenz/authorization-proxy:sha-ck29d1-amd64
tags: ${{ env.GHCR_IMAGE_ID }}:${{ github.sha }}${{ matrix.suffix }}
platforms: ${{ matrix.platform }}
cache-from: type=gha
cache-to: type=gha,mode=max
# Test Docker image
-
name: Test Docker image
id: test_docker
run: |
docker run --rm ${{ env.GHCR_IMAGE_ID }}:${{ github.sha }}${{ matrix.suffix }} --version
merge:
if: github.event_name != 'pull_request' # We do not need to push pr images to official registry (Docker.io)
needs:
- set_matrix
- build # Make sure each build of every platform defined in matrix is completed
runs-on: ubuntu-latest
permissions:
packages: write # Give read permission WITHOUT making the registry_visibility=Public
steps:
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Login to Docker registry
uses: docker/login-action@v3
with:
# Server address of Docker registry. If not set then will default to Docker Hub
registry: ${{ env.DOCKER_REGISTRY_URL }} # optional
# Username used to log against the Docker registry
username: ${{ vars.DOCKER_REGISTRY_USER }} # optional
# Password or personal access token used to log against the Docker registry
password: ${{ secrets[vars.DOCKER_REGISTRY_TOKEN_NAME] }} # optional
# Log out from the Docker registry at the end of a job
logout: true # optional, default is true
- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.DOCKER_REGISTRY_URL }}/${{ env.DOCKER_REGISTRY_ORG }}/${{ env.DOCKER_REGISTRY_IMAGE }}
flavor: |
latest=false
# No suffix defined as this will be the merged one!
tags: ${{ env.TAGS_CONFIG }}
- name: Set GHCR Image Name (Lowercase)
run: |
IMAGE_ID=ghcr.io/${{ github.repository }}
echo "GHCR_IMAGE_ID=$(echo $IMAGE_ID | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV
- name: Create Manifest and Push to Docker Hub
env:
PLATFORM_SUFFIXES: ${{ needs.set_matrix.outputs.suffixes }}
SHA_TAG: ${{ github.sha }}
run: |
echo "${{ steps.meta.outputs.tags }}" | while read -r docker_registry_tag; do
echo "Merging sources into final tag: $docker_registry_tag"
sources=""
for suffix in $PLATFORM_SUFFIXES; do
# i.e) ghcr.io/athenz/authorization-proxy:sha-xxx-amd64
sources="$sources ${{ env.GHCR_IMAGE_ID }}:${SHA_TAG}${suffix}"
done
docker buildx imagetools create -t "$docker_registry_tag" $sources
done
cleanup:
name: Cleanup Temporary Images from GitHub Container Registry
needs: [set_matrix, build, merge]
if: always()
runs-on: ubuntu-latest
permissions:
packages: write # Permission to delete images from GitHub Container Registry
steps:
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Delete Temporary Images using GitHub API
env:
OWNER: ${{ github.repository_owner }}
PACKAGE_NAME: authorization-proxy
SHA_TAG: ${{ github.sha }}
PLATFORM_SUFFIXES: ${{ needs.set_matrix.outputs.suffixes }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo "🧹 Cleanup using GitHub API..."
for suffix in $PLATFORM_SUFFIXES; do
TAG_NAME="${SHA_TAG}${suffix}"
echo "🔍 Finding version ID for tag: $TAG_NAME"
VERSION_ID=$(gh api "/orgs/$OWNER/packages/container/$PACKAGE_NAME/versions" \
-H "Accept: application/vnd.github+json" \
--jq ".[] | select(.metadata.container.tags[]? == \"$TAG_NAME\") | .id")
if [ -z "$VERSION_ID" ]; then
echo "⚠️ Tag $TAG_NAME not found (already deleted?)"
continue
fi
echo "🗑️ Deleting Version ID: $VERSION_ID (Tag: $TAG_NAME)"
# Delete based on ID:
gh api -X DELETE "/orgs/$OWNER/packages/container/$PACKAGE_NAME/versions/$VERSION_ID" \
-H "Accept: application/vnd.github+json" || true
done
echo "✨ Cleanup finished!"