Benutzer-Werkzeuge

Webseiten-Werkzeuge


it-wiki:kubernetes:postgresql_mit_zalando_bereitstellen

Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen angezeigt.

Link zu dieser Vergleichsansicht

Beide Seiten der vorigen RevisionVorhergehende Überarbeitung
Nächste Überarbeitung
Vorhergehende Überarbeitung
it-wiki:kubernetes:postgresql_mit_zalando_bereitstellen [2024/03/19 10:17] – [Bereitstellungsarchitektur] markoit-wiki:kubernetes:postgresql_mit_zalando_bereitstellen [2024/04/25 05:31] (aktuell) marko
Zeile 1: Zeile 1:
-====== 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.
  
Zeile 34: Zeile 34:
   - Erstellen Sie einen Namespace für den Zalando-Operator und den Postgres-Cluster: <code bash>kubectl create ns postgres   - Erstellen Sie einen Namespace für den Zalando-Operator und den Postgres-Cluster: <code bash>kubectl create ns postgres
 kubectl create ns zalando</code> kubectl create ns zalando</code>
 +  - Stellen Sie den Zalando-Operator mit dem Helm-Befehlszeilentool bereit: <code bash>helm install postgres-operator postgres-operator-charts/postgres-operator -n zalando \
 +    --set configKubernetes.enable_pod_antiaffinity=true \
 +    --set configKubernetes.pod_antiaffinity_preferred_during_scheduling=true \
 +    --set configKubernetes.pod_antiaffinity_topology_key="topology.kubernetes.io/zone" \
 +    --set configKubernetes.spilo_fsgroup="103"</code> Sie können die ''podAntiAffinity''-Einstellungen nicht direkt für die benutzerdefinierte Ressource konfigurieren, die den Postgres-Cluster darstellt. Legen Sie stattdessen global die ''podAntiAffinity''-Einstellungen für alle Postgres-Cluster in den Operatoreinstellungen fest.
 +  - Prüfen Sie den Bereitstellungsstatus des Zalando-Operators mit Helm: <code bash>helm ls -n zalando</code> Die Ausgabe sieht in etwa so aus: <code bash>NAME                 NAMESPACE    REVISION    UPDATED                                STATUS      CHART                       APP VERSION
 +postgres-operator    zalando               2023-10-13 16:04:13.945614 +0200 CEST    deployed    postgres-operator-1.10.1    1.10.1</code>
 +
 +===== Postgres bereitstellen =====
 +Die grundlegende Konfiguration für die Postgres-Clusterinstanz umfasst die folgenden Komponenten:
 +  * Drei Postgres-Replikate: ein Leader und zwei Standby-Replikate.
 +  * CPU-Ressourcenzuweisung: eine CPU-Anfrage und zwei CPU-Limits mit 4 GB Speicheranfragen und -Limits.
 +  * Toleranzen, nodeAffinities und topologySpreadConstraints, die für jede Arbeitslast konfiguriert sind und eine ordnungsgemäße Verteilung auf Kubernetes-Knoten mithilfe ihrer jeweiligen Knotenpools und verschiedenen Verfügbarkeitszonen gewährleisten.
 +
 +Diese Konfiguration stellt die minimale Einrichtung dar, die zum Erstellen eines produktionsfertigen Postgres-Clusters erforderlich ist.
 +
 +Das folgende Manifest beschreibt einen Postgres-Cluster:
 +[[https://github.com/GoogleCloudPlatform/kubernetes-engine-samples/blob/HEAD/databases/postgres-zalando/manifests/01-basic-cluster/my-cluster.yaml|databases/postgres-zalando/manifests/01-basic-cluster/my-cluster.yaml]]
 +<code yaml>
 +apiVersion: "acid.zalan.do/v1"
 +kind: postgresql
 +metadata:
 +  name: my-cluster
 +spec:
 +  dockerImage: ghcr.io/zalando/spilo-15:3.0-p1
 +  teamId: "my-team"
 +  numberOfInstances: 3
 +  users:
 +    mydatabaseowner:
 +    - superuser
 +    - createdb
 +    myuser: []
 +  databases:
 +    mydatabase: mydatabaseowner
 +  postgresql:
 +    version: "15"
 +    parameters:
 +      shared_buffers: "32MB"
 +      max_connections: "10"
 +      log_statement: "all"
 +      password_encryption: scram-sha-256
 +  volume:
 +    size: 5Gi
 +    storageClass: premium-rwo
 +  enableShmVolume: true
 +  podAnnotations:
 +    cluster-autoscaler.kubernetes.io/safe-to-evict: "true"
 +  tolerations:
 +  - key: "app.stateful/component"
 +    operator: "Equal"
 +    value: "postgres-operator"
 +    effect: NoSchedule
 +  nodeAffinity:
 +    preferredDuringSchedulingIgnoredDuringExecution:
 +    - weight: 1
 +      preference:
 +        matchExpressions:
 +        - key: "app.stateful/component"
 +          operator: In
 +          values:
 +          - "postgres-operator"
 +  resources:
 +    requests:
 +      cpu: "1"
 +      memory: 4Gi
 +    limits:
 +      cpu: "2"
 +      memory: 4Gi
 +  sidecars:
 +    - name: exporter
 +      image: quay.io/prometheuscommunity/postgres-exporter:v0.14.0
 +      args:
 +      - --collector.stat_statements
 +      ports:
 +      - name: exporter
 +        containerPort: 9187
 +        protocol: TCP
 +      resources:
 +        limits:
 +          cpu: 500m
 +          memory: 256M
 +        requests:
 +          cpu: 100m
 +          memory: 256M
 +      env:
 +      - name: "DATA_SOURCE_URI"
 +        value: "localhost/postgres?sslmode=require"
 +      - name: "DATA_SOURCE_USER"
 +        value: "$(POSTGRES_USER)"
 +      - name: "DATA_SOURCE_PASS"
 +        value: "$(POSTGRES_PASSWORD)"
 +</code>
 +
 +Dieses Manifest hat die folgenden Felder:
 +  * ''spec.teamId'' ist ein Präfix für die von Ihnen ausgewählten Clusterobjekte
 +  * ''spec.numberOfInstances'' ist die Gesamtzahl der Instanzen für einen Cluster
 +  * ''spec.users'' ist die Nutzerliste mit [[https://www.postgresql.org/docs/current/sql-createrole.html|Berechtigungen]]
 +  * ''spec.databases'' ist die Datenbankliste im Format dbname: ownername
 +  * ''spec.postgresql'' sind die Postgres-Parameter
 +  * ''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.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.sidecars'' ist eine Liste der Sidecar-Container, die postgres-exporter enthält
 +
 +Weitere Informationen finden Sie in der Postgres-Dokumentation unter [[https://postgres-operator.readthedocs.io/en/latest/reference/cluster_manifest/|Referenz zu Clustermanifesten]].
 +
 +===== 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:\\  * 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
 +  - 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.
 +  - 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
 +pod/my-cluster-0                        1/1     Running           6m41s
 +pod/my-cluster-1                        1/1     Running           5m56s
 +pod/my-cluster-2                        1/1     Running           5m16s
 +pod/postgres-operator-db9667d4d-rgcs8   1/    Running           12m
 +
 +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/  6m43s
 +
 +NAME                                READY   UP-TO-DATE   AVAILABLE   AGE
 +deployment.apps/postgres-operator   1/                        12m
 +
 +NAME                                                MIN AVAILABLE   MAX UNAVAILABLE   ALLOWED DISRUPTIONS   AGE
 +poddisruptionbudget.policy/postgres-my-cluster-pdb                N/A                               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        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>
it-wiki/kubernetes/postgresql_mit_zalando_bereitstellen.1710843440.txt.gz · Zuletzt geändert: von marko