From 815e9203b0b007b773cc6a8bfbaa7d31501032a4 Mon Sep 17 00:00:00 2001 From: Niklas Date: Thu, 14 Dec 2023 09:23:58 +0100 Subject: [PATCH 1/8] #23 Add first version of installation documentation --- .../backup_operator_installation_de.md | 254 ++++++++++++++++++ 1 file changed, 254 insertions(+) create mode 100644 docs/operations/backup_operator_installation_de.md diff --git a/docs/operations/backup_operator_installation_de.md b/docs/operations/backup_operator_installation_de.md new file mode 100644 index 0000000..c453649 --- /dev/null +++ b/docs/operations/backup_operator_installation_de.md @@ -0,0 +1,254 @@ +# Installation des Backup-Operators + +Der Backup-Operator lässt sich gewöhnlich in einem bestehenden Cloudogu EcoSystem oder leeren Cluster installieren. + +## Installation mit bestehenden Cloudogu EcoSystem + +In einem bestehenden Cloudogu EcoSystem wird der Backup-Operator über den Component-Operator installiert. +Dafür muss eine Custom Resource `Component` für den Backup-Operator und seine eigenen CRDs angelegt werden. + +### Abhängigkeiten + +Vorher sollten aber die Abhängigkeiten des Operators installiert werden. Der Backup-Operator benötigt einen Backup-Provider. +Aktuell wird `velero` als Provider unterstützt. +Ist in dem Cluster keine Snapshot-API verfügbar muss ebenfalls ein Snapshot-Controller installiert werden. +Das Gleiche gilt für den Storage-Provisioner. + +### Storage-Provisioner + +Falls im Cluster kein Storage-Provisioner existiert kann `longhorn` installiert und verwendet werden. +Mit dem Attribute `valuesYamlOverwrite` können für die Backups URL und Credentials zu einem S3-Storage konfiguriert werden. + +```yaml +apiVersion: k8s.cloudogu.com/v1 +kind: Component +metadata: + name: k8s-longhorn +spec: + name: k8s-longhorn + deployNamespace: longhorn-system + namespace: k8s + valuesYamlOverwrite: | + backup: + target: + secret: + # aws_endpoint is just the server url to the s3 compatible storage. + aws_endpoint: http://192.168.56.1:9001 # Insert your s3 url here. Ensure that the bucket `longhorn` exists in the Storage + aws_access_key_id: abcd1234 + aws_secret_access_key: abcc1234 +``` + +#### Snapshot-API + +Falls das Kubernetes-Cluster nicht die Snapshot-API unterstützt muss ebenfalls ein Snapshot-Controller installiert werden. +Dies ist der Fall, wenn man zum Beispiel `k3s` als Kubernetes-Distribution verwendet. + +```yaml +apiVersion: k8s.cloudogu.com/v1 +kind: Component +metadata: + name: k8s-snapshot-controller-crd +spec: + name: k8s-snapshot-controller-crd + namespace: k8s +``` + +```yaml +apiVersion: k8s.cloudogu.com/v1 +kind: Component +metadata: + name: k8s-snapshot-controller +spec: + name: k8s-snapshot-controller + namespace: k8s +``` + +Installation: + +`kubectl --namespace ecosystem apply -f k8s-snapshot-controller-crd.yaml` + +`kubectl --namespace ecosystem apply -f k8s-snapshot-controller.yaml` + +#### Velero + +Velero benötigt zur Ablage der Backups ebenfalls Konfiguration. +Diese beinhaltet den Access-Key, Secret-Key und die URL des S3-Storage. +Mit dem Attribut `valuesYamlOverwrite` lassen sich auch hier beliebige Konfigurationen hinzufügen oder überschreiben: + +```yaml +apiVersion: k8s.cloudogu.com/v1 +kind: Component +metadata: + name: k8s-velero +spec: + name: k8s-velero + namespace: k8s + valuesYamlOverwrite: | + velero: + credentials: + useSecret: true + secretContents: + cloud: | + [default] + aws_access_key_id=abcd1234 + aws_secret_access_key=abcc1234 + configuration: + backupStorageLocation: + - name: default + provider: aws + bucket: velero # Ensure that this bucket exists in the Storage. Furthermore, if you use longhorn the bucket `longhorn` has to be created. + accessMode: ReadWrite + config: + region: minio-default + s3ForcePathStyle: true + s3Url: http://192.168.56.1:9001 # Insert your url here + publicUrl: http://localhost:9001 # Insert your url here +``` + +Die Felder `s3Url` und `publicUrl` sind dementsprechend anzupassen. + +`kubectl --namespace ecosystem apply -f k8s-velero.yaml` + +### Installation Backup-Operator + +Anschließend kann der Backup-Operator mit seinen CRDs installiert werden: + +```yaml +apiVersion: k8s.cloudogu.com/v1 +kind: Component +metadata: + name: k8s-backup-operator-crd +spec: + name: k8s-backup-operator-crd + namespace: k8s +``` + +```yaml +apiVersion: k8s.cloudogu.com/v1 +kind: Component +metadata: + name: k8s-backup-operator +spec: + name: k8s-backup-operator + namespace: k8s +``` + +`kubectl --namespace ecosystem apply -f k8s-backup-operator-crd.yaml` + +`kubectl --namespace ecosystem apply -f k8s-backup-operator.yaml` + + +--- +> Info: +> +> Die Versionen der Komponenten können über das Attribut `version` angepasst passt werden: + +```yaml +apiVersion: k8s.cloudogu.com/v1 +kind: Component +metadata: + name: k8s-backup-operator +spec: + name: k8s-backup-operator + namespace: k8s + version: 0.1.0 +``` + + +Sind alle Komponenten auf Status `RUNNING` kann geprüft werden, ob die BackupStorageLocation verfügbar und der S3-Storage von Velero erreichbar ist. + +`kubectl --namespace ecosystem get backupstoragelocation default` + +Anschließend kann ein reguläres Backup durchgeführt werden. Siehe [Durchführung Backup](backup_de.md). + +## Installation in einem leeren Cluster + +Es kann durchaus Sinn machen Backups nicht in einem bestehenden Cloudogu EcoSystem wiederherzustellen. +Dies ist sinnvoll, wenn man zum Beispiel ein Restore in einen neuen Cluster ausführen möchte. +Dadurch erspart man sich ein initiales Setup des Cloudogu EcoSystems. + +Der Unterschied zu der Methode [Installation in einem bestehenden Cluster](#installation-mit-bestehenden-cloudogu-ecosystem) ist, dass hier die Installation nicht mit dem Komponenten-Operator durchgeführt werden können. +Stattdessen werden die regulären Helm-Charts angewendet. Konfigurationen liegen nicht in der Component-CR, sondern in einer values.yaml. + +Die Bestimmung der Abhängigkeiten bleibt bei dieser Methode gleich: +- Falls kein Storage-Provisioner existiert, muss `k8s-longhorn` installiert werden. +- Fall keine Snapshot-API existiert, muss `k8s-snapshot-controller-crd` und `k8s-snapshot-controller` installiert werden. +- Als Backup-Provider muss `k8s-velero` installiert werden. + +### Helm-Registry Login + +Da in einem bestehenden Cluster der Komponenten-Operator Credentials für die Helm-Registry hat, muss man bei dieser Methode sich direkt mit der Registry authentifizieren. + +`helm registry login registry.cloudogu.com` + +### Storage-Provisioner + +Konfiguration values.yaml: + +```yaml +backup: + target: + secret: + # aws_endpoint is just the server url to the s3 compatible storage. + aws_endpoint: http://192.168.56.1:9001 # Insert your s3 url here. Ensure that the bucket `longhorn` exists in the Storage + aws_access_key_id: abcd1234 + aws_secret_access_key: abcc1234 +``` + +Installation: + +`helm install k8s-longhorn oci://registry.cloudogu.com/k8s/k8s-longhorn --version 1.5.1-3 -f values.yaml --namespace ecosystem` + +### Snapshot-API + +Installation: + +`helm install k8s-snapshot-controller-crd oci://registry.cloudogu.com/k8s/k8s-snapshot-controller-crd --version 5.0.1-5 --namespace ecosystem` + +`helm install k8s-snapshot-controller oci://registry.cloudogu.com/k8s/k8s-snapshot-controller --version 5.0.1-5 --namespace ecosystem` + +### Velero + +```yaml +velero: + credentials: + useSecret: true + secretContents: + cloud: | + [default] + aws_access_key_id=abcd1234 + aws_secret_access_key=abcc1234 + configuration: + backupStorageLocation: + - name: default + provider: aws + bucket: velero # Ensure that this bucket exists in the Storage. Furthermore, if you use longhorn the bucket `longhorn` has to be created. + accessMode: ReadWrite + config: + region: minio-default + s3ForcePathStyle: true + s3Url: http://192.168.56.1:9001 # Insert your url here + publicUrl: http://localhost:9001 # Insert your url here +``` + +Die Felder `s3Url` und `publicUrl` sind dementsprechend anzupassen. + +`helm install k8s-velero oci://registry.cloudogu.com/k8s/k8s-velero --version 5.0.2-4 -f values.yaml --namespace ecosystem` + +### Installation Backup-Operator + +Anschließend kann der Backup-Operator mit seinen CRDs installiert werden: + +`helm install k8s-backup-operator-crd oci://registry.cloudogu.com/k8s/k8s-backup-operator-crd --version 5.0.2-4 --namespace ecosystem` + +`helm install k8s-backup-operator oci://registry.cloudogu.com/k8s/k8s-backup-operator --version 5.0.2-4 --namespace ecosystem` + +Sind alle Komponenten auf Status `RUNNING` kann geprüft werden, ob die BackupStorageLocation verfügbar und der S3-Storage von Velero erreichbar ist. + +`kubectl --namespace ecosystem get backupstoragelocation default` + +Anschließend kann ein regulärer Restore durchgeführt werden. Siehe [Durchführung Restore](restore_de.md). + +### Helm-Registry Logout + +`helm registry logout registry.cloudogu.com` From 2c15db34b84775ad88a838ac04419f0ffa4edb73 Mon Sep 17 00:00:00 2001 From: Jeremias Weber Date: Thu, 14 Dec 2023 14:20:20 +0100 Subject: [PATCH 2/8] #23 skip cleanup of velero resources --- pkg/cleanup/cleanup.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pkg/cleanup/cleanup.go b/pkg/cleanup/cleanup.go index e57f34e..5574996 100644 --- a/pkg/cleanup/cleanup.go +++ b/pkg/cleanup/cleanup.go @@ -21,6 +21,7 @@ const ( deleteVerb = "delete" customResourceDefinitionKind = "CustomResourceDefinition" podKind = "Pod" + veleroGroup = "velero.io" ) var defaultCleanupSelector = &metav1.LabelSelector{ @@ -108,7 +109,11 @@ func (c *defaultCleanupManager) deleteByLabelSelector(ctx context.Context, resou u.SetGroupVersionKind(gvk) // Skip crd deletion because we need the provider and snapshot-controller components. - if gvk.Kind == customResourceDefinitionKind || gvk.Kind == podKind { + if gvk.Kind == customResourceDefinitionKind || + // Skip pod deletion because this would kill our backup operator. + gvk.Kind == podKind || + // Skip velero resource deletion because we need those to restore. + gvk.Group == veleroGroup { return nil } From 4534ae708708763acf94b8c6609a1e8bbbd21a3f Mon Sep 17 00:00:00 2001 From: Niklas Date: Thu, 14 Dec 2023 16:56:16 +0100 Subject: [PATCH 3/8] #23 Add labels --- .../backup_operator_installation_de.md | 14 ++- .../templates/k8s.cloudogu.com_backups.yaml | 105 ++++++++++-------- .../k8s.cloudogu.com_backupschedules.yaml | 96 ++++++++-------- .../templates/k8s.cloudogu.com_restores.yaml | 84 +++++++------- k8s/helm/templates/_helpers.tpl | 2 +- pkg/velero/backupManager.go | 2 +- pkg/velero/syncManager.go | 3 +- 7 files changed, 165 insertions(+), 141 deletions(-) diff --git a/docs/operations/backup_operator_installation_de.md b/docs/operations/backup_operator_installation_de.md index c453649..afd6daa 100644 --- a/docs/operations/backup_operator_installation_de.md +++ b/docs/operations/backup_operator_installation_de.md @@ -38,6 +38,8 @@ spec: aws_secret_access_key: abcc1234 ``` +`kubectl --namespace ecosystem apply -f k8s-longhorn.yaml` + #### Snapshot-API Falls das Kubernetes-Cluster nicht die Snapshot-API unterstützt muss ebenfalls ein Snapshot-Controller installiert werden. @@ -183,7 +185,7 @@ Da in einem bestehenden Cluster der Komponenten-Operator Credentials für die He ### Storage-Provisioner -Konfiguration values.yaml: +Konfiguration k8s-longhorn-values.yaml: ```yaml backup: @@ -197,13 +199,13 @@ backup: Installation: -`helm install k8s-longhorn oci://registry.cloudogu.com/k8s/k8s-longhorn --version 1.5.1-3 -f values.yaml --namespace ecosystem` +`helm install k8s-longhorn oci://registry.cloudogu.com/k8s/k8s-longhorn --version 1.5.1-3 -f k8s-longhorn-values.yaml --namespace longhorn-system --create-namespace` ### Snapshot-API Installation: -`helm install k8s-snapshot-controller-crd oci://registry.cloudogu.com/k8s/k8s-snapshot-controller-crd --version 5.0.1-5 --namespace ecosystem` +`helm install k8s-snapshot-controller-crd oci://registry.cloudogu.com/k8s/k8s-snapshot-controller-crd --version 5.0.1-5 --namespace ecosystem --create-namespace` `helm install k8s-snapshot-controller oci://registry.cloudogu.com/k8s/k8s-snapshot-controller --version 5.0.1-5 --namespace ecosystem` @@ -233,15 +235,15 @@ velero: Die Felder `s3Url` und `publicUrl` sind dementsprechend anzupassen. -`helm install k8s-velero oci://registry.cloudogu.com/k8s/k8s-velero --version 5.0.2-4 -f values.yaml --namespace ecosystem` +`helm install k8s-velero oci://registry.cloudogu.com/k8s/k8s-velero --version 5.0.2-4 -f k8s-velero-values.yaml --namespace ecosystem` ### Installation Backup-Operator Anschließend kann der Backup-Operator mit seinen CRDs installiert werden: -`helm install k8s-backup-operator-crd oci://registry.cloudogu.com/k8s/k8s-backup-operator-crd --version 5.0.2-4 --namespace ecosystem` +`helm install k8s-backup-operator-crd oci://registry.cloudogu.com/k8s/k8s-backup-operator-crd --version 0.9.0 --namespace ecosystem` -`helm install k8s-backup-operator oci://registry.cloudogu.com/k8s/k8s-backup-operator --version 5.0.2-4 --namespace ecosystem` +`helm install k8s-backup-operator oci://registry.cloudogu.com/k8s/k8s-backup-operator --version 0.9.0 --namespace ecosystem` Sind alle Komponenten auf Status `RUNNING` kann geprüft werden, ob die BackupStorageLocation verfügbar und der S3-Storage von Velero erreichbar ist. diff --git a/k8s/helm-crd/templates/k8s.cloudogu.com_backups.yaml b/k8s/helm-crd/templates/k8s.cloudogu.com_backups.yaml index 45deb7e..9777921 100644 --- a/k8s/helm-crd/templates/k8s.cloudogu.com_backups.yaml +++ b/k8s/helm-crd/templates/k8s.cloudogu.com_backups.yaml @@ -18,50 +18,61 @@ spec: singular: backup scope: Namespaced versions: - - name: v1 - schema: - openAPIV3Schema: - description: Backup is the Schema for the backups API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: Spec defines the desired state of Backup - properties: - provider: - description: Provider defines the backup provider which should be used for the backup. - type: string - syncedFromProvider: - description: 'SyncedFromProvider defines that this backup already exists in the provider and its status should be synced. This is necessary because we cannot set the status of a backup on creation, see: https://stackoverflow.com/questions/73574615/how-to-create-kubernetes-objects-with-status-fields' - type: boolean - type: object - status: - description: Status defines the observed state of Backup - properties: - completionTimestamp: - description: CompletionTimestamp marks the date/time when the backup finished being processed, regardless of any errors. - format: date-time - type: string - requeueTimeNanos: - description: RequeueTimeNanos contains the time in nanoseconds to wait until the next requeue. - format: int64 - type: integer - startTimestamp: - description: StartTimestamp marks the date/time when the backup started being processed. - format: date-time - type: string - status: - description: Status represents the state of the backup. - type: string - type: object - type: object - served: true - storage: true - subresources: - status: {} + - name: v1 + schema: + openAPIV3Schema: + description: Backup is the Schema for the backups API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: Spec defines the desired state of Backup + properties: + provider: + description: Provider defines the backup provider which should be + used for the backup. + type: string + syncedFromProvider: + description: 'SyncedFromProvider defines that this backup already + exists in the provider and its status should be synced. This is + necessary because we cannot set the status of a backup on creation, + see: https://stackoverflow.com/questions/73574615/how-to-create-kubernetes-objects-with-status-fields' + type: boolean + type: object + status: + description: Status defines the observed state of Backup + properties: + completionTimestamp: + description: CompletionTimestamp marks the date/time when the backup + finished being processed, regardless of any errors. + format: date-time + type: string + requeueTimeNanos: + description: RequeueTimeNanos contains the time in nanoseconds to + wait until the next requeue. + format: int64 + type: integer + startTimestamp: + description: StartTimestamp marks the date/time when the backup started + being processed. + format: date-time + type: string + status: + description: Status represents the state of the backup. + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/k8s/helm-crd/templates/k8s.cloudogu.com_backupschedules.yaml b/k8s/helm-crd/templates/k8s.cloudogu.com_backupschedules.yaml index 2bc755c..0b064ab 100644 --- a/k8s/helm-crd/templates/k8s.cloudogu.com_backupschedules.yaml +++ b/k8s/helm-crd/templates/k8s.cloudogu.com_backupschedules.yaml @@ -5,10 +5,6 @@ metadata: annotations: controller-gen.kubebuilder.io/version: v0.13.0 name: backupschedules.k8s.cloudogu.com - labels: - app: ces - app.kubernetes.io/name: k8s-backup-operator - k8s.cloudogu.com/part-of: backup spec: group: k8s.cloudogu.com names: @@ -18,45 +14,53 @@ spec: singular: backupschedule scope: Namespaced versions: - - name: v1 - schema: - openAPIV3Schema: - description: BackupSchedule is the Schema for the backupschedules API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: BackupScheduleSpec defines the desired state of BackupSchedule - properties: - provider: - description: Provider defines the backup provider which should be used for the scheduled backups. - type: string - schedule: - description: Schedule is a cron expression defining when to run the backup. - type: string - type: object - status: - description: BackupScheduleStatus defines the observed state of BackupSchedule - properties: - currentCronJobImage: - description: CurrentCronJobImage is the image currently used to create scheduled backups. - type: string - requeueTimeNanos: - description: RequeueTimeNanos contains the time in nanoseconds to wait until the next requeue. - format: int64 - type: integer - status: - description: Status represents the state of the backup. - type: string - type: object - type: object - served: true - storage: true - subresources: - status: {} + - name: v1 + schema: + openAPIV3Schema: + description: BackupSchedule is the Schema for the backupschedules API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: BackupScheduleSpec defines the desired state of BackupSchedule + properties: + provider: + description: Provider defines the backup provider which should be + used for the scheduled backups. + type: string + schedule: + description: Schedule is a cron expression defining when to run the + backup. + type: string + type: object + status: + description: BackupScheduleStatus defines the observed state of BackupSchedule + properties: + currentCronJobImage: + description: CurrentCronJobImage is the image currently used to create + scheduled backups. + type: string + requeueTimeNanos: + description: RequeueTimeNanos contains the time in nanoseconds to + wait until the next requeue. + format: int64 + type: integer + status: + description: Status represents the state of the backup. + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/k8s/helm-crd/templates/k8s.cloudogu.com_restores.yaml b/k8s/helm-crd/templates/k8s.cloudogu.com_restores.yaml index b37afbd..175b24e 100644 --- a/k8s/helm-crd/templates/k8s.cloudogu.com_restores.yaml +++ b/k8s/helm-crd/templates/k8s.cloudogu.com_restores.yaml @@ -18,42 +18,48 @@ spec: singular: restore scope: Namespaced versions: - - name: v1 - schema: - openAPIV3Schema: - description: Restore is the Schema for the restores API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: Spec defines the desired state of Restore - properties: - backupName: - description: BackupName references the backup that should be restored. - type: string - provider: - description: Provider defines the backup provider which should be used for the restore. - type: string - type: object - status: - description: Status defines the observed state of Restore - properties: - requeueTimeNanos: - description: RequeueTimeNanos contains the time in nanoseconds to wait until the next requeue. - format: int64 - type: integer - status: - description: Status represents the state of the backup. - type: string - type: object - type: object - served: true - storage: true - subresources: - status: {} + - name: v1 + schema: + openAPIV3Schema: + description: Restore is the Schema for the restores API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: Spec defines the desired state of Restore + properties: + backupName: + description: BackupName references the backup that should be restored. + type: string + provider: + description: Provider defines the backup provider which should be + used for the restore. + type: string + type: object + status: + description: Status defines the observed state of Restore + properties: + requeueTimeNanos: + description: RequeueTimeNanos contains the time in nanoseconds to + wait until the next requeue. + format: int64 + type: integer + status: + description: Status represents the state of the backup. + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/k8s/helm/templates/_helpers.tpl b/k8s/helm/templates/_helpers.tpl index 422a44a..1ee4078 100644 --- a/k8s/helm/templates/_helpers.tpl +++ b/k8s/helm/templates/_helpers.tpl @@ -21,7 +21,7 @@ app.kubernetes.io/managed-by: {{ .Release.Service }} {{- define "k8s-backup-operator.selectorLabels" -}} app.kubernetes.io/name: {{ include "k8s-backup-operator.name" . }} app.kubernetes.io/instance: {{ .Release.Name }} -k8s.cloudogu.com/part-of: k8s-backup-operator +k8s.cloudogu.com/part-of: backup {{- end }} {{/* Default image configuration, e.g. the operator image */}} diff --git a/pkg/velero/backupManager.go b/pkg/velero/backupManager.go index 6b0b5ba..ca0158a 100644 --- a/pkg/velero/backupManager.go +++ b/pkg/velero/backupManager.go @@ -40,7 +40,7 @@ func (bm *defaultBackupManager) CreateBackup(ctx context.Context, backup *v1.Bac volumeFsBackup := false veleroBackup := &velerov1.Backup{ - ObjectMeta: metav1.ObjectMeta{Name: backup.Name, Namespace: backup.Namespace}, + ObjectMeta: metav1.ObjectMeta{Name: backup.Name, Namespace: backup.Namespace, Labels: map[string]string{"app": "ces", "k8s.cloudogu.com/part-of": "backup"}}, Spec: velerov1.BackupSpec{ TTL: metav1.Duration{Duration: defaultBackupTTL}, IncludedNamespaces: []string{backup.Namespace}, diff --git a/pkg/velero/syncManager.go b/pkg/velero/syncManager.go index f11e7c5..c17b1f5 100644 --- a/pkg/velero/syncManager.go +++ b/pkg/velero/syncManager.go @@ -70,7 +70,8 @@ func createBackupsForVeleroBackups(ctx context.Context, veleroBackupsList *veler if _, exists := backupMap[veleroBackup.Name]; !exists { newBackup := &backupv1.Backup{ ObjectMeta: metav1.ObjectMeta{ - Name: veleroBackup.Name, + Name: veleroBackup.Name, + Labels: map[string]string{"app": "ces", "k8s.cloudogu.com/part-of": "backup"}, }, Spec: backupv1.BackupSpec{ Provider: backupv1.ProviderVelero, From 62d652552936b34a905fa445011dcdc4bf4a8fc5 Mon Sep 17 00:00:00 2001 From: Niklas Date: Fri, 15 Dec 2023 08:03:04 +0100 Subject: [PATCH 4/8] #23 Add translation --- .../backup_operator_installation_de.md | 8 +- .../backup_operator_installation_en.md | 256 ++++++++++++++++++ 2 files changed, 260 insertions(+), 4 deletions(-) create mode 100644 docs/operations/backup_operator_installation_en.md diff --git a/docs/operations/backup_operator_installation_de.md b/docs/operations/backup_operator_installation_de.md index afd6daa..6d075ca 100644 --- a/docs/operations/backup_operator_installation_de.md +++ b/docs/operations/backup_operator_installation_de.md @@ -107,13 +107,13 @@ spec: publicUrl: http://localhost:9001 # Insert your url here ``` -Die Felder `s3Url` und `publicUrl` sind dementsprechend anzupassen. +Die Felder `aws_access_key_id`, `aws_secret_access_key_id`, `s3Url` und `publicUrl` sind dementsprechend anzupassen. `kubectl --namespace ecosystem apply -f k8s-velero.yaml` ### Installation Backup-Operator -Anschließend kann der Backup-Operator mit seinen CRDs installiert werden: +Anschließend kann der Backup-Operator mit seinen Komponenten-CRs installiert werden: ```yaml apiVersion: k8s.cloudogu.com/v1 @@ -233,13 +233,13 @@ velero: publicUrl: http://localhost:9001 # Insert your url here ``` -Die Felder `s3Url` und `publicUrl` sind dementsprechend anzupassen. +Die Felder `aws_access_key_id`, `aws_secret_access_key_id`, `s3Url` und `publicUrl` sind dementsprechend anzupassen. `helm install k8s-velero oci://registry.cloudogu.com/k8s/k8s-velero --version 5.0.2-4 -f k8s-velero-values.yaml --namespace ecosystem` ### Installation Backup-Operator -Anschließend kann der Backup-Operator mit seinen CRDs installiert werden: +Anschließend kann der Backup-Operator installiert werden: `helm install k8s-backup-operator-crd oci://registry.cloudogu.com/k8s/k8s-backup-operator-crd --version 0.9.0 --namespace ecosystem` diff --git a/docs/operations/backup_operator_installation_en.md b/docs/operations/backup_operator_installation_en.md new file mode 100644 index 0000000..17dd04d --- /dev/null +++ b/docs/operations/backup_operator_installation_en.md @@ -0,0 +1,256 @@ +# Installing the backup operator + +The backup operator can usually be installed in an existing Cloudogu EcoSystem or empty cluster. + +## Installation with an existing Cloudogu EcoSystem + +In an existing Cloudogu EcoSystem, the backup operator is installed via the component operator. +To do this, a custom resource `Component` must be created for the backup operator and its own CRDs. + +### Dependencies + +However, the operator's dependencies should be installed first. The backup operator requires a backup provider. +Currently `velero` is supported as a provider. +If no snapshot API is available in the cluster, a snapshot controller must also be installed. +The same applies to the storage provider. + +### Storage provisioner + +If no storage provisioner exists in the cluster, `longhorn` can be installed and used. +The attribute `valuesYamlOverwrite` can be used to configure the URL and credentials for backups to an S3 storage. + +```yaml +apiVersion: k8s.cloudogu.com/v1 +kind: Component +metadata: + name: k8s-longhorn +spec: + name: k8s-longhorn + deployNamespace: longhorn-system + namespace: k8s + valuesYamlOverwrite: | + backup: + target: + secret: + # aws_endpoint is just the server url to the s3 compatible storage. + aws_endpoint: http://192.168.56.1:9001 # Insert your s3 url here. Ensure that the bucket `longhorn` exists in the Storage + aws_access_key_id: abcd1234 # Insert your access key here + aws_secret_access_key: abcc1234 # Insert your access secret key here +``` + +`kubectl --namespace ecosystem apply -f k8s-longhorn.yaml` + +#### Snapshot API + +If the Kubernetes cluster does not support the snapshot API, a snapshot controller must also be installed. +This is the case if, for example, `k3s` is used as the Kubernetes distribution. + +```yaml +apiVersion: k8s.cloudogu.com/v1 +kind: Component +metadata: + name: k8s-snapshot-controller-crd +spec: + name: k8s-snapshot-controller-crd + namespace: k8s +``` + +```yaml +apiVersion: k8s.cloudogu.com/v1 +kind: Component +metadata: + name: k8s-snapshot-controller +spec: + name: k8s-snapshot-controller + namespace: k8s +``` + +Installation: + +`kubectl --namespace ecosystem apply -f k8s-snapshot-controller-crd.yaml` + +`kubectl --namespace ecosystem apply -f k8s-snapshot-controller.yaml` + +#### Velero + +Velero also requires configuration to store the backups. +This includes the access key, secret key and the URL of the S3 storage. +The attribute `valuesYamlOverwrite` can also be used here to add or overwrite any configurations: + +```yaml +apiVersion: k8s.cloudogu.com/v1 +kind: Component +metadata: + name: k8s-velero +spec: + name: k8s-velero + namespace: k8s + valuesYamlOverwrite: | + velero: + credentials: + useSecret: true + secretContents: + cloud: | + [default] + aws_access_key_id=abcd1234 # Insert your access key here + aws_secret_access_key=abcc1234 # Insert your access secret key here + configuration: + backupStorageLocation: + - name: default + provider: aws + bucket: velero # Ensure that this bucket exists in the Storage. Furthermore, if you use longhorn the bucket `longhorn` has to be created. + accessMode: ReadWrite + config: + region: minio-default + s3ForcePathStyle: true + s3Url: http://192.168.56.1:9001 # Insert your url here + publicUrl: http://localhost:9001 # Insert your url here +``` + +The `aws_access_key_id`, `aws_secret_access_key_id`, `s3Url` and `publicUrl` fields must be adapted accordingly. + +`kubectl --namespace ecosystem apply -f k8s-velero.yaml` + +### Installation backup operator + +The backup operator can then be installed with its Component-CRs: + +```yaml +apiVersion: k8s.cloudogu.com/v1 +kind: Component +metadata: + name: k8s-backup-operator-crd +spec: + name: k8s-backup-operator-crd + namespace: k8s +``` + +```yaml +apiVersion: k8s.cloudogu.com/v1 +kind: Component +metadata: + name: k8s-backup-operator +spec: + name: k8s-backup-operator + namespace: k8s +``` + +`kubectl --namespace ecosystem apply -f k8s-backup-operator-crd.yaml` + +`kubectl --namespace ecosystem apply -f k8s-backup-operator.yaml` + + +--- +> Info: +> +> The versions of the components can be customized using the `version` attribute: + +```yaml +apiVersion: k8s.cloudogu.com/v1 +kind: Component +metadata: + name: k8s-backup-operator +spec: + name: k8s-backup-operator + namespace: k8s + version: 0.1.0 +``` + + +If all components have the status `RUNNING`, you can check whether the BackupStorageLocation is available and the S3 storage of Velero is accessible. + +`kubectl --namespace ecosystem get backupstoragelocation default` + +A regular backup can then be performed. See [Perform backup](backup_en.md). + +## Installation in an empty cluster + +It may make sense not to restore backups to an existing Cloudogu EcoSystem. +This makes sense, for example, if you want to perform a restore to a new cluster. +This saves an initial setup of the Cloudogu EcoSystem. + +The difference to the method [Installation in an existing cluster](#installation-with-existing-cloudogu-ecosystem) is that the installation cannot be carried out with the component operator. +Instead, the regular Helm charts are used. Configurations are not in the component CR, but in a values.yaml. + +The determination of dependencies remains the same with this method: +- If no storage provisioner exists, `k8s-longhorn` must be installed. +- If no snapshot API exists, `k8s-snapshot-controller-crd` and `k8s-snapshot-controller` must be installed. +- The backup provider `k8s-velero` must be installed. + +### Helm registry login + +Since the component operator in an existing cluster has credentials for the Helm registry, this method requires you to authenticate yourself directly with the registry. + +`helm registry login registry.cloudogu.com` + +### Storage-Provisioner + +Configuration k8s-longhorn-values.yaml: + +```yaml +backup: + target: + secret: + # aws_endpoint is just the server url to the s3 compatible storage. + aws_endpoint: http://192.168.56.1:9001 # Insert your s3 url here. Ensure that the bucket `longhorn` exists in the Storage + aws_access_key_id: abcd1234 # Insert your access key here + aws_secret_access_key: abcc1234 # Insert your access secret key here +``` + +Installation: + +`helm install k8s-longhorn oci://registry.cloudogu.com/k8s/k8s-longhorn --version 1.5.1-3 -f k8s-longhorn-values.yaml --namespace longhorn-system --create-namespace` + +### Snapshot API + +Installation: + +`helm install k8s-snapshot-controller-crd oci://registry.cloudogu.com/k8s/k8s-snapshot-controller-crd --version 5.0.1-5 --namespace ecosystem --create-namespace` + +`helm install k8s-snapshot-controller oci://registry.cloudogu.com/k8s/k8s-snapshot-controller --version 5.0.1-5 --namespace ecosystem` + +### Velero + +```yaml +velero: + credentials: + useSecret: true + secretContents: + cloud: | + [default] + aws_access_key_id=abcd1234 # Insert your access key here + aws_secret_access_key=abcc1234 # Insert your access secret key here + configuration: + backupStorageLocation: + - name: default + provider: aws + bucket: velero # Ensure that this bucket exists in the Storage. Furthermore, if you use longhorn the bucket `longhorn` has to be created. + accessMode: ReadWrite + config: + region: minio-default + s3ForcePathStyle: true + s3Url: http://192.168.56.1:9001 # Insert your url here + publicUrl: http://localhost:9001 # Insert your url here +``` + +The `aws_access_key_id`, `aws_secret_access_key_id`, `s3Url` and `publicUrl` fields must be adapted accordingly. + +`helm install k8s-velero oci://registry.cloudogu.com/k8s/k8s-velero --version 5.0.2-4 -f k8s-velero-values.yaml --namespace ecosystem` + +### Installation backup operator + +The backup operator can then be installed: + +`helm install k8s-backup-operator-crd oci://registry.cloudogu.com/k8s/k8s-backup-operator-crd --version 0.9.0 --namespace ecosystem` + +`helm install k8s-backup-operator oci://registry.cloudogu.com/k8s/k8s-backup-operator --version 0.9.0 --namespace ecosystem` + +If all components have the status `RUNNING`, you can check whether the BackupStorageLocation is available and the S3 storage of Velero is accessible. + +`kubectl --namespace ecosystem get backupstoragelocation default` + +A regular restore can then be performed. See [Execution Restore](restore_en.md). + +### Helm registry logout + +`helm registry logout registry.cloudogu.com`. \ No newline at end of file From d616c7b600dbb8e5929920b03276dc6ec311305f Mon Sep 17 00:00:00 2001 From: Niklas Date: Fri, 15 Dec 2023 10:08:40 +0100 Subject: [PATCH 5/8] #23 Add CHANGELOG.md entry. --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a2d5a89..79ada9d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added +- [#23] Added docs for installing the operator in an existent Cloudogu EcoSystem and on an empty cluster. + +### Fixed +- Fix value of label `k8s.cloudogu.com/part-of` in helm template do avoid deletion in cleanup process. ## [v0.9.0] - 2023-12-08 ### Added From 55b5b1097148fa6822b22cec04fc5ba6fe8f93d6 Mon Sep 17 00:00:00 2001 From: Niklas Date: Fri, 15 Dec 2023 12:06:12 +0100 Subject: [PATCH 6/8] #23 Fix unit-tests --- pkg/velero/backupManager_test.go | 20 ++++++++++---------- pkg/velero/syncManager_test.go | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/pkg/velero/backupManager_test.go b/pkg/velero/backupManager_test.go index d432bab..6ecc028 100644 --- a/pkg/velero/backupManager_test.go +++ b/pkg/velero/backupManager_test.go @@ -32,7 +32,7 @@ func Test_backupManager_CreateBackup(t *testing.T) { volumeFsBackup := false expectedVeleroBackup := &velerov1.Backup{ - ObjectMeta: metav1.ObjectMeta{Name: "testBackup", Namespace: testNamespace}, + ObjectMeta: metav1.ObjectMeta{Name: "testBackup", Namespace: testNamespace, Labels: map[string]string{"app": "ces", "k8s.cloudogu.com/part-of": "backup"}}, Spec: velerov1.BackupSpec{ TTL: metav1.Duration{Duration: 87660 * time.Hour}, IncludedNamespaces: []string{testNamespace}, @@ -70,7 +70,7 @@ func Test_backupManager_CreateBackup(t *testing.T) { volumeFsBackup := false expectedVeleroBackup := &velerov1.Backup{ - ObjectMeta: metav1.ObjectMeta{Name: "testBackup", Namespace: testNamespace}, + ObjectMeta: metav1.ObjectMeta{Name: "testBackup", Namespace: testNamespace, Labels: map[string]string{"app": "ces", "k8s.cloudogu.com/part-of": "backup"}}, Spec: velerov1.BackupSpec{ TTL: metav1.Duration{Duration: 87660 * time.Hour}, IncludedNamespaces: []string{testNamespace}, @@ -109,7 +109,7 @@ func Test_backupManager_CreateBackup(t *testing.T) { volumeFsBackup := false expectedVeleroBackup := &velerov1.Backup{ - ObjectMeta: metav1.ObjectMeta{Name: "testBackup", Namespace: testNamespace}, + ObjectMeta: metav1.ObjectMeta{Name: "testBackup", Namespace: testNamespace, Labels: map[string]string{"app": "ces", "k8s.cloudogu.com/part-of": "backup"}}, Spec: velerov1.BackupSpec{ TTL: metav1.Duration{Duration: 87660 * time.Hour}, IncludedNamespaces: []string{testNamespace}, @@ -142,7 +142,7 @@ func Test_backupManager_CreateBackup(t *testing.T) { resultChan <- watch.Event{ Type: watch.Deleted, Object: &velerov1.Backup{ - ObjectMeta: metav1.ObjectMeta{Name: "testBackup", Namespace: testNamespace}, + ObjectMeta: metav1.ObjectMeta{Name: "testBackup", Namespace: testNamespace, Labels: map[string]string{"app": "ces", "k8s.cloudogu.com/part-of": "backup"}}, }, } }() @@ -164,7 +164,7 @@ func Test_backupManager_CreateBackup(t *testing.T) { volumeFsBackup := false expectedVeleroBackup := &velerov1.Backup{ - ObjectMeta: metav1.ObjectMeta{Name: "testBackup", Namespace: testNamespace}, + ObjectMeta: metav1.ObjectMeta{Name: "testBackup", Namespace: testNamespace, Labels: map[string]string{"app": "ces", "k8s.cloudogu.com/part-of": "backup"}}, Spec: velerov1.BackupSpec{ TTL: metav1.Duration{Duration: 87660 * time.Hour}, IncludedNamespaces: []string{testNamespace}, @@ -197,7 +197,7 @@ func Test_backupManager_CreateBackup(t *testing.T) { resultChan <- watch.Event{ Type: watch.Modified, Object: &velerov1.Backup{ - ObjectMeta: metav1.ObjectMeta{Name: "testBackup", Namespace: testNamespace}, + ObjectMeta: metav1.ObjectMeta{Name: "testBackup", Namespace: testNamespace, Labels: map[string]string{"app": "ces", "k8s.cloudogu.com/part-of": "backup"}}, Status: velerov1.BackupStatus{Phase: velerov1.BackupPhaseFailedValidation}, }, } @@ -220,7 +220,7 @@ func Test_backupManager_CreateBackup(t *testing.T) { volumeFsBackup := false expectedVeleroBackup := &velerov1.Backup{ - ObjectMeta: metav1.ObjectMeta{Name: "testBackup", Namespace: testNamespace}, + ObjectMeta: metav1.ObjectMeta{Name: "testBackup", Namespace: testNamespace, Labels: map[string]string{"app": "ces", "k8s.cloudogu.com/part-of": "backup"}}, Spec: velerov1.BackupSpec{ TTL: metav1.Duration{Duration: 87660 * time.Hour}, IncludedNamespaces: []string{testNamespace}, @@ -253,7 +253,7 @@ func Test_backupManager_CreateBackup(t *testing.T) { resultChan <- watch.Event{ Type: watch.Modified, Object: &velerov1.Backup{ - ObjectMeta: metav1.ObjectMeta{Name: "testBackup", Namespace: testNamespace}, + ObjectMeta: metav1.ObjectMeta{Name: "testBackup", Namespace: testNamespace, Labels: map[string]string{"app": "ces", "k8s.cloudogu.com/part-of": "backup"}}, Status: velerov1.BackupStatus{Phase: velerov1.BackupPhaseDeleting}, }, } @@ -276,7 +276,7 @@ func Test_backupManager_CreateBackup(t *testing.T) { volumeFsBackup := false expectedVeleroBackup := &velerov1.Backup{ - ObjectMeta: metav1.ObjectMeta{Name: "testBackup", Namespace: testNamespace}, + ObjectMeta: metav1.ObjectMeta{Name: "testBackup", Namespace: testNamespace, Labels: map[string]string{"app": "ces", "k8s.cloudogu.com/part-of": "backup"}}, Spec: velerov1.BackupSpec{ TTL: metav1.Duration{Duration: 87660 * time.Hour}, IncludedNamespaces: []string{testNamespace}, @@ -309,7 +309,7 @@ func Test_backupManager_CreateBackup(t *testing.T) { resultChan <- watch.Event{ Type: watch.Modified, Object: &velerov1.Backup{ - ObjectMeta: metav1.ObjectMeta{Name: "testBackup", Namespace: testNamespace}, + ObjectMeta: metav1.ObjectMeta{Name: "testBackup", Namespace: testNamespace, Labels: map[string]string{"app": "ces", "k8s.cloudogu.com/part-of": "backup"}}, Status: velerov1.BackupStatus{Phase: velerov1.BackupPhaseCompleted}, }, } diff --git a/pkg/velero/syncManager_test.go b/pkg/velero/syncManager_test.go index fa80602..3240250 100644 --- a/pkg/velero/syncManager_test.go +++ b/pkg/velero/syncManager_test.go @@ -170,7 +170,7 @@ func Test_defaultSyncManager_SyncBackups(t *testing.T) { } createBackupMock := backupv1.Backup{ TypeMeta: metav1.TypeMeta{}, - ObjectMeta: metav1.ObjectMeta{Name: veleroBackupName}, + ObjectMeta: metav1.ObjectMeta{Name: veleroBackupName, Labels: map[string]string{"app": "ces", "k8s.cloudogu.com/part-of": "backup"}}, Spec: backupv1.BackupSpec{ Provider: backupv1.ProviderVelero, SyncedFromProvider: true, @@ -235,7 +235,7 @@ func Test_defaultSyncManager_SyncBackups(t *testing.T) { } createBackupMock := backupv1.Backup{ TypeMeta: metav1.TypeMeta{}, - ObjectMeta: metav1.ObjectMeta{Name: veleroBackupName}, + ObjectMeta: metav1.ObjectMeta{Name: veleroBackupName, Labels: map[string]string{"app": "ces", "k8s.cloudogu.com/part-of": "backup"}}, Spec: backupv1.BackupSpec{ Provider: backupv1.ProviderVelero, SyncedFromProvider: true, From c66fb795455b3ed5cdf552a05a6af153935198ef Mon Sep 17 00:00:00 2001 From: Benjamin Ernst Date: Tue, 19 Dec 2023 16:01:00 +0100 Subject: [PATCH 7/8] Bump version --- Dockerfile | 2 +- Makefile | 2 +- k8s/helm/component-patch-tpl.yaml | 2 +- k8s/helm/values.yaml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index fcb2803..50b637e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -34,7 +34,7 @@ RUN make compile-generic FROM gcr.io/distroless/static:nonroot LABEL maintainer="hello@cloudogu.com" \ NAME="k8s-backup-operator" \ - VERSION="0.9.0" + VERSION="0.10.0" WORKDIR / COPY --from=builder /workspace/target/k8s-backup-operator . diff --git a/Makefile b/Makefile index e6b30bf..4cdd246 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ # Set these to the desired values ARTIFACT_ID=k8s-backup-operator -VERSION=0.9.0 +VERSION=0.10.0 IMAGE=cloudogu/${ARTIFACT_ID}:${VERSION} GOTAG?=1.21 MAKEFILES_VERSION=9.0.1 diff --git a/k8s/helm/component-patch-tpl.yaml b/k8s/helm/component-patch-tpl.yaml index 97ac2cf..92a480b 100644 --- a/k8s/helm/component-patch-tpl.yaml +++ b/k8s/helm/component-patch-tpl.yaml @@ -1,7 +1,7 @@ apiVersion: v1 values: images: - backupOperator: cloudogu/k8s-backup-operator:0.9.0 + backupOperator: cloudogu/k8s-backup-operator:0.10.0 kubeRbacProxy: gcr.io/kubebuilder/kube-rbac-proxy:v0.14.1 patches: values.yaml: diff --git a/k8s/helm/values.yaml b/k8s/helm/values.yaml index a638f54..8992a16 100644 --- a/k8s/helm/values.yaml +++ b/k8s/helm/values.yaml @@ -18,7 +18,7 @@ manager: logLevel: info image: repository: cloudogu/k8s-backup-operator - tag: 0.9.0 + tag: 0.10.0 imagePullPolicy: IfNotPresent resources: limits: From f97d936ffebc3805c470899c4074a8391c51b164 Mon Sep 17 00:00:00 2001 From: Benjamin Ernst Date: Tue, 19 Dec 2023 16:01:11 +0100 Subject: [PATCH 8/8] Update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 79ada9d..d6ff418 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] + +## [v0.10.0] - 2023-12-19 ### Added - [#23] Added docs for installing the operator in an existent Cloudogu EcoSystem and on an empty cluster.