Skip to content
Draft
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
94 changes: 78 additions & 16 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,57 @@ on:
type: boolean

jobs:
build:
tags:
runs-on: ubuntu-24.04
outputs:
# version is the immutable release/build tag; the controller image is always pinned to it.
version: ${{ steps.tags.outputs.version }}
# extra-tags are additional tags (e.g. "latest") that point at the same content as version.
# Both image jobs build from version + extra-tags, so the operator image and the manifests
# artifact stay in lockstep.
extra-tags: ${{ steps.tags.outputs.extra-tags }}
steps:
- name: Checkout
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
# NOTE: We fetch depth so that we can put the right `GIT` reference
fetch-depth: 0
ref: ${{ github.ref }}
- name: Compute tags
id: tags
# If `is-development` then suffix the version with `-dev`
# If `is-latest` then also add a `latest` tag
# If not `is-stable` then suffix `-dev` to `latest`
run: |
version="$(git describe --tags --always --dirty --match='v[0-9]*')${{ inputs.is-development && '-dev' || '' }}"
extra=""
if [ "${{ inputs.is-latest }}" = "true" ]; then
extra="latest${{ ! inputs.is-stable && '-dev' || '' }}"
fi
echo "version=${version}" >> "$GITHUB_OUTPUT"
echo "extra-tags=${extra}" >> "$GITHUB_OUTPUT"

operator-image:
needs: tags
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
fetch-depth: 0
ref: ${{ github.ref }}
- name: Compute image refs
id: refs
env:
VERSION: ${{ needs.tags.outputs.version }}
EXTRA_TAGS: ${{ needs.tags.outputs.extra-tags }}
run: |
image="ghcr.io/${{ github.repository }}"
refs="${image}:${VERSION}"
for tag in $EXTRA_TAGS; do
refs="${refs},${image}:${tag}"
done
echo "refs=${refs}" >> "$GITHUB_OUTPUT"
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0
- name: Login to the registry
Expand All @@ -37,26 +79,46 @@ jobs:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Compute tags
id: tags
# If `is-development` then suffix tag with `-dev`
# If `is-latest` then add `latest` tag
# If not `is-stable` then suffix `-dev` to `latest
run: |
version="$(git describe --tags --always --dirty --match='v[0-9]*')${{ inputs.is-development && '-dev' || '' }}"
tags="ghcr.io/${{ github.repository }}:${version}"
if [ "${{ inputs.is-latest }}" = "true" ]; then
tags="$tags,ghcr.io/${{ github.repository }}:latest${{ ! inputs.is-stable && '-dev' || '' }}"
fi
echo "tags=$tags" >> $GITHUB_OUTPUT
echo "version=$version" >> $GITHUB_OUTPUT
- name: Build image
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0
with:
context: .
build-args:
VERSION=${{ steps.tags.outputs.version }}
VERSION=${{ needs.tags.outputs.version }}
push: true
tags: ${{ steps.tags.outputs.tags }}
tags: ${{ steps.refs.outputs.refs }}
cache-from: type=gha,scope=crl-operator
cache-to: type=gha,mode=max,scope=crl-operator

manifests-image:
needs: tags
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
ref: ${{ github.ref }}
- name: Set up Go
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version-file: go.mod
- name: Login to the registry
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
# Publishes the config/ tree as an OCI artifact (ghcr.io/<repo>-manifests), pinned to the
# versioned operator image. Extra tags (e.g. latest) point at the same artifact, so they keep
# pinning that version rather than a floating image tag. flux reads the credentials written
# by docker/login-action.
- name: Push manifests OCI artifact
env:
VERSION: ${{ needs.tags.outputs.version }}
EXTRA_TAGS: ${{ needs.tags.outputs.extra-tags }}
run: |
make push-manifests \
IMG=ghcr.io/${{ github.repository }}:${VERSION} \
MANIFESTS_IMG=ghcr.io/${{ github.repository }}-manifests \
VERSION="${VERSION}" \
MANIFESTS_EXTRA_TAGS="${EXTRA_TAGS}"
48 changes: 47 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,10 @@ endif
# This is useful for CI or a project to utilize a specific version of the operator-sdk toolkit.
# renovate: datasource=github-releases depName=operator-framework/operator-sdk
OPERATOR_SDK_VERSION ?= v1.41.1
# REGISTRY is the registry and namespace for the operator's published images and artifacts.
REGISTRY ?= ghcr.io/scality
# Image URL to use all building/pushing image targets
IMG ?= controller:latest
IMG ?= $(REGISTRY)/crl-operator:$(VERSION)

# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
ifeq (,$(shell go env GOBIN))
Expand Down Expand Up @@ -377,3 +379,47 @@ catalog-build: opm ## Build a catalog image.
.PHONY: catalog-push
catalog-push: ## Push a catalog image.
$(MAKE) docker-push IMG=$(CATALOG_IMG)

##@ Flux OCI manifests
# Everything below publishes the operator's config/ tree as an OCI artifact that Flux can
# consume directly (OCIRepository + Kustomization). It is intentionally kept separate from the
# operator-sdk / kubebuilder scaffolding above.

# MANIFESTS_IMG is the OCI artifact repository (no tag) for the config/ bundle.
MANIFESTS_IMG ?= $(REGISTRY)/crl-operator-manifests
# MANIFESTS_EXTRA_TAGS are extra tags to also point at the published artifact (e.g. "latest"),
# space-separated. They reference the SAME artifact, so - like VERSION - they pin the controller
# image at IMG (a specific version), never a floating tag: a `latest` manifests bundle must keep
# pinning the controller version it was built for, otherwise it would break on the next release.
MANIFESTS_EXTRA_TAGS ?=

FLUX ?= $(LOCALBIN)/flux
# renovate: datasource=github-releases depName=fluxcd/flux2
FLUX_VERSION ?= v2.8.8

.PHONY: flux
flux: ## Download flux CLI locally if necessary.
ifeq (,$(wildcard $(FLUX)))
ifeq (,$(shell which flux 2>/dev/null))
@{ \
set -e ;\
mkdir -p $(dir $(FLUX)) ;\
OS=$(shell go env GOOS) && ARCH=$(shell go env GOARCH) && \
curl -sSL https://github.com/fluxcd/flux2/releases/download/$(FLUX_VERSION)/flux_$(patsubst v%,%,$(FLUX_VERSION))_$${OS}_$${ARCH}.tar.gz | tar -xzf - -C $(LOCALBIN) flux ;\
chmod +x $(FLUX) ;\
}
else
FLUX = $(shell which flux)
endif
endif

.PHONY: push-manifests
push-manifests: kustomize flux ## Publish config/ as an OCI artifact for Flux, pinned to IMG (a specific version).
cd config/manager && $(KUSTOMIZE) edit set image controller=$(IMG)
$(FLUX) push artifact oci://$(MANIFESTS_IMG):$(VERSION) \
--path=./config \
--source="$(shell git config --get remote.origin.url)" \
--revision="$(VERSION)@sha1:$(shell git rev-parse HEAD)"
for tag in $(MANIFESTS_EXTRA_TAGS); do \
$(FLUX) tag artifact oci://$(MANIFESTS_IMG):$(VERSION) --tag $$tag ; \
done
39 changes: 39 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,45 @@ make uninstall
make undeploy
```

### OCI manifests artifact

Each build also publishes the `config/` tree as an OCI artifact
(`ghcr.io/scality/crl-operator-manifests:<version>`), pinned to the matching
controller image, so Flux can deploy crl-operator straight from it:

```yaml
apiVersion: source.toolkit.fluxcd.io/v1
kind: OCIRepository
metadata:
name: crl-operator
namespace: flux-system
spec:
interval: 1h
url: oci://ghcr.io/scality/crl-operator-manifests
ref:
tag: latest
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: crl-operator
namespace: flux-system
spec:
interval: 1h
sourceRef:
kind: OCIRepository
name: crl-operator
path: ./default
prune: true
wait: true
```

To publish the artifact manually (e.g. from a branch build):

```sh
make push-manifests VERSION=<version>
```

## Contributing

See [contributing](CONTRIBUTING.md) for details.
Expand Down