Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions template/.actionlint.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
self-hosted-runner:
# BuildJet machines we are using
labels:
- buildjet-2vcpu-ubuntu-2204-arm
- buildjet-4vcpu-ubuntu-2204-arm
70 changes: 60 additions & 10 deletions template/.github/workflows/build.yml.j2
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ jobs:
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
with:
submodules: recursive
- uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # tag=v5.1.0
- uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5.1.0
with:
python-version: '3.12'
- name: Install jinja2-cli
Expand Down Expand Up @@ -298,11 +298,14 @@ jobs:
run: echo All tests have passed!

package_and_publish:
name: Package Charts, Build Docker Image and publish them
name: Package Charts, Build Docker Image and publish them - ${{ matrix.runner }}
needs:
- tests_passed
- select_helm_repo
runs-on: ubuntu-latest
strategy:
matrix:
runner: ["ubuntu-latest", "buildjet-2vcpu-ubuntu-2204-arm"]
runs-on: ${{ matrix.runner }}
permissions:
id-token: write
env:
Expand All @@ -324,7 +327,7 @@ jobs:
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
with:
submodules: recursive
- uses: cachix/install-nix-action@8887e596b4ee1134dae06b98d573bd674693f47c # tag=v26
- uses: cachix/install-nix-action@8887e596b4ee1134dae06b98d573bd674693f47c # v26
- uses: dtolnay/rust-toolchain@d8352f6b1d2e870bc5716e7a6d9b65c4cc244a1a
with:
toolchain: ${{ env.RUST_TOOLCHAIN_VERSION }}
Expand All @@ -340,15 +343,25 @@ jobs:
if: ${{ github.event_name == 'pull_request' }}
run: cargo set-version --offline --workspace 0.0.0-pr${{ github.event.pull_request.number }}

# Recreate charts and publish charts and docker image. The "-e" is needed as we want to override the
# default value in the makefile if called from this action, but not otherwise (i.e. when called locally).
# This is needed for the HELM_REPO variable.
# Recreate charts and publish charts and docker image. The "-e" is needed as we want to override the
# default value in the makefile if called from this action, but not otherwise (i.e. when called locally).
# This is needed for the HELM_REPO variable.
- name: Install cosign
uses: sigstore/cosign-installer@59acb6260d9c0ba8f4a2f9d9b48431a222b68e20 # tag=v3.5.0
uses: sigstore/cosign-installer@59acb6260d9c0ba8f4a2f9d9b48431a222b68e20 # v3.5.0
- name: Install syft
uses: anchore/sbom-action/download-syft@7ccf588e3cf3cc2611714c2eeae48550fbc17552 # v0.15.11
- name: Build Docker image and Helm chart
run: make -e build-ci
run: |
# Installing helm on BuildJet only
if [ "$(arch)" = "aarch64" ]; then
curl https://baltocdn.com/helm/signing.asc | gpg --dearmor | sudo tee /usr/share/keyrings/helm.gpg > /dev/null
sudo apt-get -y install apt-transport-https --yes
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/helm.gpg] https://baltocdn.com/helm/stable/debian/ all main" | sudo tee /etc/apt/sources.list.d/helm-stable-debian.list
sudo apt-get -y update
sudo apt-get -y install helm
fi

make -e build
- name: Publish Docker image and Helm chart
if: ${{ !github.event.pull_request.head.repo.fork }}
run: make -e publish
Expand All @@ -358,6 +371,43 @@ jobs:
if: ${{ !github.event.pull_request.head.repo.fork }}
run: echo "IMAGE_TAG=$(make -e print-docker-tag)" >> $GITHUB_OUTPUT

create_manifest_list:
name: Build and publish manifest list
needs:
- package_and_publish
runs-on: ubuntu-latest
permissions:
id-token: write
env:
NEXUS_PASSWORD: ${{ secrets.NEXUS_PASSWORD }}
OCI_REGISTRY_SDP_PASSWORD: ${{ secrets.HARBOR_ROBOT_SDP_GITHUB_ACTION_BUILD_SECRET }}
OCI_REGISTRY_SDP_USERNAME: "robot$sdp+github-action-build"
OCI_REGISTRY_SDP_CHARTS_PASSWORD: ${{ secrets.HARBOR_ROBOT_SDP_CHARTS_GITHUB_ACTION_BUILD_SECRET }}
OCI_REGISTRY_SDP_CHARTS_USERNAME: "robot$sdp-charts+github-action-build"
steps:
- name: Install cosign
uses: sigstore/cosign-installer@59acb6260d9c0ba8f4a2f9d9b48431a222b68e20 # v3.5.0
- name: Checkout
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
with:
submodules: recursive
# This step checks if the current run was triggered by a push to a pr (or a pr being created).
# If this is the case it changes the version of this project in all Cargo.toml files to include the suffix
# "-pr<prnumber>" so that the published artifacts can be linked to this PR.
- uses: stackabletech/cargo-install-action@main
with:
crate: cargo-edit
bin: cargo-set-version
- name: Update version if PR
if: ${{ github.event_name == 'pull_request' }}
run: cargo set-version --offline --workspace 0.0.0-pr${{ github.event.pull_request.number }}
- name: Build manifest list
run: |
# Creating manifest list
make -e docker-manifest-list-build
# Pushing and signing manifest list
make -e docker-manifest-list-publish

openshift_preflight:
name: Run the OpenShift Preflight check on the published images
if: ${{ !github.event.pull_request.head.repo.fork }}
Expand All @@ -376,4 +426,4 @@ jobs:
ARCH_FOR_PREFLIGHT="$(arch | sed -e 's#x86_64#amd64#' | sed -e 's#aarch64#arm64#')"
./preflight-linux-amd64 check container "$IMAGE_TAG" --platform "${ARCH_FOR_PREFLIGHT}" > preflight.out
- name: "Passed?"
run: '[ "$(./preflight-linux-amd64 check container "$IMAGE_TAG" --platform "${ARCH_FOR_PREFLIGHT}" | jq -r .passed)" == true ]'
run: '[ "$(cat preflight.out | jq -r .passed)" == true ]'
2 changes: 2 additions & 0 deletions template/.gitignore.j2
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,5 @@ tilt_options.json
.direnv/
.direnvrc
.envrc

.DS_Store
47 changes: 37 additions & 10 deletions template/Makefile.j2
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
TAG := $(shell git rev-parse --short HEAD)
OPERATOR_NAME := {[ operator.name }]
VERSION := $(shell cargo metadata --format-version 1 | jq -r '.packages[] | select(.name=="stackable-${OPERATOR_NAME}") | .version')
ARCH := $(shell arch | sed -e 's#x86_64#amd64#' | sed -e 's#aarch64#arm64#')

DOCKER_REPO := docker.stackable.tech
ORGANIZATION := stackable
Expand All @@ -30,17 +31,17 @@ render-readme:

## Docker related targets
docker-build:
docker build --force-rm --build-arg VERSION=${VERSION} -t "${DOCKER_REPO}/${ORGANIZATION}/${OPERATOR_NAME}:${VERSION}" -f docker/Dockerfile .
docker tag "${DOCKER_REPO}/${ORGANIZATION}/${OPERATOR_NAME}:${VERSION}" "${OCI_REGISTRY_HOSTNAME}/${OCI_REGISTRY_PROJECT_IMAGES}/${OPERATOR_NAME}:${VERSION}"
docker build --force-rm --build-arg VERSION=${VERSION} -t "${DOCKER_REPO}/${ORGANIZATION}/${OPERATOR_NAME}:${VERSION}-${ARCH}" -f docker/Dockerfile .
docker tag "${DOCKER_REPO}/${ORGANIZATION}/${OPERATOR_NAME}:${VERSION}-${ARCH}" "${OCI_REGISTRY_HOSTNAME}/${OCI_REGISTRY_PROJECT_IMAGES}/${OPERATOR_NAME}:${VERSION}-${ARCH}"

docker-publish:
# Push to Nexus
echo "${NEXUS_PASSWORD}" | docker login --username github --password-stdin "${DOCKER_REPO}"
DOCKER_OUTPUT=$$(docker push --all-tags "${DOCKER_REPO}/${ORGANIZATION}/${OPERATOR_NAME}");\
# Obtain the digest of the pushed image from the output of `docker push`, because signing by tag is deprecated and will be removed from cosign in the future\
REPO_DIGEST_OF_IMAGE=$$(echo "$$DOCKER_OUTPUT" | awk '/^${VERSION}: digest: sha256:[0-9a-f]{64} size: [0-9]+$$/ { print $$3 }');\
REPO_DIGEST_OF_IMAGE=$$(echo "$$DOCKER_OUTPUT" | awk '/^${VERSION}-${ARCH}: digest: sha256:[0-9a-f]{64} size: [0-9]+$$/ { print $$3 }');\
if [ -z "$$REPO_DIGEST_OF_IMAGE" ]; then\
echo 'Could not find repo digest for container image: ${DOCKER_REPO}/${ORGANIZATION}/${OPERATOR_NAME}:${VERSION}';\
echo 'Could not find repo digest for container image: ${DOCKER_REPO}/${ORGANIZATION}/${OPERATOR_NAME}:${VERSION}-${ARCH}';\
exit 1;\
fi;\
# This generates a signature and publishes it to the registry, next to the image\
Expand All @@ -51,8 +52,8 @@ docker-publish:
# Determine the PURL for the container image\
PURL="pkg:docker/${ORGANIZATION}/${OPERATOR_NAME}@$$REPO_DIGEST_OF_IMAGE?repository_url=${DOCKER_REPO}";\
# Get metadata from the image\
IMAGE_DESCRIPTION=$$(docker inspect --format='{{.Config.Labels.description}}' "${DOCKER_REPO}/${ORGANIZATION}/${OPERATOR_NAME}:${VERSION}");\
IMAGE_NAME=$$(docker inspect --format='{{.Config.Labels.name}}' "${DOCKER_REPO}/${ORGANIZATION}/${OPERATOR_NAME}:${VERSION}");\
IMAGE_DESCRIPTION=$$(docker inspect --format='{{.Config.Labels.description}}' "${DOCKER_REPO}/${ORGANIZATION}/${OPERATOR_NAME}:${VERSION}-${ARCH}");\
IMAGE_NAME=$$(docker inspect --format='{{.Config.Labels.name}}' "${DOCKER_REPO}/${ORGANIZATION}/${OPERATOR_NAME}:${VERSION}-${ARCH}");\
# Merge the SBOM with the metadata for the operator\
jq -s '{"metadata":{"component":{"description":"'"$$IMAGE_NAME. $$IMAGE_DESCRIPTION"'","supplier":{"name":"Stackable GmbH","url":["https://stackable.tech/"]},"author":"Stackable GmbH","purl":"'"$$PURL"'","publisher":"Stackable GmbH"}}} * .[0]' sbom.json > sbom.merged.json;\
# Attest the SBOM to the image\
Expand All @@ -63,9 +64,9 @@ docker-publish:
docker login --username '${value OCI_REGISTRY_SDP_USERNAME}' --password '${OCI_REGISTRY_SDP_PASSWORD}' '${OCI_REGISTRY_HOSTNAME}'
DOCKER_OUTPUT=$$(docker push --all-tags '${OCI_REGISTRY_HOSTNAME}/${OCI_REGISTRY_PROJECT_IMAGES}/${OPERATOR_NAME}');\
# Obtain the digest of the pushed image from the output of `docker push`, because signing by tag is deprecated and will be removed from cosign in the future\
REPO_DIGEST_OF_IMAGE=$$(echo "$$DOCKER_OUTPUT" | awk '/^${VERSION}: digest: sha256:[0-9a-f]{64} size: [0-9]+$$/ { print $$3 }');\
REPO_DIGEST_OF_IMAGE=$$(echo "$$DOCKER_OUTPUT" | awk '/^${VERSION}-${ARCH}: digest: sha256:[0-9a-f]{64} size: [0-9]+$$/ { print $$3 }');\
if [ -z "$$REPO_DIGEST_OF_IMAGE" ]; then\
echo 'Could not find repo digest for container image: ${OCI_REGISTRY_HOSTNAME}/${OCI_REGISTRY_PROJECT_IMAGES}/${OPERATOR_NAME}:${VERSION}';\
echo 'Could not find repo digest for container image: ${OCI_REGISTRY_HOSTNAME}/${OCI_REGISTRY_PROJECT_IMAGES}/${OPERATOR_NAME}:${VERSION}-${ARCH}';\
exit 1;\
fi;\
# This generates a signature and publishes it to the registry, next to the image\
Expand All @@ -76,13 +77,39 @@ docker-publish:
# Determine the PURL for the container image\
PURL="pkg:docker/${OCI_REGISTRY_PROJECT_IMAGES}/${OPERATOR_NAME}@$$REPO_DIGEST_OF_IMAGE?repository_url=${OCI_REGISTRY_HOSTNAME}";\
# Get metadata from the image\
IMAGE_DESCRIPTION=$$(docker inspect --format='{{.Config.Labels.description}}' "${OCI_REGISTRY_HOSTNAME}/${OCI_REGISTRY_PROJECT_IMAGES}/${OPERATOR_NAME}:${VERSION}");\
IMAGE_NAME=$$(docker inspect --format='{{.Config.Labels.name}}' "${OCI_REGISTRY_HOSTNAME}/${OCI_REGISTRY_PROJECT_IMAGES}/${OPERATOR_NAME}:${VERSION}");\
IMAGE_DESCRIPTION=$$(docker inspect --format='{{.Config.Labels.description}}' "${OCI_REGISTRY_HOSTNAME}/${OCI_REGISTRY_PROJECT_IMAGES}/${OPERATOR_NAME}:${VERSION}-${ARCH}");\
IMAGE_NAME=$$(docker inspect --format='{{.Config.Labels.name}}' "${OCI_REGISTRY_HOSTNAME}/${OCI_REGISTRY_PROJECT_IMAGES}/${OPERATOR_NAME}:${VERSION}-${ARCH}");\
# Merge the SBOM with the metadata for the operator\
jq -s '{"metadata":{"component":{"description":"'"$$IMAGE_NAME. $$IMAGE_DESCRIPTION"'","supplier":{"name":"Stackable GmbH","url":["https://stackable.tech/"]},"author":"Stackable GmbH","purl":"'"$$PURL"'","publisher":"Stackable GmbH"}}} * .[0]' sbom.json > sbom.merged.json;\
# Attest the SBOM to the image\
cosign attest -y --predicate sbom.merged.json --type cyclonedx "${OCI_REGISTRY_HOSTNAME}/${OCI_REGISTRY_PROJECT_IMAGES}/${OPERATOR_NAME}@$$REPO_DIGEST_OF_IMAGE"

# This assumes "${DOCKER_REPO}/${ORGANIZATION}/${OPERATOR_NAME}:${VERSION}-amd64 and "${DOCKER_REPO}/${ORGANIZATION}/${OPERATOR_NAME}:${VERSION}-arm64 are build and pushed
docker-manifest-list-build:
docker manifest create "${DOCKER_REPO}/${ORGANIZATION}/${OPERATOR_NAME}:${VERSION}" --amend "${DOCKER_REPO}/${ORGANIZATION}/${OPERATOR_NAME}:${VERSION}-amd64" --amend "${DOCKER_REPO}/${ORGANIZATION}/${OPERATOR_NAME}:${VERSION}-arm64"
docker manifest create "${OCI_REGISTRY_HOSTNAME}/${OCI_REGISTRY_PROJECT_IMAGES}/${OPERATOR_NAME}:${VERSION}" --amend "${OCI_REGISTRY_HOSTNAME}/${OCI_REGISTRY_PROJECT_IMAGES}/${OPERATOR_NAME}:${VERSION}-amd64" --amend "${OCI_REGISTRY_HOSTNAME}/${OCI_REGISTRY_PROJECT_IMAGES}/${OPERATOR_NAME}:${VERSION}-arm64"

docker-manifest-list-publish:
# Push to Nexus
echo "${NEXUS_PASSWORD}" | docker login --username github --password-stdin "${DOCKER_REPO}"
# `docker manifest push` directly returns the digest of the manifest list
# As it is an experimental feature, this might change in the future
# Further reading: https://docs.docker.com/reference/cli/docker/manifest/push/
DIGEST_NEXUS=$$(docker manifest push "${DOCKER_REPO}/${ORGANIZATION}/${OPERATOR_NAME}:${VERSION}");\
# Refer to image via its digest (oci.stackable.tech/sdp/airflow@sha256:0a1b2c...)\
# This generates a signature and publishes it to the registry, next to the image\
# Uses the keyless signing flow with Github Actions as identity provider\
cosign sign -y "${DOCKER_REPO}/${ORGANIZATION}/${OPERATOR_NAME}:${VERSION}@$$DIGEST_NEXUS"

# Push to Harbor
# We need to use "value" here to prevent the variable from being recursively expanded by make (username contains a dollar sign, since it's a Harbor bot)
docker login --username '${value OCI_REGISTRY_SDP_USERNAME}' --password '${OCI_REGISTRY_SDP_PASSWORD}' '${OCI_REGISTRY_HOSTNAME}'
DIGEST_HARBOR=$$(docker manifest push "${OCI_REGISTRY_HOSTNAME}/${OCI_REGISTRY_PROJECT_IMAGES}/${OPERATOR_NAME}:${VERSION}");\
# Refer to image via its digest (oci.stackable.tech/sdp/airflow@sha256:0a1b2c...);\
# This generates a signature and publishes it to the registry, next to the image\
# Uses the keyless signing flow with Github Actions as identity provider\
cosign sign -y "${OCI_REGISTRY_HOSTNAME}/${OCI_REGISTRY_PROJECT_IMAGES}/${OPERATOR_NAME}:${VERSION}@$$DIGEST_HARBOR"

# TODO remove if not used/needed
docker: docker-build docker-publish

Expand Down