Skip to content

Datenbanken ​

Datenbanken legst du als Custom Resource in deinem Namespace an. Die Operatoren laufen bereits im Cluster, du musst nichts installieren.

PostgreSQL (CloudNativePG) ​

Gruppe und Version: postgresql.cnpg.io/v1, Kind Cluster.

yaml
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
  name: app-db
spec:
  instances: 3
  storage:
    size: 10Gi
    storageClass: hcloud-volumes

Eine Instanz ohne Backup ist kein Produktionsbetrieb

Ein Cluster mit instances: 1 und ohne konfiguriertes Backup ist ein Ausgangspunkt zum Ausprobieren. Für den Produktivbetrieb nimm instances: 3 und richte ein Backup-Ziel ein. Das Volume auf hcloud-volumes ist über das Netz angebunden und übersteht den Ausfall eines Knotens, aber mit einer Instanz ist die Datenbank nicht erreichbar, bis das Volume an einem anderen Knoten hängt und der Pod dort gestartet ist. Ohne Backup-Ziel gibt es keine Wiederherstellung auf einen bestimmten Zeitpunkt und nichts Konsistentes, aus dem du zurückholen kannst, wenn Daten gelöscht oder beschädigt werden oder das Volume selbst verloren geht.

Wird sein Knoten ersetzt, startet ein Cluster mit instances: 1 samt Volume auf einem anderen Knoten neu und ist bis dahin nicht erreichbar. Behält der Cluster sein PodDisruptionBudget (die Voreinstellung), setzt die Plattform für diese Zeit spec.nodeMaintenanceWindow am Cluster und entfernt das Feld danach wieder. Mit zwei oder mehr Instanzen wechselt der Primary vorher auf eine andere Instanz.

In einen PostgreSQL-Pod kommst du nicht per Shell ​

kubectl exec in einen CloudNativePG-Pod wird abgelehnt:

text
Error from server: admission webhook denied the request:
Exec/attach is only allowed into gVisor-sandboxed pods.

Deine eigenen Workloads laufen sandboxed und akzeptieren exec ganz normal. PostgreSQL-Pods sind die Ausnahme, das betrifft also nur PostgreSQL. In MariaDB- und Dragonfly-Pods kommst du wie überall sonst hinein.

kubectl port-forward ist davon nicht betroffen. Der übliche Weg, SQL gegen deine eigene Datenbank auszuführen, ist deshalb: Port weiterleiten und mit einem lokalen Client verbinden, mit den Zugangsdaten, die der Operator erzeugt hat. Ein kurzlebiger psql-Pod im Namespace funktioniert genauso.

MariaDB (mariadb-operator) ​

Gruppe: k8s.mariadb.com, Kind MariaDB.

yaml
apiVersion: k8s.mariadb.com/v1alpha1
kind: MariaDB
metadata:
  name: app-db
spec:
  rootPasswordSecretKeyRef:
    name: app-db-root
    key: password
  storage:
    size: 10Gi
    storageClassName: hcloud-volumes

Dragonfly ​

Gruppe und Version: dragonflydb.io/v1alpha1, Kind Dragonfly.

yaml
apiVersion: dragonflydb.io/v1alpha1
kind: Dragonfly
metadata:
  name: cache
spec:
  replicas: 2

Erreichbar ist die Instanz unter redis://<name>:6379, im Beispiel oben also redis://cache:6379.

Dragonfly spricht das Redis-Wire-Protokoll, die meisten Clients funktionieren deshalb ohne Anpassung. Es gibt allerdings dokumentierte Unterschiede im Verhalten einzelner Befehle. Teste deine Anwendung, bevor du eine bestehende Redis-Instanz ablöst.

Ohne spec.image läuft die Instanz mit der Dragonfly-Version, die die Plattform gerade bereitstellt, und wird auf eine neue Version neu gestartet, wenn die Plattform wechselt. Mit spec.image bestimmst du die Version und den Zeitpunkt von Upgrades selbst.

Die eingebaute tägliche Versionsprüfung von Dragonfly ist bei jeder Instanz abgeschaltet, weil sie Angaben über die Installation an den Hersteller schickt. Um sie wieder einzuschalten, ergänze --version_check=true in spec.args.

Backups ​

PostgreSQL und MariaDB können sich beide planmäßig sichern, in einen Bucket, der dir gehört. Ein Bucket wird nicht gestellt, das hier ist also etwas, das du einrichtest, und nichts, was du geerbt bekommst.

Wohin Backups gehen ​

Überallhin, wo S3 gesprochen wird. ITSH Object Storage funktioniert und ist der einfachste Weg: Leg einen Bucket und einen Zugangsschlüssel an und pack den Schlüssel in ein Secret in deinem Namespace.

Gib dem Schlüssel Lesen und Schreiben auf diesen Bucket. CloudNativePG listet den Bucket für seinen Backup-Katalog und löscht alte Backups, um die retentionPolicy durchzusetzen, und beides darf Nur Schreiben nicht.

bash
kubectl create secret generic backup-creds \
  --from-literal=ACCESS_KEY_ID='<access-key>' \
  --from-literal=ACCESS_SECRET_KEY='<secret-key>'

PostgreSQL ​

PostgreSQL-Backups laufen über das Barman Cloud Plugin. Beschreib das Ziel als ObjectStore, verweis im Cluster darauf und plane dann Basis-Backups:

yaml
apiVersion: barmancloud.cnpg.io/v1
kind: ObjectStore
metadata:
  name: app-db-backups
spec:
  configuration:
    destinationPath: "s3://my-backups/app-db"
    endpointURL: "https://storage.itsh.dev"
    s3Credentials:
      accessKeyId:
        name: backup-creds
        key: ACCESS_KEY_ID
      secretAccessKey:
        name: backup-creds
        key: ACCESS_SECRET_KEY
  retentionPolicy: "30d"
---
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
  name: app-db
spec:
  instances: 3
  storage:
    size: 10Gi
    storageClass: hcloud-volumes
  plugins:
    - name: barman-cloud.cloudnative-pg.io
      isWALArchiver: true
      parameters:
        barmanObjectName: app-db-backups
---
apiVersion: postgresql.cnpg.io/v1
kind: ScheduledBackup
metadata:
  name: app-db-daily
spec:
  schedule: "0 0 3 * * *"
  cluster:
    name: app-db
  method: plugin
  pluginConfiguration:
    name: barman-cloud.cloudnative-pg.io

Der Zeitplan ist ein sechsstelliger Cron-Ausdruck, Sekunden zuerst. Das Beispiel läuft also täglich um 03:00 Uhr.

Das Plugin fügt jeder Instanz einen Container hinzu

Es läuft als Sidecar in jedem Datenbank-Pod, und dieser Container zählt gegen dein Kontingent. Ohne eigene Werte bekommt er die Standardwerte deines Namespace (siehe Abrechnung und Kontingente). Setz sie unter spec.instanceSidecarConfiguration.resources am ObjectStore, wenn sie nicht passen. Im Free Tier setz sie in jedem Fall: Dort ist schon das Standardlimit für CPU das ganze CPU-Kontingent, ein Instanz-Pod mit einem Sidecar auf Standardwerten wird also abgelehnt.

Umstieg von barmanObjectStore ​

Cluster, die noch spec.backup.barmanObjectStore nutzen, laufen weiter, mit einer Deprecation-Warnung bei jedem Anwenden: CloudNativePG will das Feld entfernen. Der Umstieg behält die Backups, die du schon hast:

  1. Leg einen ObjectStore an, mit dem Inhalt von barmanObjectStore unter spec.configuration und demselben destinationPath, und verschieb retentionPolicy nach spec.retentionPolicy. Ein serverName gehört nicht dorthin: Setz ihn als Parameter serverName neben barmanObjectName.
  2. Entferne in einer einzigen Änderung am Cluster den Abschnitt backup und ergänze den plugins-Eintrag von oben. Die Instanzen starten dabei einmal neu.
  3. Ergänze in jedem ScheduledBackup method: plugin und die pluginConfiguration.

Mit demselben destinationPath übernimmt das Plugin die vorhandenen Backups und setzt die Aufbewahrung auch für sie weiter durch. Eine Wiederherstellung kommt also auch an Zeitpunkte vor dem Umstieg heran.

MariaDB ​

Backup- und Restore-Ressourcen funktionieren genauso und nehmen entweder ein S3-Ziel oder ein PVC. Der Feldaufbau steht in der Dokumentation des mariadb-operator.

Zwei Grenzen, die du kennen solltest ​

Object Versioning, Lifecycle-Regeln und Object-Lock gibt es bei ITSH Object Storage nicht. Backups lassen sich hier also nicht unveränderlich machen: Wer in den Bucket schreiben darf, kann sie auch löschen.

Gib Backups einen eigenen Bucket und einen darauf beschränkten Zugangsschlüssel, und halt diesen Schlüssel aus Workloads heraus, die ihn nicht brauchen. Sind unveränderliche Backups für dich zwingend, sprich vorher mit dem Support, bevor du dich auf dieses Setup verlässt.

Volume-Snapshots und Point-in-Time-Wiederherstellung von Volumes gibt es nicht. Backups laufen auf Datenbankebene und werden vom Operator erstellt. Für ein PVC, das keine verwaltete Datenbank ist, gibt es kein Äquivalent. Was dir in einem einfachen Volume wichtig ist, braucht also eine eigene Kopie woanders.

Teste die Wiederherstellung ​

Ein Backup, das nie jemand zurückgespielt hat, ist eine Vermutung. Spiel es einmal in einen Wegwerf-Cluster zurück, bevor du es brauchst, und prüf, ob die Daten wirklich da sind.

Wie es weitergeht ​