Beide Seiten der vorigen RevisionVorhergehende ÜberarbeitungNächste Überarbeitung | Vorhergehende Überarbeitung |
it-wiki:kubernetes:postgresql_mit_zalando_bereitstellen [2024/03/19 10:36] – [Zalando-Operator in Ihrem Cluster bereitstellen] marko | it-wiki:kubernetes:postgresql_mit_zalando_bereitstellen [2024/04/25 05:31] (aktuell) – marko |
---|
====== PostgreSQL mit Zalando in Kubernetes bereitstellen ====== | ====== PostgreSQL mit Zalando Operator in Kubernetes bereitstellen ====== |
In dieser Anleitung erfahren Sie, wie Sie mit dem [[https://github.com/zalando/postgres-operator|Zalando Postgres-Operator]] Postgres-Cluster in bereitstellen. | In dieser Anleitung erfahren Sie, wie Sie mit dem [[https://github.com/zalando/postgres-operator|Zalando Postgres-Operator]] Postgres-Cluster in bereitstellen. |
| |
* ''spec.volume'' sind die Parameter für den nichtflüchtigen Speicher | * ''spec.volume'' sind die Parameter für den nichtflüchtigen Speicher |
* ''spec.tolerations'' ist die Toleranz-Pod-Vorlage, mit der Cluster-Pods auf pool-postgres-Knoten geplant werden können | * ''spec.tolerations'' ist die Toleranz-Pod-Vorlage, mit der Cluster-Pods auf pool-postgres-Knoten geplant werden können |
* ''spec.nodeAffinity'' ist die Pod-Vorlage nodeAffinity, die GKE mitteilt, dass Cluster-Pods lieber auf pool-postgres-Knoten geplant werden sollen. | * ''spec.nodeAffinity'' ist die Pod-Vorlage nodeAffinity, die Kubernetes mitteilt, dass Cluster-Pods lieber auf pool-postgres-Knoten geplant werden sollen. |
* ''spec.resources'' sind Anfragen und Limits für Cluster-Pods | * ''spec.resources'' sind Anfragen und Limits für Cluster-Pods |
* ''spec.sidecars'' ist eine Liste der Sidecar-Container, die postgres-exporter enthält | * ''spec.sidecars'' ist eine Liste der Sidecar-Container, die postgres-exporter enthält |
| |
===== Einfachen Postgres-Cluster erstellen ===== | ===== Einfachen Postgres-Cluster erstellen ===== |
- Erstellen Sie mithilfe der grundlegenden Konfiguration einen neuen Postgres-Cluster: <code bash>kubectl apply -n postgres -f manifests/01-basic-cluster/my-cluster.yaml</code> Mit diesem Befehl wird eine benutzerdefinierte PostgreSQL-Ressource des Zalando-Operators erstellt: | - Erstellen Sie mithilfe der grundlegenden Konfiguration einen neuen Postgres-Cluster: <code bash>kubectl apply -n postgres -f manifests/01-basic-cluster/my-cluster.yaml</code> Mit diesem Befehl wird eine benutzerdefinierte PostgreSQL-Ressource des Zalando-Operators erstellt:\\ * CPU- und Speicheranforderungen und -limits\\ * Markierungen und Affinitäten zum Verteilen der bereitgestellten Pod-Replikate auf Kubernetes-Knoten.\\ * Eine Datenbank\\ * Zwei Nutzer mit Datenbankinhaberberechtigungen\\ * Ein Nutzer ohne Berechtigungen |
* CPU- und Speicheranforderungen und -limits | - Warten Sie, bis Kubernetes die erforderlichen Arbeitslasten gestartet hat: <code bash>kubectl wait pods -l cluster-name=my-cluster --for condition=Ready --timeout=300s -n postgres</code> Die Verarbeitung dieses Befehls kann einige Minuten dauern. |
* Markierungen und Affinitäten zum Verteilen der bereitgestellten Pod-Replikate auf GKE-Knoten. | - Prüfen Sie, ob Kubernetes die Postgres-Arbeitslasten erstellt hat: <code bash>kubectl get pod,svc,statefulset,deploy,pdb,secret -n postgres</code> Die Ausgabe sieht in etwa so aus: <code bash>NAME READY STATUS RESTARTS AGE |
* Eine Datenbank | pod/my-cluster-0 1/1 Running 0 6m41s |
* Zwei Nutzer mit Datenbankinhaberberechtigungen | pod/my-cluster-1 1/1 Running 0 5m56s |
* Ein Nutzer ohne Berechtigungen | pod/my-cluster-2 1/1 Running 0 5m16s |
| pod/postgres-operator-db9667d4d-rgcs8 1/1 Running 0 12m |
| |
- Warten Sie, bis Kubernetes die erforderlichen Arbeitslasten gestartet hat: <code bash>kubectl wait pods -l cluster-name=my-cluster --for condition=Ready --timeout=300s -n postgres</code> Die Verarbeitung dieses Befehls kann einige Minuten dauern. | NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE |
- | service/my-cluster ClusterIP 10.52.12.109 <none> 5432/TCP 6m43s |
| service/my-cluster-config ClusterIP None <none> <none> 5m55s |
| service/my-cluster-repl ClusterIP 10.52.6.152 <none> 5432/TCP 6m43s |
| service/postgres-operator ClusterIP 10.52.8.176 <none> 8080/TCP 12m |
| |
| NAME READY AGE |
| statefulset.apps/my-cluster 3/3 6m43s |
| |
| NAME READY UP-TO-DATE AVAILABLE AGE |
| deployment.apps/postgres-operator 1/1 1 1 12m |
| |
| NAME MIN AVAILABLE MAX UNAVAILABLE ALLOWED DISRUPTIONS AGE |
| poddisruptionbudget.policy/postgres-my-cluster-pdb 1 N/A 0 6m44s |
| |
| NAME TYPE DATA AGE |
| secret/my-user.my-cluster.credentials.postgresql.acid.zalan.do Opaque 2 6m45s |
| secret/postgres.my-cluster.credentials.postgresql.acid.zalan.do Opaque 2 6m44s |
| secret/sh.helm.release.v1.postgres-operator.v1 helm.sh/release.v1 1 12m |
| secret/standby.my-cluster.credentials.postgresql.acid.zalan.do Opaque 2 6m44s |
| secret/zalando.my-cluster.credentials.postgresql.acid.zalan.do Opaque 2 6m44s</code> |
| |
| Der Operator erstellt die folgenden Ressourcen: |
| * Ein Postgres-StatefulSet, das drei Pod-Replikate für Postgres steuert |
| * Einen ''PodDisruptionBudgets'', wodurch mindestens ein verfügbares Replikat garantiert wird |
| * Den ''my-cluster''-Dienst, der nur auf das Leader-Replikat ausgerichtet ist |
| * Den ''my-cluster-repl''-Dienst, der den Postgres-Port für eingehende Verbindungen und für die Replikation zwischen Postgres-Replikaten verfügbar macht |
| * Den monitorlosen Dienst ''my-cluster-config'' zum Abrufen der Liste der laufenden Postgres-Pod-Replikate |
| * Secrets mit Nutzeranmeldedaten für den Zugriff auf die Datenbank und die Replikation zwischen Postgres-Knoten |
| |
| ===== Bei Postgres authentifizieren ===== |
| Sie können Postgres-Nutzer erstellen und ihnen Datenbankberechtigungen zuweisen. Das folgende Manifest beschreibt beispielsweise eine benutzerdefinierte Ressource, die Nutzer und Rollen zuweist: |
| <code yaml> |
| apiVersion: "acid.zalan.do/v1" |
| kind: postgresql |
| metadata: |
| name: my-cluster |
| spec: |
| ... |
| users: |
| mydatabaseowner: |
| - superuser |
| - createdb |
| myuser: [] |
| databases: |
| mydatabase: mydatabaseowner |
| </code> |
| |
| In diesem Manifest: |
| * Der ''mydatabaseowner''-Nutzer hat die Rollen [[https://www.postgresql.org/docs/16/sql-createrole.html|SUPERUSER und CREATEDB]], die uneingeschränkte Administratorrechte gewähren (Verwaltung der Postgres-Konfiguration, neue Datenbanken, Tabellen und Nutzer erstellen, usw). |
| * Dem Nutzer ''myuser'' wurden keine Rollen zugewiesen. Dies folgt der [[https://wiki.postgresql.org/wiki/Client_Authentication|Best Practice]] zur Verwendung von ''SUPERUSER'', um Nutzer mit den geringsten Berechtigungen zu erstellen. Detaillierte Rechte werden ''myuser'' von ''mydatabaseowner'' gewährt. Aus Sicherheitsgründen sollten Sie ''myuser''-Anmeldedaten nur für Clientanwendungen freigeben. |
| |
| ===== Passwörter speichern ===== |
| Verwenden Sie die [[https://www.postgresql.org/docs/current/auth-password.html|empfohlene Methode zum Speichern von Passwörtern]] ''scram-sha-256''. Das folgende Manifest beschreibt beispielsweise eine benutzerdefinierte Ressource, die die ''scram-sha-256''-Verschlüsselung mit dem Feld ''postgresql.parameters.password_encryption'' angibt: |
| <code yaml> |
| apiVersion: "acid.zalan.do/v1" |
| kind: postgresql |
| metadata: |
| name: my-cluster |
| spec: |
| ... |
| postgresql: |
| parameters: |
| password_encryption: scram-sha-256 |
| </code> |
| |
| ===== Nutzeranmeldedaten rotieren ===== |
| Sie können [[https://postgres-operator.readthedocs.io/en/latest/administrator/#password-rotation-in-k8s-secrets|Nutzeranmeldedaten rotieren]], die in Kubernetes-Secrets mit Zalando gespeichert sind. Das folgende Manifest beschreibt beispielsweise eine benutzerdefinierte Ressource, die die Rotation von Nutzeranmeldedaten mithilfe des Felds ''usersWithSecretRotation'' definiert: |
| <code yaml> |
| apiVersion: "acid.zalan.do/v1" |
| kind: postgresql |
| metadata: |
| name: my-cluster |
| spec: |
| ... |
| usersWithSecretRotation: |
| - myuser |
| - myanotheruser |
| - ... |
| </code> |
| |
| ===== Authentifizierungsbeispiel: Verbindung zu Postgres herstellen ===== |
| In diesem Abschnitt erfahren Sie, wie Sie einen Postgres-Beispielclient bereitstellen und mit dem Passwort aus einem Kubernetes-Secret eine Verbindung zur Datenbank herstellen. |
| - Führen Sie den Client-Pod aus, um mit Ihrem Postgres-Cluster zu interagieren: <code bash>kubectl apply -n postgres -f manifests/02-auth/client-pod.yaml</code> Die Anmeldedaten der Nutzer myuser und mydatabaseowner werden aus den zugehörigen Secrets übernommen und als Umgebungsvariablen im Pod bereitgestellt. |
| - Stellen Sie eine Verbindung zum Pod her, wenn er bereit ist: <code bash>kubectl wait pod postgres-client --for=condition=Ready --timeout=300s -n postgres |
| kubectl exec -it postgres-client -n postgres -- /bin/bash</code> |
| - Stellen Sie eine Verbindung zu Postgres her und versuchen Sie, eine neue Tabelle mit den myuser-Anmeldedaten zu erstellen: <code bash>PGPASSWORD=$CLIENTPASSWORD psql \ |
| -h my-cluster \ |
| -U $CLIENTUSERNAME \ |
| -d mydatabase \ |
| -c "CREATE TABLE test (id serial PRIMARY KEY, randomdata VARCHAR ( 50 ) NOT NULL);"</code> Der Befehl sollte mit einem Fehler wie diesem fehlschlagen: <code bash>ERROR: permission denied for schema public |
| LINE 1: CREATE TABLE test (id serial PRIMARY KEY, randomdata VARCHAR...</code> Der Befehl schlägt fehl, da sich Nutzer ohne zugewiesene Berechtigungen standardmäßig nur bei Postgres anmelden und Datenbanken auflisten können. |
| - Erstellen Sie eine Tabelle mit ''mydatabaseowner''-Anmeldedaten und gewähren Sie ''myuser'' **alle** Berechtigungen für die Tabelle: <code bash>PGPASSWORD=$OWNERPASSWORD psql \ |
| -h my-cluster \ |
| -U $OWNERUSERNAME \ |
| -d mydatabase \ |
| -c "CREATE TABLE test (id serial PRIMARY KEY, randomdata VARCHAR ( 50 ) NOT NULL);GRANT ALL ON test TO myuser;GRANT ALL ON SEQUENCE test_id_seq TO myuser;" </code> Die Ausgabe sieht in etwa so aus: <code bash>CREATE TABLE |
| GRANT |
| GRANT </code> |
| - Fügen Sie zufällige Daten mit den Anmeldedaten myuser in die Tabelle ein: <code bash>for i in {1..10}; do |
| DATA=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 13) |
| PGPASSWORD=$CLIENTPASSWORD psql \ |
| -h my-cluster \ |
| -U $CLIENTUSERNAME \ |
| -d mydatabase \ |
| -c "INSERT INTO test(randomdata) VALUES ('$DATA');" |
| done</code> Die Ausgabe sieht in etwa so aus: <code bash>INSERT 0 1 |
| INSERT 0 1 |
| INSERT 0 1 |
| INSERT 0 1 |
| INSERT 0 1 |
| INSERT 0 1 |
| INSERT 0 1 |
| INSERT 0 1 |
| INSERT 0 1 |
| INSERT 0 1</code> |
| - Rufen Sie die eingefügten Werte ab: <code bash>PGPASSWORD=$CLIENTPASSWORD psql \ |
| -h my-cluster \ |
| -U $CLIENTUSERNAME \ |
| -d mydatabase \ |
| -c "SELECT * FROM test;"</code> Die Ausgabe sieht in etwa so aus: <code bash>id | randomdata |
| ----+--------------- |
| 1 | jup9HYsAjwtW4 |
| 2 | 9rLAyBlcpLgNT |
| 3 | wcXSqxb5Yz75g |
| 4 | KoDRSrx3muD6T |
| 5 | b9atC7RPai7En |
| 6 | 20d7kC8E6Vt1V |
| 7 | GmgNxaWbkevGq |
| 8 | BkTwFWH6hWC7r |
| 9 | nkLXHclkaqkqy |
| 10 | HEebZ9Lp71Nm3 |
| (10 rows)</code> |
| - Beenden Sie die Pod-Shell: <code bash>exit</code> |