Skip to content

Add Helm hook to upgrade CRDs #2371

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
151 changes: 137 additions & 14 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ concurrency:
env:
SEMVER_PATTERN: '^v([0-9]+)\.([0-9]+)\.([0-9]+)(-rc\.([0-9]+))?$'
IMAGE_REGISTRY: ghcr.io
IMAGE_REPOSITORY: kubeflow/spark-operator/controller
OPERATOR_IMAGE_REPOSITORY: ${{ github.repository }}/controller
KUBECTL_IMAGE_REPOSITORY: ${{ github.repository }}/kubectl

jobs:
check-release:
Expand Down Expand Up @@ -65,7 +66,7 @@ jobs:
echo "Tag '${VERSION}' does not exist."
fi

build_images:
build_operator_images:
needs:
- check-release

Expand Down Expand Up @@ -96,7 +97,7 @@ jobs:
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.IMAGE_REGISTRY }}/${{ env.IMAGE_REPOSITORY }}
images: ${{ env.IMAGE_REGISTRY }}/${{ env.OPERATOR_IMAGE_REPOSITORY }}
tags: |
type=semver,pattern={{version}},value=${{ env.VERSION }}

Expand All @@ -119,7 +120,7 @@ jobs:
with:
platforms: ${{ matrix.platform }}
labels: ${{ steps.meta.outputs.labels }}
outputs: type=image,name=${{ env.IMAGE_REGISTRY }}/${{ env.IMAGE_REPOSITORY }},push-by-digest=true,name-canonical=true,push=true
outputs: type=image,name=${{ env.IMAGE_REGISTRY }}/${{ env.OPERATOR_IMAGE_REPOSITORY }},push-by-digest=true,name-canonical=true,push=true

- name: Export digest
run: |
Expand All @@ -130,14 +131,135 @@ jobs:
- name: Upload digest
uses: actions/upload-artifact@v4
with:
name: digests-${{ env.PLATFORM_PAIR }}
name: digests-operator-${{ env.PLATFORM_PAIR }}
path: /tmp/digests/*
if-no-files-found: error
retention-days: 1

release_images:
build_kubectl_images:
needs:
- build_images
- check-release

runs-on: ubuntu-latest

strategy:
fail-fast: false
matrix:
platform:
- linux/amd64
- linux/arm64

steps:
- name: Prepare
run: |
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV

- name: Checkout source code
uses: actions/checkout@v4

- name: Read version from VERSION file
run: |
VERSION=$(cat VERSION)
echo "VERSION=${VERSION}" >> $GITHUB_ENV

- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.IMAGE_REGISTRY }}/${{ env.KUBECTL_IMAGE_REPOSITORY }}
tags: |
type=semver,pattern={{version}},value=${{ env.VERSION }}

- name: Set up QEMU
uses: docker/setup-qemu-action@v3

- name: Set up Docker buildx
uses: docker/setup-buildx-action@v3

- name: Login to container registry
uses: docker/login-action@v3
with:
registry: ${{ env.IMAGE_REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build and push by digest
id: build
uses: docker/build-push-action@v6
with:
file: docker/Dockerfile.kubectl
platforms: ${{ matrix.platform }}
labels: ${{ steps.meta.outputs.labels }}
outputs: type=image,name=${{ env.IMAGE_REGISTRY }}/${{ env.KUBECTL_IMAGE_REPOSITORY }},push-by-digest=true,name-canonical=true,push=true

- name: Export digest
run: |
mkdir -p /tmp/digests
digest="${{ steps.build.outputs.digest }}"
touch "/tmp/digests/${digest#sha256:}"

- name: Upload digest
uses: actions/upload-artifact@v4
with:
name: digests-kubectl-${{ env.PLATFORM_PAIR }}
path: /tmp/digests/*
if-no-files-found: error
retention-days: 1

release_operator_images:
needs:
- build_operator_images

runs-on: ubuntu-latest

steps:
- name: Checkout source code
uses: actions/checkout@v4

- name: Read version from VERSION file
run: |
VERSION=$(cat VERSION)
echo "VERSION=${VERSION}" >> $GITHUB_ENV

- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.IMAGE_REGISTRY }}/${{ env.OPERATOR_IMAGE_REPOSITORY }}
tags: |
type=semver,pattern={{version}},value=${{ env.VERSION }}

- name: Download digests
uses: actions/download-artifact@v4
with:
path: /tmp/digests
pattern: digests-operator-*
merge-multiple: true

- name: Set up Docker buildx
uses: docker/setup-buildx-action@v3

- name: Login to container registry
uses: docker/login-action@v3
with:
registry: ${{ env.IMAGE_REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Create manifest list and push
working-directory: /tmp/digests
run: |
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf '${{ env.IMAGE_REGISTRY }}/${{ env.OPERATOR_IMAGE_REPOSITORY }}@sha256:%s ' *)

- name: Inspect image
run: |
docker buildx imagetools inspect ${{ env.IMAGE_REGISTRY }}/${{ env.OPERATOR_IMAGE_REPOSITORY }}:${{ steps.meta.outputs.version }}

release_kubectl_images:
needs:
- build_kubectl_images

runs-on: ubuntu-latest

Expand All @@ -154,15 +276,15 @@ jobs:
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.IMAGE_REGISTRY }}/${{ env.IMAGE_REPOSITORY }}
images: ${{ env.IMAGE_REGISTRY }}/${{ env.KUBECTL_IMAGE_REPOSITORY }}
tags: |
type=semver,pattern={{version}},value=${{ env.VERSION }}

- name: Download digests
uses: actions/download-artifact@v4
with:
path: /tmp/digests
pattern: digests-*
pattern: digests-kubectl-*
merge-multiple: true

- name: Set up Docker buildx
Expand All @@ -179,15 +301,16 @@ jobs:
working-directory: /tmp/digests
run: |
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf '${{ env.IMAGE_REGISTRY }}/${{ env.IMAGE_REPOSITORY }}@sha256:%s ' *)
$(printf '${{ env.IMAGE_REGISTRY }}/${{ env.KUBECTL_IMAGE_REPOSITORY }}@sha256:%s ' *)

- name: Inspect image
run: |
docker buildx imagetools inspect ${{ env.IMAGE_REGISTRY }}/${{ env.IMAGE_REPOSITORY }}:${{ steps.meta.outputs.version }}
docker buildx imagetools inspect ${{ env.IMAGE_REGISTRY }}/${{ env.KUBECTL_IMAGE_REPOSITORY }}:${{ steps.meta.outputs.version }}

push_tag:
needs:
- release_images
- release_operator_images
- release_kubectl_images

runs-on: ubuntu-latest

Expand All @@ -209,7 +332,7 @@ jobs:

- name: Create and push tag
run: |
git tag -a "${VERSION}" -m "Spark Operator Official Release ${VERSION}"
git tag -a "${VERSION}" -m "Official Release ${VERSION}"
git push origin "${VERSION}"

draft_release:
Expand Down Expand Up @@ -251,7 +374,7 @@ jobs:
uses: softprops/action-gh-release@v2
with:
token: ${{ secrets.GITHUB_TOKEN }}
name: "Spark Operator ${{ env.VERSION }}"
name: ${{ env.VERSION }}
tag_name: ${{ env.VERSION }}
prerelease: ${{ contains(env.VERSION, 'rc') }}
target_commitish: ${{ github.sha }}
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ override LDFLAGS += \
.PHONY: build-operator
build-operator: ## Build Spark operator.
echo "Building spark-operator binary..."
go build -o $(SPARK_OPERATOR) -ldflags '${LDFLAGS}' cmd/operator/main.go
CGO_ENABLED=0 go build -o $(SPARK_OPERATOR) -ldflags '${LDFLAGS}' cmd/operator/main.go

.PHONY: clean
clean: ## Clean binaries.
Expand Down
4 changes: 4 additions & 0 deletions charts/spark-operator-chart/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ See [helm uninstall](https://helm.sh/docs/helm/helm_uninstall) for command docum
| image.tag | string | If not set, the chart appVersion will be used. | Image tag. |
| image.pullPolicy | string | `"IfNotPresent"` | Image pull policy. |
| image.pullSecrets | list | `[]` | Image pull secrets for private image registry. |
| hook.upgradeCrd | bool | `false` | Whether to create a Helm pre-install/pre-upgrade hook Job to update CRDs. |
| hook.image.registry | string | `"ghcr.io"` | Image registry. |
| hook.image.repository | string | `"kubeflow/spark-operator/kubectl"` | Image repository. |
| hook.image.tag | string | If not set, the chart appVersion will be used. | Image tag. |
| controller.replicas | int | `1` | Number of replicas of controller. |
| controller.leaderElection.enable | bool | `true` | Specifies whether to enable leader election for controller. |
| controller.workers | int | `10` | Reconcile concurrency, higher values might increase memory usage. |
Expand Down
56 changes: 56 additions & 0 deletions charts/spark-operator-chart/templates/hook/_helpers.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
{{- /*
Copyright 2025 The Kubeflow authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/ -}}

{{- /* Create the name of Helm hook */ -}}
{{- define "spark-operator.hook.name" -}}
{{- include "spark-operator.fullname" . }}-hook
{{- end -}}

{{- /* Common labels for the Helm hook */ -}}
{{- define "spark-operator.hook.labels" -}}
{{ include "spark-operator.labels" . }}
app.kubernetes.io/component: hook
{{- end -}}

{{- /* Selector labels for the Helm hook */ -}}
{{- define "spark-operator.hook.selectorLabels" -}}
{{ include "spark-operator.hook.labels" . }}
{{- end -}}

{{- /* Create the name of the service account to be used by the Helm hooks. */ -}}
{{- define "spark-operator.hook.serviceAccount.name" -}}
{{ include "spark-operator.hook.name" . }}
{{- end -}}

{{- /* Create the name of the cluster role to be used by the Helm hooks. */ -}}
{{- define "spark-operator.hook.clusterRole.name" -}}
{{ include "spark-operator.hook.name" . }}
{{- end -}}

{{- /* Create the name of the cluster role binding to be used by the Helm hooks. */ -}}
{{- define "spark-operator.hook.clusterRoleBinding.name" -}}
{{ include "spark-operator.hook.clusterRole.name" . }}
{{- end -}}

{{- /* Create the name of the Helm hook job. */ -}}
{{- define "spark-operator.hook.job.name" -}}
{{ include "spark-operator.hook.name" . }}
{{- end -}}

{{- /* Create the name of the Helm hook job. */ -}}
{{- define "spark-operator.hook.image" -}}
{{ printf "%s/%s:%s" .Values.hook.image.registry .Values.hook.image.repository (.Values.hook.image.tag | default .Chart.AppVersion | toString) }}
{{- end -}}
40 changes: 40 additions & 0 deletions charts/spark-operator-chart/templates/hook/cluster_role.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{{- /*
Copyright 2025 The Kubeflow authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/ -}}

{{- if .Values.hook.upgradeCrd -}}
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: {{ include "spark-operator.hook.clusterRole.name" . }}
namespace: {{ .Release.Namespace }}
labels:
{{- include "spark-operator.hook.labels" . | nindent 4 }}
annotations:
helm.sh/hook: pre-install,pre-upgrade
helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded,hook-failed
helm.sh/hook-weight: "2"
rules:
- apiGroups:
- apiextensions.k8s.io
resources:
- customresourcedefinitions
resourceNames:
- sparkapplications.sparkoperator.k8s.io
- scheduledsparkapplications.sparkoperator.k8s.io
verbs:
- get
- patch
{{- end }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{{- /*
Copyright 2025 The Kubeflow authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/ -}}

{{- if .Values.hook.upgradeCrd -}}
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: {{ include "spark-operator.hook.clusterRoleBinding.name" . }}
namespace: {{ .Release.Namespace }}
labels:
{{- include "spark-operator.hook.labels" . | nindent 4 }}
annotations:
helm.sh/hook: pre-install,pre-upgrade
helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded,hook-failed
helm.sh/hook-weight: "3"
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: {{ include "spark-operator.hook.clusterRole.name" . }}
subjects:
- kind: ServiceAccount
name: {{ include "spark-operator.hook.serviceAccount.name" . }}
namespace: {{ .Release.Namespace }}
{{- end }}
Loading