Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Ein Überblick über den Percona XtraDB Cluster Kubernetes Operator

Wenn Sie in der Containerwelt unterwegs waren, wissen Sie, dass es eine ziemliche Herausforderung ist, eine vollständige Kubernetes-Automatisierung für ein geclustertes Datenbanksystem zu übernehmen, was der Container-basierten üblicherweise ein gewisses Maß an Komplexität hinzufügt Architektur für diese zustandsbehafteten Anwendungen. Hier kann uns ein Kubernetes-Operator helfen, dieses Problem anzugehen. Ein Kubernetes-Operator ist eine spezielle Art von Controller, der eingeführt wurde, um komplexe Bereitstellungen zu vereinfachen und die Kubernetes-API im Grunde um benutzerdefinierte Ressourcen erweitert. Es baut auf den grundlegenden Kubernetes-Ressourcen- und Controller-Konzepten auf, enthält jedoch domänen- oder anwendungsspezifisches Wissen, um den gesamten Lebenszyklus der von ihm verwalteten Software zu automatisieren.

Percona XtraDB Cluster Operator ist eine nette Möglichkeit, die spezifischen Aufgaben von Percona XtraDB Cluster wie Bereitstellung, Skalierung, Backups und Upgrades innerhalb von Kubernetes zu automatisieren, das von Percona erstellt und verwaltet wird. Es stellt den Cluster in einem StatefulSet mit einem Persistent Volume bereit, wodurch wir eine konsistente Identität für jeden Pod im Cluster und unsere Daten beibehalten können.

In diesem Blogbeitrag werden wir die Bereitstellung von Percona XtraDB Cluster 8.0 in einer containerisierten Umgebung testen, die von Percona XtraDB Cluster Kubernetes Operator auf der Google Cloud Platform orchestriert wird.

Erstellen eines Kubernetes-Clusters in Google Cloud

In dieser exemplarischen Vorgehensweise verwenden wir den Kubernetes-Cluster in Google Cloud, da es relativ einfach ist, Kubernetes zum Laufen zu bringen. Melden Sie sich bei Ihrem Google Cloud Platform-Dashboard an -> Compute -> Kubernetes Engine -> Cluster erstellen, und Ihnen wird das folgende Dialogfeld angezeigt:

Geben Sie einfach den Namen des Kubernetes-Clusters ein, wählen Sie Ihre bevorzugte Zone aus und klicken Sie auf „CREATE " (am Ende der Seite). In 5 Minuten ist ein Kubernetes-Cluster mit 3 Knoten fertig. Installieren Sie nun auf Ihrer Workstation das gcloud SDK wie in dieser Anleitung gezeigt und ziehen Sie dann die Kubernetes-Konfiguration auf Ihre Workstation:

$ gcloud container clusters get-credentials my-k8s-cluster --zone asia-northeast1-a --project s9s-qa
Fetching cluster endpoint and auth data.
kubeconfig entry generated for my-k8s-cluster.

Sie sollten jetzt eine Verbindung zum Kubernetes-Cluster herstellen können. Führen Sie zur Überprüfung den folgenden Befehl aus:

$ kubectl get nodes
NAME                                            STATUS   ROLES    AGE    VERSION
gke-my-k8s-cluster-default-pool-b80902cd-gp09   Ready    <none>   139m   v1.16.13-gke.401
gke-my-k8s-cluster-default-pool-b80902cd-jdc3   Ready    <none>   139m   v1.16.13-gke.401
gke-my-k8s-cluster-default-pool-b80902cd-rdv8   Ready    <none>   139m   v1.16.13-gke.401

Die obige Ausgabe bedeutet, dass wir uns mit dem Kubernetes-Master verbinden und die Kubernetes-Clusterknoten abrufen können. Jetzt sind wir bereit, die Kubernetes-Workloads auszuführen.

Bereitstellen eines Percona XtraDB-Clusters auf Kubernetes

Für die Workload-Bereitstellung befolgen wir die Anweisungen in der Percona XtraDB Cluster Operator-Dokumentation. Grundsätzlich führen wir den folgenden Befehl auf unserer Workstation aus, um die benutzerdefinierten Ressourcen, den Namespace, die rollenbasierte Zugriffskontrolle und auch den Kubernetes-Operator selbst zu erstellen:

$ git clone -b v1.6.0 https://github.com/percona/percona-xtradb-cluster-operator
$ cd percona-xtradb-cluster-operator/
$ kubectl apply -f deploy/crd.yaml
$ kubectl create namespace pxc
$ kubectl config set-context $(kubectl config current-context) --namespace=pxc
$ kubectl create clusterrolebinding cluster-admin-binding --clusterrole=cluster-admin --user=$(gcloud config get-value core/account)
$ kubectl apply -f deploy/rbac.yaml
$ kubectl apply -f deploy/operator.yaml

Als Nächstes müssen wir unsere Passwörter (im Kubernetes-Begriff „Secrets“ genannt) vorbereiten, indem wir die Werte in der Datei „deploy/secrets.yaml“ in einem base64-codierten Format aktualisieren. Sie können Online-Tools wie https://www.base64encode.org/ verwenden, um eine zu erstellen, oder ein Befehlszeilentool wie das folgende verwenden:

$ echo -n 'mypassword' | base64
bXlwYXNzd29yZA==

Aktualisieren Sie dann die Datei deploy/secrets.yaml wie unten gezeigt:

apiVersion: v1
kind: Secret
metadata:
  name: my-cluster-secrets
type: Opaque
data:
  root: bXlwYXNzd29yZA==
  xtrabackup: bXlwYXNzd29yZA==
  monitor: bXlwYXNzd29yZA==
  clustercheck: bXlwYXNzd29yZA==
  proxyadmin: bXlwYXNzd29yZA==
  pmmserver: bXlwYXNzd29yZA==
  operator: bXlwYXNzd29yZA==

Das Obige ist eine super Vereinfachung der geheimen Verwaltung, bei der wir alle Passwörter so einstellen, dass sie für alle Benutzer gleich sind. Bitte verwenden Sie in der Produktion ein komplexeres Passwort und legen Sie für jeden Benutzer ein anderes Passwort fest.

Jetzt können wir die geheime Konfiguration an Kubernetes übertragen:

$ kubectl apply -f deploy/secrets.yaml

Bevor wir mit der Bereitstellung eines Percona XtraDB-Clusters fortfahren, müssen wir die Standardbereitstellungsdefinition in deploy/cr.yaml für den Cluster erneut aufrufen. Es gibt viele Kubernetes-Objekte, die hier definiert sind, aber die meisten von ihnen sind auskommentiert. Für unsere Arbeitslast würden wir die Änderung wie folgt vornehmen:

$ cat deploy/cr.yaml
apiVersion: pxc.percona.com/v1-6-0
kind: PerconaXtraDBCluster
metadata:
  name: cluster1
  finalizers:
    - delete-pxc-pods-in-order
spec:
  crVersion: 1.6.0
  secretsName: my-cluster-secrets
  vaultSecretName: keyring-secret-vault
  sslSecretName: my-cluster-ssl
  sslInternalSecretName: my-cluster-ssl-internal
  allowUnsafeConfigurations: false
  updateStrategy: SmartUpdate
  upgradeOptions:
    versionServiceEndpoint: https://check.percona.com
    apply: recommended
    schedule: "0 4 * * *"
  pxc:
    size: 3
    image: percona/percona-xtradb-cluster:8.0.20-11.1
    configuration: |
      [client]
      default-character-set=utf8

      [mysql]
      default-character-set=utf8

      [mysqld]
      collation-server = utf8_unicode_ci
      character-set-server = utf8
      default_authentication_plugin = mysql_native_password
    resources:
      requests:
        memory: 1G
    affinity:
      antiAffinityTopologyKey: "kubernetes.io/hostname"
    podDisruptionBudget:
      maxUnavailable: 1
    volumeSpec:
      persistentVolumeClaim:
        resources:
          requests:
            storage: 6Gi
    gracePeriod: 600
  haproxy:
    enabled: true
    size: 3
    image: percona/percona-xtradb-cluster-operator:1.6.0-haproxy
    resources:
      requests:
        memory: 1G
    affinity:
      antiAffinityTopologyKey: "kubernetes.io/hostname"
    podDisruptionBudget:
      maxUnavailable: 1
    gracePeriod: 30
  backup:
    image: percona/percona-xtradb-cluster-operator:1.6.0-pxc8.0-backup
    storages:
      fs-pvc:
        type: filesystem
        volume:
          persistentVolumeClaim:
            accessModes: [ "ReadWriteOnce" ]
            resources:
              requests:
                storage: 6Gi
    schedule:
      - name: "daily-backup"
        schedule: "0 0 * * *"
        keep: 5
        storageName: fs-pvc

Wir haben einige Änderungen an der bereitgestellten cr.yaml vorgenommen, damit sie mit unserer Anwendung funktioniert, wie oben gezeigt. Zunächst müssen wir alle CPU-bezogenen Zeilen auskommentieren (oder entfernen), zum Beispiel [*].resources.requests.cpu:600m, um sicherzustellen, dass Kubernetes in der Lage ist, die Pod-Erstellung auf Knoten mit begrenzter CPU korrekt zu planen. Dann müssen wir einige Kompatibilitätsoptionen für Percona XtraDB Cluster 8.0 hinzufügen, das auf MySQL 8.0 basiert, um reibungslos mit unserer WordPress-Anwendung zu arbeiten, die wir später bereitstellen werden, wie im folgenden Auszug gezeigt:

   configuration: |
      [client]
      default-character-set=utf8

      [mysql]
      default-character-set=utf8

      [mysqld]
      collation-server = utf8_unicode_ci
      character-set-server = utf8
      default_authentication_plugin = mysql_native_password

Das obige entspricht dem Standardzeichensatz des MySQL-Servers mit dem MySQLi-PHP-Treiber in unserem WordPress-Container. Der nächste Abschnitt ist die HAProxy-Bereitstellung, wo sie auf „enabled:true“ gesetzt ist. Es gibt auch einen ProxySQL-Abschnitt mit "enabled:false" - normalerweise würde man für jeden Cluster einen der Reverse-Proxys auswählen. Der letzte Abschnitt ist die Backup-Konfiguration, bei der wir gerne ein tägliches Backup um 12:00 Uhr planen und die letzten 5 Backups aufbewahren möchten.

Wir können jetzt mit der Bereitstellung unseres 3-Knoten-Percona-XtraDB-Clusters beginnen:

$ kubectl apply -f deploy/cr.yaml

Der Erstellungsprozess wird einige Zeit in Anspruch nehmen. Der Betreiber stellt die Percona XtraDB-Cluster-Pods als Stateful Set bereit, was bedeutet, dass jeweils ein Pod erstellt wird, und jedem Pod im StatefulSet wird eine ganzzahlige Ordnungszahl von 0 bis N-1 zugewiesen, die für das Set eindeutig ist. Der Vorgang ist beendet, wenn sowohl der Bediener als auch die Pods ihren Status „Wird ausgeführt“ erreicht haben:

$ kubectl get pods
NAME                                               READY   STATUS    RESTARTS   AGE
cluster1-haproxy-0                                 2/2     Running   0          71m
cluster1-haproxy-1                                 2/2     Running   0          70m
cluster1-haproxy-2                                 2/2     Running   0          70m
cluster1-pxc-0                                     1/1     Running   0          71m
cluster1-pxc-1                                     1/1     Running   0          70m
cluster1-pxc-2                                     1/1     Running   0          69m
percona-xtradb-cluster-operator-79d786dcfb-6clld   1/1     Running   0          121m

Da dieser Operator eine benutzerdefinierte Ressource ist, können wir die perconaxtradbcluster-Ressource so manipulieren, dass sie der standardmäßigen Kubernetes-Ressource ähnelt:

$ kubectl get perconaxtradbcluster
NAME       ENDPOINT               STATUS   PXC   PROXYSQL   HAPROXY   AGE
cluster1   cluster1-haproxy.pxc   ready    3                3         27h

Sie können auch den kürzeren Ressourcennamen "pxc" verwenden und es mit den folgenden Befehlen versuchen:

$ kubectl describe pxc
$ kubectl edit pxc

Wenn wir uns das Workload-Set ansehen, können wir feststellen, dass der Operator zwei StatefulSets erstellt hat:

$ kubectl get statefulsets -o wide
NAME               READY   AGE   CONTAINERS          IMAGES
cluster1-haproxy   3/3     26h   haproxy,pxc-monit   percona/percona-xtradb-cluster-operator:1.6.0-haproxy,percona/percona-xtradb-cluster-operator:1.6.0-haproxy
cluster1-pxc       3/3     26h   pxc                 percona/percona-xtradb-cluster:8.0.20-11.2

Der Betreiber erstellt auch die entsprechenden Dienste, die Verbindungen zu den jeweiligen Pods mit Lastenausgleich herstellen:

$ kubectl get service
NAME                        TYPE           CLUSTER-IP     EXTERNAL-IP     PORT(S)                       AGE
cluster1-haproxy            ClusterIP      10.40.9.177    <none>          3306/TCP,3309/TCP,33062/TCP   3h27m
cluster1-haproxy-replicas   ClusterIP      10.40.0.236    <none>          3306/TCP                      3h27m
cluster1-pxc                ClusterIP      None           <none>          3306/TCP,33062/TCP            3h27m
cluster1-pxc-unready        ClusterIP      None           <none>          3306/TCP,33062/TCP            3h27m

Die obige Ausgabe zeigt, dass der Operator 4 Dienste erstellt hat:

  • cluster1-haproxy - Der Dienst für einen lastverteilten MySQL Single-Master (3306), Proxy-Protokoll (3309) und MySQL Admin (33062) - Ein neuer administrativer Port, der in MySQL 8.0.14 und höher eingeführt wurde. Dies ist der Dienstname oder die Cluster-IP-Adresse, die die Anwendungen benötigen, um eine Verbindung herzustellen, um eine Single-Master-Verbindung zum Galera-Cluster herzustellen.
  • cluster1-haproxy-replicas - Der Dienst für einen lastverteilten MySQL-Multimaster (3306). Dies ist der Dienstname oder die Cluster-IP-Adresse, die die Anwendungen verbinden müssen, um eine Multi-Master-Verbindung zum Galera-Cluster mit Round-Robin-Balancing-Algorithmus herzustellen.
  • cluster1-pxc - Der Dienst für lastausgeglichene PXC-Pods unter Umgehung von HAProxy. Durch die direkte Verbindung mit diesem Dienst leitet Kubernetes die Verbindung im Round-Robin-Verfahren an alle PXC-Pods weiter, ähnlich wie Cluster-Haproxy-Replicase bietet. Dem Dienst ist keine öffentliche IP-Adresse zugewiesen und er ist außerhalb des Clusters nicht verfügbar.
  • cluster1-pxc-unbereit - Der „nicht bereit“-Dienst wird für die Erkennung der Pod-Adresse während des Anwendungsstarts benötigt, unabhängig vom Pod-Status. Proxysql- und pxc-Pods sollten voneinander wissen, bevor die Datenbank voll funktionsfähig ist. Dem nicht bereiten Dienst ist keine öffentliche IP-Adresse zugewiesen und er ist außerhalb des Clusters nicht verfügbar.

Um sich über einen MySQL-Client zu verbinden, führen Sie einfach den folgenden Befehl aus:

$ kubectl run -i --rm --tty percona-client --image=percona:8.0 --restart=Never -- bash -il

Dies erstellt einen transienten Pod und tritt sofort in die Containerumgebung ein. Führen Sie dann den standardmäßigen mysql-Client-Befehl mit den richtigen Anmeldeinformationen aus:

bash-4.2$ mysql -uroot -pmypassword -h cluster1-haproxy -P3306 -e 'SELECT @@hostname'
mysql: [Warning] Using a password on the command line interface can be insecure.
+----------------+
| @@hostname     |
+----------------+
| cluster1-pxc-0 |
+----------------+

Wenn wir uns die Pod-Platzierung ansehen, befinden sich alle Percona XtraDB-Cluster-Pods auf einem anderen Kubernetes-Host:

$ kubectl get pods -o wide --selector=app.kubernetes.io/component=pxc
NAME             READY   STATUS    RESTARTS   AGE   IP           NODE                                            NOMINATED NODE   READINESS GATES
cluster1-pxc-0   1/1     Running   0          67m   10.36.2.5    gke-my-k8s-cluster-default-pool-b80902cd-gp09   <none>           <none>
cluster1-pxc-1   1/1     Running   0          66m   10.36.1.10   gke-my-k8s-cluster-default-pool-b80902cd-rdv8   <none>           <none>
cluster1-pxc-2   1/1     Running   0          65m   10.36.0.11   gke-my-k8s-cluster-default-pool-b80902cd-jdc3   <none>           <none>

Dies verbessert definitiv die Verfügbarkeit des Dienstes, falls einer der Kubernetes-Hosts ausfällt.

Um auf bis zu 5 Pods zu skalieren, müssen wir vorher 2 weitere neue Kubernetes-Knoten vorbereiten, um die Pod-Affinitätskonfiguration zu berücksichtigen (standardmäßig affinity.antiAffinityTopologyKey.topologyKey="kubernetes.io/hostname"). Führen Sie dann den folgenden Patch-Befehl aus, um den Percona XtraDB-Cluster auf 5 Knoten zu skalieren:

$ kubectl patch pxc cluster1 \
--type='json' -p='[{"op": "replace", "path": "/spec/pxc/size", "value": 5 }]'

Überwachen Sie die Erstellung des Pods mit dem Befehl kubectl get pods:

$ kubectl get pods -o wide
NAME               READY   STATUS      RESTARTS   AGE   IP           NODE                                            NOMINATED NODE   READINESS GATES
cluster1-pxc-0     1/1     Running     0          27h   10.36.2.5    gke-my-k8s-cluster-default-pool-b80902cd-gp09   <none>           <none>
cluster1-pxc-1     1/1     Running     0          27h   10.36.1.10   gke-my-k8s-cluster-default-pool-b80902cd-rdv8   <none>           <none>
cluster1-pxc-2     1/1     Running     0          27h   10.36.0.11   gke-my-k8s-cluster-default-pool-b80902cd-jdc3   <none>           <none>
cluster1-pxc-3     1/1     Running     0          30m   10.36.7.2    gke-my-k8s-cluster-pool-1-ab14a45e-h1pf         <none>           <none>
cluster1-pxc-4     1/1     Running     0          13m   10.36.5.3    gke-my-k8s-cluster-pool-1-ab14a45e-01qn         <none>           <none>

Weitere 2 neue Pods (cluster1-pxc-3 und cluster1-pxc-4) wurden auf weiteren 2 neuen Kubernetes-Knoten (gke-my-k8s-cluster-pool-1-ab14a45e-h1pf und gke-my-k8s-cluster-pool-1-ab14a45e-01qn). Zum Verkleinern ändern Sie einfach den Wert im obigen Patch-Befehl zurück auf 3. Beachten Sie, dass der Percona XtraDB-Cluster mit einer ungeraden Anzahl von Knoten ausgeführt werden sollte, um Split-Brain zu verhindern.

Bereitstellen einer Anwendung (WordPress)

In diesem Beispiel werden wir eine WordPress-Anwendung auf unserem Percona XtraDB-Cluster und HAProxy bereitstellen. Bereiten wir zuerst die YAML-Definitionsdatei wie folgt vor:

$ cat wordpress-deployment.yaml
apiVersion: v1
kind: Service
metadata:
  name: wordpress
  labels:
    app: wordpress
spec:
  ports:
    - port: 80
  selector:
    app: wordpress
    tier: frontend
  type: LoadBalancer
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: wp-pv-claim
  labels:
    app: wordpress
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 2Gi
---
apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
  name: wordpress
  labels:
    app: wordpress
spec:
  selector:
    matchLabels:
      app: wordpress
      tier: frontend
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: wordpress
        tier: frontend
    spec:
      containers:
      - image: wordpress:4.8-apache
        name: wordpress
        env:
        - name: WORDPRESS_DB_HOST
          value: cluster1-haproxy
        - name: WORDPRESS_DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: my-cluster-secrets
              key: root
        ports:
        - containerPort: 80
          name: wordpress
        volumeMounts:
        - name: wordpress-persistent-storage
          mountPath: /var/www/html
      volumes:
      - name: wordpress-persistent-storage
        persistentVolumeClaim:
          claimName: wp-pv-claim

Achten Sie auf die Umgebungsvariablen WORDPRESS_DB_HOST und WORDPRESS_DB_PASSWORD. Die erste Variable, in der wir „cluster1-haproxy“ als Datenbankhost anstelle eines einzelnen Datenbankknotens definiert haben, und für letztere haben wir das Root-Passwort angegeben, indem wir Kubernetes angewiesen haben, es aus dem my-cluster-secrets-Objekt unter dem Schlüssel „root“ zu lesen. was "mypassword" entspricht (nachdem der base64-Wert dekodiert wurde). Wir überspringen die Definition der Umgebungsvariable WORDPRESS_DB_USER, da der Standardwert "root" ist.

Jetzt können wir unsere Anwendung erstellen:

$ kubectl apply -f wordpress-deployment.yaml

Prüfen Sie den Dienst:

$ kubectl get service
NAME                        TYPE           CLUSTER-IP     EXTERNAL-IP     PORT(S)                       AGE
cluster1-haproxy            ClusterIP      10.40.9.177    <none>          3306/TCP,3309/TCP,33062/TCP   4h42m
cluster1-haproxy-replicas   ClusterIP      10.40.0.236    <none>          3306/TCP                      4h42m
cluster1-pxc                ClusterIP      None           <none>          3306/TCP,33062/TCP            4h42m
cluster1-pxc-unready        ClusterIP      None           <none>          3306/TCP,33062/TCP            4h42m
wordpress                   LoadBalancer   10.40.13.205   35.200.78.195   80:32087/TCP                  4h39m

An diesem Punkt können wir uns mit unserer WordPress-Anwendung unter http://35.200.78.195/ (der externen IP-Adresse) verbinden und mit der Konfiguration der WordPress-Anwendung beginnen. An diesem Punkt ist unsere WordPress-Anwendung über einen der HAProxy-Pods mit einem der Percona XtraDB-Cluster (Single-Master-Verbindung) verbunden.

Das war es erstmal. Weitere Informationen finden Sie in der Dokumentation zu Percona Kubernetes Operator for Percona XtraDB Cluster. Viel Spaß beim Containerisieren!