diff --git a/charts/otomi-db/templates/backup.yaml b/charts/otomi-db/templates/backup.yaml index c7734ca769..2f678474f0 100644 --- a/charts/otomi-db/templates/backup.yaml +++ b/charts/otomi-db/templates/backup.yaml @@ -11,7 +11,7 @@ spec: suspend: {{ .Values.backup.suspend }} immediate: {{ .Values.backup.immediate }} target: {{ .Values.backup.target }} - schedule: {{ .Values.backup.schedule }} + schedule: {{ .Values.backup.schedule | quote }} backupOwnerReference: {{ .Values.backup.backupOwnerReference }} cluster: name: {{ .Values.name }} diff --git a/charts/team-ns/templates/backup/schedule.yaml b/charts/team-ns/templates/backup/schedule.yaml index c6be32cccb..8df20ec168 100644 --- a/charts/team-ns/templates/backup/schedule.yaml +++ b/charts/team-ns/templates/backup/schedule.yaml @@ -9,7 +9,7 @@ metadata: name: team-{{ $v.teamId }}-backup-{{ .name }} namespace: velero spec: - schedule: {{ .schedule }} + schedule: {{ .schedule | quote }} template: includedNamespaces: - team-{{ $v.teamId }} diff --git a/helmfile.d/snippets/defaults.yaml b/helmfile.d/snippets/defaults.yaml index a41d1f6bc0..174c032ebb 100644 --- a/helmfile.d/snippets/defaults.yaml +++ b/helmfile.d/snippets/defaults.yaml @@ -1078,6 +1078,8 @@ environments: enabled: false keycloak: enabled: false + gitea: + enabled: false cluster: provider: linode name: apl diff --git a/tests/fixtures/env/settings.yaml b/tests/fixtures/env/settings.yaml index b56ca4ad91..46b4b61ae6 100644 --- a/tests/fixtures/env/settings.yaml +++ b/tests/fixtures/env/settings.yaml @@ -52,6 +52,7 @@ obj: loki: my-clusterid-loki tempo: my-clusterid-tempo velero: my-clusterid-velero + gitea: my-clusterid-gitea type: linode oidc: adminGroupID: someAdminGroupID @@ -85,6 +86,10 @@ platformBackups: enabled: true retentionPolicy: 7d schedule: 0 0 0 * * * + gitea: + enabled: true + retentionPolicy: 7d + schedule: 0 0 0 * * * smtp: auth_username: no-reply@doma.in from: no-reply@doma.in diff --git a/values-schema.yaml b/values-schema.yaml index 317f859a03..f670888437 100644 --- a/values-schema.yaml +++ b/values-schema.yaml @@ -2987,6 +2987,22 @@ properties: description: Linode API Token $ref: '#/definitions/wordCharacterPattern' x-secret: '' + gitea: + type: object + title: Gitea + description: Enable application-level backup of Gitea repositories and database + additionalProperties: false + properties: + enabled: + type: boolean + default: false + resources: + $ref: '#/definitions/resources' + retentionPolicy: + $ref: '#/definitions/backupRetentionPolicy' + schedule: + $ref: '#/definitions/backupSchedule' + obj: properties: provider: @@ -3027,6 +3043,10 @@ properties: type: string $ref: '#/definitions/wordCharacterPattern' default: tempo + gitea: + type: string + $ref: '#/definitions/wordCharacterPattern' + default: gitea required: - region - accessKeyId diff --git a/values/gitea/gitea-otomi-db.gotmpl b/values/gitea/gitea-otomi-db.gotmpl index 15e0cbe3da..afe68c24d7 100644 --- a/values/gitea/gitea-otomi-db.gotmpl +++ b/values/gitea/gitea-otomi-db.gotmpl @@ -14,7 +14,7 @@ instances: {{ $gdb.replicas }} {{- if $b.enabled }} backup: enabled: {{ $b.enabled }} - schedule: {{ $b.schedule }} + schedule: {{ $b.schedule | quote }} retentionPolicy: {{ $b.retentionPolicy }} type: {{ $obj.type }} {{- if eq $obj.type "minioLocal" }} diff --git a/values/gitea/gitea-raw.gotmpl b/values/gitea/gitea-raw.gotmpl index 841110b6b9..f31aa3ab5a 100644 --- a/values/gitea/gitea-raw.gotmpl +++ b/values/gitea/gitea-raw.gotmpl @@ -1,6 +1,7 @@ {{- $v := .Values }} {{- $otomiAdmin := "otomi-admin" }} {{- $obj := $v.obj.provider }} +{{- $giteaBackupConfig := $v.platformBackups.gitea }} resources: {{- if $v._derived.untrustedCA }} @@ -19,6 +20,7 @@ resources: data: username: "{{ "gitea" | b64enc }}" password: "{{ $v.apps.gitea.postgresqlPassword | b64enc }}" +# DB / app backup resources {{- if eq $obj.type "minioLocal" }} - apiVersion: v1 kind: Secret @@ -37,3 +39,104 @@ resources: S3_STORAGE_ACCOUNT: "{{ $obj.linode.accessKeyId | b64enc }}" S3_STORAGE_KEY: "{{ $obj.linode.secretAccessKey | b64enc }}" {{- end }} +# Application backup resources +- apiVersion: v1 + kind: PersistentVolumeClaim + metadata: + name: gitea-backup + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + {{- if eq $v.cluster.provider "vultr" }} + storage: 10Gi + {{- else }} + storage: 1Gi + {{- end }} +{{- if $giteaBackupConfig.enabled }} +- apiVersion: v1 + kind: ServiceAccount + metadata: + name: gitea-backup +- apiVersion: rbac.authorization.k8s.io/v1 + kind: Role + metadata: + name: gitea-backup-operator + rules: + - apiGroups: [""] + resources: ["pods"] + verbs: ["get", "watch", "list"] + - apiGroups: [""] + resources: ["pods/exec"] + verbs: ["create"] +- apiVersion: rbac.authorization.k8s.io/v1 + kind: RoleBinding + metadata: + name: gitea-backup + subjects: + - kind: ServiceAccount + name: gitea-backup + roleRef: + kind: Role + name: gitea-backup-operator + apiGroup: rbac.authorization.k8s.io +- apiVersion: batch/v1 + kind: CronJob + metadata: + name: gitea-backup-job + spec: + schedule: {{ $giteaBackupConfig.schedule | quote }} + concurrencyPolicy: Forbid + jobTemplate: + spec: + template: + metadata: + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: gitea-backup + containers: + - image: bitnami/kubectl:1.30 + name: kubectl + command: + - /bin/sh + - -ec + - >- + kubectl exec gitea-0 -- /bin/sh -ec " + if [ ! -f '/backup/.bin/rclone' ]; then + echo 'Installing RClone...' && + mkdir -p /backup/.bin && + cd /backup/.bin && + curl -fsSL -o rclone.zip https://github.com/rclone/rclone/releases/download/v1.68.0/rclone-v1.68.0-linux-amd64.zip && + echo '2fd93c246c72fa6bb192d33b0447013b31a982f9daaaa1f9c0b85e99f4233ee47c089e8b3f7f994dfe21090dab8e2adaec2e62c68aed0c7dadbac9bcce4e1706 rclone.zip' | sha512sum -c - && + unzip -oj rclone.zip + fi && + cd /backup && + echo 'Creating backup...' && + gitea dump --type tar.bz2 && + echo '5d20f5562609695b565d696980bbee91ec0503ed946410eb2e6024a8b6850ebd5b587d5c71488f471012ea39e6bf440d843840165e8ac75cd0ec737defa2a749 .bin/rclone' | sha512sum -c - && + echo 'Uploading to object storage...' && + .bin/rclone copy --exclude '\.*/**' /backup gitea:/\$BUCKET_NAME && + echo 'Removing old backups from object storage...' && + .bin/rclone sync --min-age $RETENTION_TIME --exclude '\.*/**' /backup gitea:/\$BUCKET_NAME && + echo 'Cleaning up local backups...' && + find . -type f -iname '*.tar.bz2' -ctime +1 -delete" + resources: + limits: + cpu: 250m + memory: 256Mi + requests: + cpu: 100m + memory: 128Mi + env: + - name: RETENTION_TIME + value: {{ $giteaBackupConfig.retentionPolicy }} + securityContext: + runAsNonRoot: true + runAsUser: 65535 + runAsGroup: 65535 + restartPolicy: Never + securityContext: + fsGroup: 65535 +{{- end }} diff --git a/values/gitea/gitea.gotmpl b/values/gitea/gitea.gotmpl index 38af5cdd57..d74ec9f263 100644 --- a/values/gitea/gitea.gotmpl +++ b/values/gitea/gitea.gotmpl @@ -5,6 +5,13 @@ {{- $giteaDomain := printf "gitea.%s" $v.cluster.domainSuffix }} {{- $cm := $v.apps | get "cert-manager" }} {{- $gdb := $v.databases.gitea }} +{{- $obj := $v.obj.provider }} +{{- $giteaBucketName := "" }} +{{- if eq $obj.type "minioLocal" }} +{{- $giteaBucketName = "gitea" }} +{{- else if eq $obj.type "linode" }} +{{- $giteaBucketName = $obj.linode.buckets | get "gitea" nil }} +{{- end }} nameOverride: gitea fullnameOverride: gitea @@ -115,6 +122,44 @@ gitea: init: resources: {{- $g.resources.init | toYaml | nindent 4 }} +statefulset: + env: + - name: RCLONE_CONFIG_GITEA_TYPE + value: s3 + {{- if eq $obj.type "minioLocal" }} + - name: RCLONE_CONFIG_GITEA_PROVIDER + value: Minio + - name: RCLONE_CONFIG_GITEA_ENDPOINT + value: http://minio.minio.svc.cluster.local:9000 + - name: RCLONE_CONFIG_GITEA_ACCESS_KEY_ID + valueFrom: + secretKeyRef: + name: minio-creds + key: MINIO_ACCESS_KEY + - name: RCLONE_CONFIG_GITEA_SECRET_ACCESS_KEY + valueFrom: + secretKeyRef: + name: minio-creds + key: MINIO_SECRET_KEY + {{- else if eq $obj.type "linode" }} + - name: RCLONE_CONFIG_GITEA_PROVIDER + value: Linode + - name: RCLONE_CONFIG_GITEA_ENDPOINT + value: {{ $obj.linode.region }}.linodeobjects.com + - name: RCLONE_CONFIG_GITEA_ACCESS_KEY_ID + valueFrom: + secretKeyRef: + name: linode-creds + key: S3_STORAGE_ACCOUNT + - name: RCLONE_CONFIG_GITEA_SECRET_ACCESS_KEY + valueFrom: + secretKeyRef: + name: linode-creds + key: S3_STORAGE_KEY + {{- end }} + - name: BUCKET_NAME + value: {{ $giteaBucketName }} + memcached: # @TODO: image: @@ -185,12 +230,19 @@ postgresql: additionalLabels: prometheus: system -{{- if $v._derived.untrustedCA }} extraVolumeMounts: + - name: backup + mountPath: /backup +{{- if $v._derived.untrustedCA }} - name: custom-ca mountPath: /etc/ssl/certs/ca-certificates.crt subPath: ca-certificates.crt +{{- end }} extraVolumes: + - name: backup + persistentVolumeClaim: + claimName: gitea-backup +{{- if $v._derived.untrustedCA }} - name: custom-ca secret: secretName: custom-ca diff --git a/values/harbor/harbor-otomi-db.gotmpl b/values/harbor/harbor-otomi-db.gotmpl index 34483483bb..23598ab7da 100644 --- a/values/harbor/harbor-otomi-db.gotmpl +++ b/values/harbor/harbor-otomi-db.gotmpl @@ -13,7 +13,7 @@ instances: {{ $hdb.replicas }} {{- if $b.enabled }} backup: enabled: {{ $b.enabled }} - schedule: {{ $b.schedule }} + schedule: {{ $b.schedule | quote }} retentionPolicy: {{ $b.retentionPolicy }} type: {{ $obj.type }} {{- if eq $obj.type "minioLocal" }} diff --git a/values/keycloak/keycloak-otomi-db.gotmpl b/values/keycloak/keycloak-otomi-db.gotmpl index be6c61d3c3..5784e898af 100644 --- a/values/keycloak/keycloak-otomi-db.gotmpl +++ b/values/keycloak/keycloak-otomi-db.gotmpl @@ -14,7 +14,7 @@ instances: {{ $kdb.replicas }} {{- if $b.enabled }} backup: enabled: {{ $b.enabled }} - schedule: {{ $b.schedule }} + schedule: {{ $b.schedule | quote }} retentionPolicy: {{ $b.retentionPolicy }} type: {{ $obj.type }} {{- if eq $obj.type "minioLocal" }} diff --git a/values/minio/minio.gotmpl b/values/minio/minio.gotmpl index 066540b406..76a9467b23 100644 --- a/values/minio/minio.gotmpl +++ b/values/minio/minio.gotmpl @@ -3,6 +3,7 @@ {{- $k := $v.apps.keycloak }} {{- $minioDomain := printf "minio.%s" $v.cluster.domainSuffix }} {{- $rootCASecretName := "root-ca" }} +{{- $bucketNames := list "cnpg" "gitea" "harbor" "loki" "tempo" "velero" -}} mode: standalone auth: @@ -63,11 +64,9 @@ provisioning: cpu: 200m memory: 128Mi buckets: - - name: velero - - name: loki - - name: harbor - - name: tempo - - name: cnpg + {{- range $bucketNames }} + - name: {{ . }} + {{- end }} policies: - name: otomi-apps statements: @@ -79,11 +78,9 @@ provisioning: - s3:GetBucketLocation - s3:ListBucketMultipartUploads resources: - - arn:aws:s3:::velero - - arn:aws:s3:::loki - - arn:aws:s3:::harbor - - arn:aws:s3:::tempo - - arn:aws:s3:::cnpg + {{- range $bucketNames }} + - arn:aws:s3:::{{ . }} + {{- end }} - effect: Allow principal: AWS: @@ -91,11 +88,9 @@ provisioning: actions: - s3:ListBucket resources: - - arn:aws:s3:::velero - - arn:aws:s3:::loki - - arn:aws:s3:::harbor - - arn:aws:s3:::tempo - - arn:aws:s3:::cnpg + {{- range $bucketNames }} + - arn:aws:s3:::{{ . }} + {{- end }} condition: StringEquals: s3:prefix: @@ -111,8 +106,6 @@ provisioning: - s3:DeleteObject - s3:GetObject resources: - - arn:aws:s3:::velero/** - - arn:aws:s3:::loki/** - - arn:aws:s3:::harbor/** - - arn:aws:s3:::tempo/** - - arn:aws:s3:::cnpg/** + {{- range $bucketNames }} + - arn:aws:s3:::{{ . }}/** + {{- end }} diff --git a/versions.yaml b/versions.yaml index 030ae04ac3..2bdd59c579 100644 --- a/versions.yaml +++ b/versions.yaml @@ -1,4 +1,4 @@ -api: main -console: main +api: APL-121-gitea-app-backup +console: v3.0.0-rc.0 tasks: 3.2.0 tools: 2.6.0