Skip to content
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

Migrate the cron container from sidecar to K8s CronJob #703

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
2 changes: 1 addition & 1 deletion charts/nextcloud/Chart.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
apiVersion: v2
name: nextcloud
version: 6.6.6
version: 6.6.7
# renovate: image=docker.io/library/nextcloud
appVersion: 30.0.6
description: A file sharing server that puts the control and security of your own data back into your hands.
Expand Down
233 changes: 117 additions & 116 deletions charts/nextcloud/README.md

Large diffs are not rendered by default.

196 changes: 196 additions & 0 deletions charts/nextcloud/templates/_helpers.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -398,3 +398,199 @@ Create volume mounts for the nextcloud container as well as the cron sidecar con
subPath: {{ $key }}
{{- end }}
{{- end -}}


{{/*
Create volumes for the nextcloud deployment as well as the cronjob.
*/}}
{{- define "nextcloud.volumes" -}}
volumes:
- name: nextcloud-main
{{- if .Values.persistence.enabled }}
persistentVolumeClaim:
claimName: {{ if .Values.persistence.existingClaim }}{{ .Values.persistence.existingClaim }}{{- else }}{{ include "nextcloud.fullname" . }}-nextcloud{{- end }}
{{- else }}
emptyDir: {}
{{- end }}
{{- if and .Values.persistence.nextcloudData.enabled .Values.persistence.enabled }}
- name: nextcloud-data
persistentVolumeClaim:
claimName: {{ if .Values.persistence.nextcloudData.existingClaim }}{{ .Values.persistence.nextcloudData.existingClaim }}{{- else }}{{ include "nextcloud.fullname" . }}-nextcloud-data{{- end }}
{{- end }}
{{- if .Values.nextcloud.configs }}
- name: nextcloud-config
configMap:
name: {{ include "nextcloud.fullname" . }}-config
{{- end }}
{{- if .Values.nextcloud.phpConfigs }}
- name: nextcloud-phpconfig
configMap:
name: {{ include "nextcloud.fullname" . }}-phpconfig
{{- end }}
{{- if .Values.nginx.enabled }}
- name: nextcloud-nginx-config
configMap:
name: {{ include "nextcloud.fullname" . }}-nginxconfig
{{- end }}
{{- if not (values .Values.nextcloud.hooks | compact | empty) }}
- name: nextcloud-hooks
configMap:
name: {{ include "nextcloud.fullname" . }}-hooks
defaultMode: 0o755
{{- end }}
{{- with .Values.nextcloud.extraVolumes }}
{{- toYaml . | nindent 2 }}
{{- end }}
{{- end -}}


{{/*
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The following is more common in helm-charts.
Where you have to add app.kubernetes.io/component: app manuelle.

{{/*
Common labels
*/}}
{{- define "nextcloud.labels" -}}
helm.sh/chart: {{ include "nextcloud.chart" . }}
{{ include "nextcloud.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}

{{/*
Selector labels
*/}}
{{- define "nextcloud.selectorLabels" -}}
app.kubernetes.io/name: {{ include "headscale.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}

PS: Maybe you should move such changes into smaller PRs for easiert review (and merge)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wrenix
Thanks for your comment.

To make the review easier I used a commit for every step of the refactoring over smaller PRs as it makes only sense to me if get everything merged in. In commit a874bc4 you can see that I simply moved the labels as they were from the deployment.yamltohelpers.tpl`. So I guess someone had good reasoning to define the labels like this.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you must differentiate the labels used by the deployment to select its pod vs the labels on the cronjob pods, otherwise cronjob pods would show up as pods of a deployment and might get controlled by the replicaset controller, right? So app in app.kubernetes.io/component: app should probably be cronjob for cronjob pods or so.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pschichtel Good that you noticed this! Thank you.

Copy link
Collaborator

@wrenix wrenix Mar 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MartinKirchner as a Co-Maintainer i could easier merge such single changes / small PRs.
For the change from sidecar to cronjob itself, i believe we need a longer discussion, see #683

PS: i like to have an _helper for the labels and that could be in this week if i got a easy to review.

Create match labels for the nextcloud container as well as the cronjob container.
Parameters:
- component: app or cronjob
- rootContext: $ (Inside a template the scope changes, i.e. you cannot access variables of the parent context or its parents.
Unfortunately this is also the case for the root context, this means .Values, .Release, .Chart cannot be accessed.
However the other templates need values from the objects. That's why the caller has to pass on reference to the root context which this template in turn passes on.)
*/}}
{{- define "nextcloud.pods.matchlabels" -}}
app.kubernetes.io/name: {{ include "nextcloud.name" .rootContext }}
app.kubernetes.io/instance: {{ .rootContext.Release.Name }}
app.kubernetes.io/component: {{ .component }}
{{- end -}}

{{/*
Create match labels for the nextcloud deployment as well as the cronjob.
Parameters:
- component: app or cronjob
- rootContext: $ (Inside a template the scope changes, i.e. you cannot access variables of the parent context or its parents.
Unfortunately this is also the case for the root context, this means .Values, .Release, .Chart cannot be accessed.
However the other templates need values from the objects. That's why the caller has to pass on reference to the root context which this template in turn passes on.)
*/}}
{{- define "nextcloud.pods.labels" -}}
{{ include "nextcloud.pods.matchlabels" ( dict "component" .component "rootContext" .rootContext) }}
helm.sh/chart: {{ include "nextcloud.chart" .rootContext }}
app.kubernetes.io/managed-by: {{ .rootContext.Release.Service }}
{{- end -}}

{{/*
Create metadata for the nextcloud deployment template as well as the cronjob template.
- component: app or cronjob
- rootContext: $ (Inside a template the scope changes, i.e. you cannot access variables of the parent context or its parents.
Unfortunately this is also the case for the root context, this means .Values, .Release, .Chart cannot be accessed.
However the other templates need values from the objects. That's why the caller has to pass on reference to the root context which this template in turn passes on.)
*/}}
{{- define "nextcloud.deployment.template.metadata" -}}
metadata:
labels:
{{- include "nextcloud.pods.matchlabels" ( dict "component" .component "rootContext" .rootContext) | nindent 4 }}
{{- if .rootContext.Values.redis.enabled }}
{{ include "nextcloud.redis.fullname" .rootContext }}-client: "true"
{{- end }}
{{- with .rootContext.Values.podLabels }}
{{- toYaml . | nindent 4 }}
{{- end }}
annotations:
nextcloud-config-hash: {{ print (toJson .rootContext.Values.nextcloud.defaultConfigs) "-" (toJson .rootContext.Values.nextcloud.configs) | sha256sum }}
php-config-hash: {{ toJson .rootContext.Values.nextcloud.phpConfigs | sha256sum }}
{{- if .rootContext.Values.nginx.enabled }}
nginx-config-hash: {{ print .rootContext.Values.nginx.config.default "-" .rootContext.Values.nginx.config.custom | sha256sum }}
{{- end }}
hooks-hash: {{ toYaml .rootContext.Values.nextcloud.hooks | sha256sum }}
{{- with .rootContext.Values.podAnnotations }}
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end -}}

{{/*
Create common pod definitions for nextcloud deployment and cronjob.
*/}}
{{- define "nextcloud.pod.commons" -}}
{{- with .Values.image.pullSecrets }}
imagePullSecrets:
{{- range . }}
- name: {{ . }}
{{- end}}
{{- end }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 2 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 2 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 2 }}
{{- end }}
{{ include "nextcloud.volumes" . }}
# Actually it does not make much sense to define securityContext and podSecurityContext on a pod with only one container
# except for backward compatibility when the cronjob was a sidecar container.
securityContext:
{{- with .Values.securityContext }}
{{- toYaml . | nindent 2 }}
{{- end }}
{{- with .Values.nextcloud.podSecurityContext }}
{{- toYaml . | nindent 2 }}
{{- else }}
{{- if .Values.nginx.enabled }}
# Will mount configuration files as www-data (id: 82) for nextcloud
fsGroup: 82
{{- else }}
# Will mount configuration files as www-data (id: 33) for nextcloud
fsGroup: 33
{{- end }}
{{- end }}{{/* end-with podSecurityContext */}}
{{- if .Values.rbac.enabled }}
serviceAccountName: {{ .Values.rbac.serviceaccount.name }}
{{- end }}
{{- with .Values.dnsConfig }}
dnsConfig:
{{- toYaml . | nindent 2 }}
{{- end }}
{{- end -}}


{{/*
Create nextcloud container definition for deployment and cronjob.
Pass these parameters in the dict:
- containerName: name of the container
- context: Pointer to the context in the values.yaml where "resources, lifecycle, securityContext" can be found
- rootContext: $ (Inside a template the scope changes, i.e. you cannot access variables of the parent context or its parents.
Unfortunately this is also the case for the root context, this means .Values, .Release, .Chart cannot be accessed.
However the other templates need values from the objects. That's why the caller has to pass on reference to the root context which this template in turn passes on.)
*/}}
{{- define "nextcloud.container" -}}
- name: {{ .containerName }}
image: {{ include "nextcloud.image" .rootContext }}
imagePullPolicy: {{ .rootContext.Values.image.pullPolicy }}
{{- if .context.command }}
command:
{{- toYaml .context.command | nindent 4 }}
{{- end }}
{{- with .context.lifecycle }}
lifecycle:
{{- with .postStartCommand }}
postStart:
exec:
command:
{{- toYaml . | nindent 10 }}
{{- end }}
{{- with .preStopCommand }}
preStop:
exec:
command:
{{- toYaml . | nindent 10 }}
{{- end }}
{{- end }}
env:
{{- include "nextcloud.env" .rootContext | nindent 4 }}
resources:
{{- toYaml .context.resources | nindent 4 }}
{{- with .context.securityContext }}
securityContext:
{{- toYaml . | nindent 4 }}
{{- end }}
volumeMounts:
{{- include "nextcloud.volumeMounts" .rootContext | trim | nindent 4 }}
{{- end -}}
25 changes: 25 additions & 0 deletions charts/nextcloud/templates/cronjob.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
{{- if .Values.cronjob.enabled }}

apiVersion: batch/v1
kind: CronJob
metadata:
name: {{ template "nextcloud.fullname" . }}-cron
labels:
{{- include "nextcloud.pods.labels" ( dict "component" "cronjob" "rootContext" $ ) | nindent 4 }}
spec:
schedule: "*/5 * * * *"
concurrencyPolicy: Forbid
failedJobsHistoryLimit: 5
jobTemplate:
{{- include "nextcloud.deployment.template.metadata" ( dict "component" "cronjob" "rootContext" $ ) | nindent 4 }}
spec:
template:
{{- include "nextcloud.deployment.template.metadata" ( dict "component" "cronjob" "rootContext" $ ) | nindent 8 }}
spec:
containers:
{{- $containerName := printf "%s-cron" .Chart.Name }}
{{- include "nextcloud.container" ( dict "containerName" $containerName "rootContext" $ "context" .Values.cronjob ) | nindent 10 }}
{{- include "nextcloud.pod.commons" . | nindent 10 }}
restartPolicy: OnFailure
{{- end }}{{/* end-if cronjob.enabled */}}
Loading