mirror of
https://github.com/outbackdingo/firezone.git
synced 2026-03-22 09:41:59 +00:00
In #7389, we started tagging the built images with the branch name in addition to other tags such as `latest` and the version number. That wasn't enough unfortunately because we also need to tag the merged manifest image that bundles the different architectures together as only that one actually gets pushed to the registry.
408 lines
18 KiB
YAML
408 lines
18 KiB
YAML
name: Build Artifacts
|
|
run-name: Triggered from ${{ github.event_name }} by ${{ github.actor }}
|
|
on:
|
|
workflow_call:
|
|
inputs:
|
|
image_prefix:
|
|
description: |
|
|
The prefix to prepend to the image name to prevent SHA conflicts.
|
|
* Use "debug" to build debug binaries inside debug stage images + with debug tooling installed.
|
|
* Use "perf" to build release binaries inside debug stage images + with debug tooling installed.
|
|
* Leave blank to build release binaries inside release stage images.
|
|
required: false
|
|
type: string
|
|
sha:
|
|
required: false
|
|
type: string
|
|
default: ${{ github.sha }}
|
|
profile:
|
|
description: "The Rust profile to build data plane components with"
|
|
required: true
|
|
type: string
|
|
stage:
|
|
description: "The stage of the data plane component images to build"
|
|
required: true
|
|
type: string
|
|
outputs:
|
|
client_image:
|
|
description: "The client image that was built"
|
|
value: ${{ jobs.data-plane.outputs.client_image }}
|
|
relay_image:
|
|
description: "The relay image that was built"
|
|
value: ${{ jobs.data-plane.outputs.relay_image }}
|
|
gateway_image:
|
|
description: "The gateway image that was built"
|
|
value: ${{ jobs.data-plane.outputs.gateway_image }}
|
|
http_test_server_image:
|
|
description: "The http_test_server image that was built"
|
|
value: ${{ jobs.data-plane.outputs.http_test_server_image }}
|
|
|
|
permissions:
|
|
# write permission is required to create a github release
|
|
contents: write
|
|
id-token: write
|
|
|
|
jobs:
|
|
control-plane:
|
|
name: ${{ matrix.image_name }}
|
|
runs-on: ubuntu-22.04
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- image_name: domain
|
|
target: runtime
|
|
build-args: |
|
|
APPLICATION_NAME=domain
|
|
GIT_SHA=${{ inputs.sha }}
|
|
- image_name: api
|
|
target: runtime
|
|
build-args: |
|
|
APPLICATION_NAME=api
|
|
GIT_SHA=${{ inputs.sha }}
|
|
- image_name: web
|
|
target: runtime
|
|
build-args: |
|
|
APPLICATION_NAME=web
|
|
GIT_SHA=${{ inputs.sha }}
|
|
- image_name: elixir
|
|
target: compiler
|
|
build-args: |
|
|
APPLICATION_NAME=api
|
|
GIT_SHA=${{ inputs.sha }}
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ inputs.sha }}
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@v3
|
|
with:
|
|
# We are overriding the default buildkit version being used by Buildx. We need buildkit >= 12.0 and currently BuildX
|
|
# supports v0.11.6 https://github.com/docker/buildx/blob/b8739d74417f86aa8fc9aafb830a8ba656bdef0e/Dockerfile#L9.
|
|
# We should for any updates on buildx and on the setup-buildx-action itself.
|
|
driver-opts: |
|
|
image=moby/buildkit:v0.15.1
|
|
- uses: ./.github/actions/gcp-docker-login
|
|
id: login
|
|
with:
|
|
project: firezone-staging
|
|
- name: Docker meta
|
|
id: meta
|
|
uses: docker/metadata-action@v5
|
|
with:
|
|
images: ${{ steps.login.outputs.registry }}/firezone/${{matrix.image_name }}
|
|
tags: |
|
|
type=raw,value=${{ inputs.sha }}
|
|
- name: Sanitize github.ref_name
|
|
run: |
|
|
# `ref_name` contains `/`, '_' or '=' which is not a valid docker image tag
|
|
REF="${{ github.ref_name }}"
|
|
CACHE_TAG="${REF//[\/_=]/-}"
|
|
echo "CACHE_TAG=$CACHE_TAG" >> "$GITHUB_ENV"
|
|
- name: Build and push control plane images
|
|
id: build
|
|
uses: docker/build-push-action@v6
|
|
with:
|
|
build-args: ${{ matrix.build-args }}
|
|
target: ${{ matrix.target }}
|
|
context: elixir
|
|
cache-from: |
|
|
type=registry,ref=${{ steps.login.outputs.registry }}/cache/${{ matrix.image_name }}:${{ env.CACHE_TAG }}
|
|
type=registry,ref=${{ steps.login.outputs.registry }}/cache/${{ matrix.image_name }}:main
|
|
cache-to: |
|
|
type=registry,ref=${{steps.login.outputs.registry}}/cache/${{ matrix.image_name}}:${{ env.CACHE_TAG }},mode=max
|
|
push: true
|
|
tags: |
|
|
${{ steps.login.outputs.registry }}/firezone/${{ matrix.image_name }}:${{ inputs.sha }}
|
|
${{ steps.login.outputs.registry }}/firezone/${{ matrix.image_name }}:${{ env.CACHE_TAG }}
|
|
|
|
data-plane:
|
|
name: ${{ matrix.name.image_name }}-${{ matrix.arch.shortname }}
|
|
runs-on: ubuntu-22.04
|
|
defaults:
|
|
run:
|
|
working-directory: rust
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
# Copy input vars to matrix vars to conditionally exclude them
|
|
image_prefix:
|
|
- ${{ inputs.image_prefix }}
|
|
stage:
|
|
- ${{ inputs.stage }}
|
|
|
|
# Syntax is weird because https://github.com/actions/runner/issues/1512
|
|
exclude:
|
|
# Exclude debug builds for non-amd64 targets since they won't be used.
|
|
- { stage: debug, arch: { platform: linux/arm/v7 } }
|
|
- { stage: debug, arch: { platform: linux/arm64 } }
|
|
# Exclude http-test-server from perf image builds
|
|
- { image_prefix: perf, name: { package: http-test-server } }
|
|
|
|
arch:
|
|
- target: x86_64-unknown-linux-musl
|
|
shortname: x86_64
|
|
platform: linux/amd64
|
|
- target: aarch64-unknown-linux-musl # E.g. AWS Graviton
|
|
shortname: aarch64
|
|
platform: linux/arm64
|
|
- target: armv7-unknown-linux-musleabihf # E.g. Raspberry Pi
|
|
platform: linux/arm/v7
|
|
shortname: armv7
|
|
name:
|
|
- package: firezone-headless-client
|
|
artifact: firezone-client-headless-linux
|
|
image_name: client
|
|
# mark:next-headless-version
|
|
release_name: headless-client-1.3.8
|
|
# mark:next-headless-version
|
|
version: 1.3.8
|
|
- package: firezone-relay
|
|
artifact: firezone-relay
|
|
image_name: relay
|
|
- package: firezone-gateway
|
|
artifact: firezone-gateway
|
|
image_name: gateway
|
|
# mark:next-gateway-version
|
|
release_name: gateway-1.4.2
|
|
# mark:next-gateway-version
|
|
version: 1.4.2
|
|
- package: http-test-server
|
|
artifact: http-test-server
|
|
image_name: http-test-server
|
|
env:
|
|
BINARY_DEST_PATH: ${{ matrix.name.artifact }}_${{ matrix.name.version }}_${{ matrix.arch.shortname }}
|
|
SENTRY_ENVIRONMENT: "production"
|
|
outputs:
|
|
client_image: ${{ steps.image-name.outputs.client_image }}
|
|
relay_image: ${{ steps.image-name.outputs.relay_image }}
|
|
gateway_image: ${{ steps.image-name.outputs.gateway_image }}
|
|
http_test_server_image: ${{ steps.image-name.outputs.http-test-server_image }}
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ inputs.sha }}
|
|
- uses: ./.github/actions/setup-rust
|
|
with:
|
|
targets: ${{ matrix.arch.target }}
|
|
# Cross doesn't support scccache without a lot of work
|
|
cache_backend: github
|
|
# Cache needs to be scoped per OS version and target since cross seems to clobber the cache
|
|
key: ubuntu-22.04-${{ matrix.arch.target }}
|
|
- uses: taiki-e/install-action@v2
|
|
with:
|
|
tool: cross
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
- name: Build binaries
|
|
run: |
|
|
set -xe
|
|
|
|
if [[ "${{ inputs.profile }}" == "release" ]]; then
|
|
PROFILE="--release"
|
|
else
|
|
PROFILE=""
|
|
fi
|
|
|
|
cross build $PROFILE -p ${{ matrix.name.package }} --target ${{ matrix.arch.target }}
|
|
|
|
# Used for Docker images
|
|
cp target/${{ matrix.arch.target }}/${{ inputs.profile }}/${{ matrix.name.package }} ${{ matrix.name.package }}
|
|
- name: Upload Release Assets
|
|
if: ${{ inputs.profile == 'release' && matrix.stage == 'release' && matrix.name.release_name }}
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: |
|
|
set -xe
|
|
|
|
# Only clobber existing release assets if the release is a draft
|
|
is_draft=$(gh release view ${{ matrix.name.release_name }} --json isDraft --jq '.isDraft' | tr -d '\n')
|
|
if [[ "$is_draft" == "true" ]]; then
|
|
clobber="--clobber"
|
|
else
|
|
clobber=""
|
|
fi
|
|
|
|
# Used for release artifact
|
|
cp target/${{ matrix.arch.target }}/${{ inputs.profile }}/${{ matrix.name.package }} $BINARY_DEST_PATH
|
|
sha256sum $BINARY_DEST_PATH > $BINARY_DEST_PATH.sha256sum.txt
|
|
gh release upload ${{ matrix.name.release_name }} \
|
|
${{ env.BINARY_DEST_PATH }} \
|
|
${{ env.BINARY_DEST_PATH }}.sha256sum.txt \
|
|
$clobber \
|
|
--repo ${{ github.repository }}
|
|
- name: Authenticate to Google Cloud
|
|
id: auth
|
|
if: ${{ inputs.profile == 'release' && matrix.stage == 'release' && contains(fromJSON('["gateway", "client"]'), matrix.name.image_name) }}
|
|
uses: google-github-actions/auth@v2
|
|
with:
|
|
workload_identity_provider: "projects/397012414171/locations/global/workloadIdentityPools/github-actions-pool/providers/github-actions"
|
|
service_account: "github-actions@github-iam-387915.iam.gserviceaccount.com"
|
|
export_environment_variables: true
|
|
create_credentials_file: true
|
|
- name: Copy binaries to Google Cloud Storage
|
|
if: ${{ inputs.profile == 'release' && matrix.stage == 'release' && contains(fromJSON('["gateway", "client"]'), matrix.name.image_name) }}
|
|
run: |
|
|
gcloud storage cp \
|
|
${BINARY_DEST_PATH} \
|
|
gs://firezone-staging-artifacts/firezone-${{ matrix.name.image_name }}/${{ inputs.sha }}/${{ matrix.arch.shortname }}
|
|
|
|
gcloud storage cp \
|
|
${BINARY_DEST_PATH}.sha256sum.txt \
|
|
gs://firezone-staging-artifacts/firezone-${{ matrix.name.image_name }}/${{ inputs.sha }}/${{ matrix.arch.shortname }}.sha256sum.txt
|
|
- name: Set up QEMU
|
|
uses: docker/setup-qemu-action@v3
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@v3
|
|
with:
|
|
# We are overriding the default buildkit version being used by Buildx. We need buildkit >= 12.0 and currently BuildX
|
|
# supports v0.11.6 https://github.com/docker/buildx/blob/b8739d74417f86aa8fc9aafb830a8ba656bdef0e/Dockerfile#L9.
|
|
# We should for any updates on buildx and on the setup-buildx-action itself.
|
|
driver-opts: |
|
|
image=moby/buildkit:v0.15.1
|
|
- uses: ./.github/actions/gcp-docker-login
|
|
id: login
|
|
with:
|
|
project: firezone-staging
|
|
- name: Build Version Tags
|
|
run: |
|
|
set -xe
|
|
|
|
version="${{ matrix.name.version }}"
|
|
MAJOR_VERSION="${version%%.*}"
|
|
MAJOR_MINOR_VERSION="${version%.*}"
|
|
echo "MAJOR_VERSION=${MAJOR_VERSION}" >> $GITHUB_ENV
|
|
echo "MAJOR_MINOR_VERSION=${MAJOR_MINOR_VERSION}" >> $GITHUB_ENV
|
|
- name: Docker meta
|
|
id: meta
|
|
uses: docker/metadata-action@v5
|
|
with:
|
|
images: ${{ steps.login.outputs.registry }}/firezone/${{ matrix.image_prefix && format('{0}/', matrix.image_prefix) || '' }}${{ matrix.name.image_name }}
|
|
# We only version client and gateway
|
|
tags: |
|
|
type=raw,value=latest
|
|
type=raw,value={{branch}}
|
|
type=raw,value=${{ inputs.sha }}
|
|
${{ matrix.name.version && format('type=raw,value={0}', matrix.name.version) }}
|
|
${{ matrix.name.version && format('type=raw,value={0}-{1}', matrix.name.version, inputs.sha) }}
|
|
${{ matrix.name.version && format('type=raw,value={0}', env.MAJOR_VERSION) }}
|
|
${{ matrix.name.version && format('type=raw,value={0}', env.MAJOR_MINOR_VERSION) }}
|
|
- name: Sanitize github.ref_name
|
|
run: |
|
|
# `ref_name` contains `/`, '_' or '=' which is not a valid docker image tag
|
|
REF="${{ github.ref_name }}"
|
|
CACHE_TAG="${REF//[\/_=]/-}"
|
|
echo "CACHE_TAG=$CACHE_TAG" >> "$GITHUB_ENV"
|
|
- name: Build Docker images
|
|
id: build
|
|
uses: docker/build-push-action@v6
|
|
with:
|
|
platforms: ${{ matrix.arch.platform }}
|
|
build-args: |
|
|
PACKAGE=${{ matrix.name.package }}
|
|
TARGET=${{ matrix.arch.target }}
|
|
context: rust
|
|
cache-from: |
|
|
type=registry,ref=${{ steps.login.outputs.registry }}/cache/${{ matrix.name.image_name }}:${{ env.CACHE_TAG }}
|
|
type=registry,ref=${{ steps.login.outputs.registry }}/cache/${{ matrix.name.image_name }}:main
|
|
cache-to: |
|
|
type=registry,ref=${{ steps.login.outputs.registry }}/cache/${{ matrix.name.image_name }}:${{ env.CACHE_TAG }},mode=max
|
|
target: ${{ matrix.stage }}
|
|
outputs: type=image,name=${{ steps.login.outputs.registry }}/firezone/${{ matrix.image_prefix && format('{0}/', matrix.image_prefix) || '' }}${{ matrix.name.image_name }},push-by-digest=true,name-canonical=true,push=true
|
|
- name: Export digest
|
|
run: |
|
|
mkdir -p /tmp/digests/${{ matrix.name.image_name }}
|
|
digest="${{ steps.build.outputs.digest }}"
|
|
touch "/tmp/digests/${{ matrix.name.image_name }}/${digest#sha256:}"
|
|
- name: Upload digest artifact
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
overwrite: true
|
|
name: ${{ matrix.image_prefix && format('{0}-', matrix.image_prefix) || '' }}${{ matrix.name.image_name }}-${{ inputs.sha }}-digest-${{ matrix.arch.shortname }}
|
|
path: /tmp/digests/${{ matrix.name.image_name }}
|
|
if-no-files-found: error
|
|
retention-days: 1
|
|
- name: Output image name
|
|
id: image-name
|
|
run: echo "${{ matrix.name.image_name }}_image=${{ steps.login.outputs.registry }}/firezone/${{ matrix.image_prefix && format('{0}/', matrix.image_prefix) || '' }}${{ matrix.name.image_name }}" >> $GITHUB_OUTPUT
|
|
|
|
merge-docker-artifacts:
|
|
name: merge-${{ matrix.image.name }}
|
|
needs: data-plane
|
|
if: ${{ always() }}
|
|
runs-on: ubuntu-22.04
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
# Copy input vars to matrix vars to conditionally exclude them
|
|
image_prefix:
|
|
- ${{ inputs.image_prefix }}
|
|
|
|
# Exclude http-test-server from perf image builds
|
|
exclude:
|
|
- { image_prefix: perf, image: { name: http-test-server } }
|
|
|
|
image:
|
|
- name: relay
|
|
- name: gateway
|
|
# mark:next-gateway-version
|
|
version: 1.4.2
|
|
- name: client
|
|
# mark:next-client-version
|
|
version: 1.0.6
|
|
- name: http-test-server
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ inputs.sha }}
|
|
- uses: ./.github/actions/gcp-docker-login
|
|
id: login
|
|
with:
|
|
project: firezone-staging
|
|
- name: Download digests
|
|
uses: actions/download-artifact@v4
|
|
with:
|
|
pattern: ${{ matrix.image_prefix && format('{0}-', matrix.image_prefix) || '' }}${{ matrix.image.name }}-${{ inputs.sha }}-digest-*
|
|
merge-multiple: true
|
|
path: /tmp/digests/${{ matrix.image.name }}
|
|
- name: Display structure of downloaded artifacts
|
|
run: ls -R /tmp/digests
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@v3
|
|
with:
|
|
# We are overriding the default buildkit version being used by Buildx. We need buildkit >= 12.0 and currently BuildX
|
|
# supports v0.11.6 https://github.com/docker/buildx/blob/b8739d74417f86aa8fc9aafb830a8ba656bdef0e/Dockerfile#L9.
|
|
# We should for any updates on buildx and on the setup-buildx-action itself.
|
|
driver-opts: |
|
|
image=moby/buildkit:v0.15.1
|
|
- name: Build Version Tags
|
|
run: |
|
|
set -xe
|
|
|
|
version="${{ matrix.image.version }}"
|
|
MAJOR_VERSION="${version%%.*}"
|
|
MAJOR_MINOR_VERSION="${version%.*}"
|
|
echo "MAJOR_VERSION=${MAJOR_VERSION}" >> $GITHUB_ENV
|
|
echo "MAJOR_MINOR_VERSION=${MAJOR_MINOR_VERSION}" >> $GITHUB_ENV
|
|
- name: Docker meta
|
|
id: meta
|
|
uses: docker/metadata-action@v5
|
|
with:
|
|
images: ${{ steps.login.outputs.registry }}/firezone/${{ matrix.image_prefix && format('{0}/', matrix.image_prefix) || '' }}${{ matrix.image.name }}
|
|
tags: |
|
|
type=raw,value=latest
|
|
type=raw,value={{branch}}
|
|
type=raw,value=${{ inputs.sha }}
|
|
${{ matrix.image.version && format('type=raw,value={0}', matrix.image.version) }}
|
|
${{ matrix.image.version && format('type=raw,value={0}-{1}', matrix.image.version, inputs.sha) }}
|
|
${{ matrix.image.version && format('type=raw,value={0}', env.MAJOR_VERSION) }}
|
|
${{ matrix.image.version && format('type=raw,value={0}', env.MAJOR_MINOR_VERSION) }}
|
|
- name: Create manifest list and push
|
|
working-directory: /tmp/digests/${{ matrix.image.name }}
|
|
run: |
|
|
tags=$(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON")
|
|
sources=$(printf '${{ steps.login.outputs.registry }}/firezone/${{ matrix.image_prefix && format('{0}/', matrix.image_prefix) || '' }}${{ matrix.image.name }}@sha256:%s ' *)
|
|
echo "$sources"
|
|
docker buildx imagetools create $tags $sources
|
|
docker buildx imagetools inspect "${{ steps.login.outputs.registry }}/firezone/${{ matrix.image_prefix && format('{0}/', matrix.image_prefix) || '' }}${{ matrix.image.name }}"
|