sql >> Base de Datos >  >> RDS >> Mysql

Una descripción general del operador Kubernetes del clúster Percona XtraDB

Si ha estado en el mundo de los contenedores, sabrá que es bastante desafiante adoptar una automatización completa de Kubernetes para un sistema de base de datos en clúster, lo que comúnmente agrega un nivel de complejidad a la base de datos basada en contenedores. arquitectura para estas aplicaciones con estado. Ahí es donde un operador de Kubernetes puede ayudarnos a abordar este problema. Un operador de Kubernetes es un tipo especial de controlador introducido para simplificar implementaciones complejas que básicamente amplía la API de Kubernetes con recursos personalizados. Se basa en los conceptos básicos de recursos y controladores de Kubernetes, pero incluye conocimientos específicos de aplicaciones o dominios para automatizar todo el ciclo de vida del software que administra.

Percona XtraDB Cluster Operator es una forma ordenada de automatizar las tareas específicas de Percona XtraDB Cluster como implementación, escalado, copias de seguridad y actualizaciones dentro de Kubernetes, creado y mantenido por Percona. Implementa el clúster en un StatefulSet con un volumen persistente, lo que nos permite mantener una identidad constante para cada pod en el clúster y mantener nuestros datos.

En esta publicación de blog, probaremos la implementación de Percona XtraDB Cluster 8.0 en un entorno en contenedores, orquestado por Percona XtraDB Cluster Kubernetes Operator en Google Cloud Platform.

Creación de un clúster de Kubernetes en Google Cloud

En este tutorial, usaremos el clúster de Kubernetes en Google Cloud porque es relativamente simple y fácil poner en marcha Kubernetes. Inicie sesión en su panel de control de Google Cloud Platform -> Compute -> Kubernetes Engine -> Create Cluster, y verá el siguiente cuadro de diálogo:

Simplemente ingrese el nombre del clúster de Kubernetes, elija su zona preferida y haga clic en "CREAR " (al final de la página). En 5 minutos, estará listo un clúster de Kubernetes de 3 nodos. Ahora, en su estación de trabajo, instale el SDK de gcloud como se muestra en esta guía y luego introduzca la configuración de Kubernetes en su estación de trabajo:

$ 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.

Debería poder conectarse al clúster de Kubernetes en este punto. Ejecute el siguiente comando para verificar:

$ 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

El resultado anterior significa que podemos conectarnos al maestro de Kubernetes y recuperar los nodos del clúster de Kubernetes. Ahora, estamos listos para ejecutar las cargas de trabajo de Kubernetes.

Implementación de un clúster Percona XtraDB en Kubernetes

Para la implementación de la carga de trabajo, vamos a seguir las instrucciones que se indican en la documentación del Operador de clúster de Percona XtraDB. Básicamente, ejecutamos el siguiente comando en nuestra estación de trabajo para crear los recursos personalizados, el espacio de nombres, el control de acceso basado en roles y también el propio operador de Kubernetes:

$ 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

A continuación, tenemos que preparar nuestras contraseñas (se llama Secretos en el término de Kubernetes) actualizando los valores dentro de deployment/secrets.yaml en un formato codificado en base64. Puede usar herramientas en línea como https://www.base64encode.org/ para crear uno o usar una herramienta de línea de comandos como la siguiente:

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

Luego, actualice deployment/secrets.yaml, como se muestra a continuación:

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==

Lo anterior es una súper simplificación de la administración de secretos, donde configuramos todas las contraseñas para que sean iguales para todos los usuarios. En producción, utilice una contraseña más compleja y especifique una contraseña diferente para cada usuario.

Ahora, podemos enviar la configuración secreta a Kubernetes:

$ kubectl apply -f deploy/secrets.yaml

Antes de continuar con la implementación de un clúster Percona XtraDB, debemos revisar la definición de implementación predeterminada dentro de deployment/cr.yaml para el clúster. Hay muchos objetos de Kubernetes que se definen aquí, pero la mayoría de ellos están comentados. Para nuestra carga de trabajo, haríamos la modificación de la siguiente manera:

$ 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

Hemos realizado algunas modificaciones al cr.yaml provisto para que funcione con nuestra aplicación, como se muestra arriba. En primer lugar, debemos comentar (o eliminar) todas las líneas relacionadas con la CPU, por ejemplo [*].resources.requests.cpu:600m, para asegurarnos de que Kubernetes pueda programar la creación del pod correctamente en nodos con CPU limitada. Luego, debemos agregar algunas opciones de compatibilidad para Percona XtraDB Cluster 8.0, que se basa en MySQL 8.0, para que funcione sin problemas con nuestra aplicación de WordPress que implementaremos más adelante, como se muestra en el siguiente extracto:

   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

Lo anterior hará coincidir el juego de caracteres predeterminado del servidor MySQL con el controlador MySQLi PHP en nuestro contenedor de WordPress. La siguiente sección es la implementación de HAProxy donde se establece en "habilitado:verdadero". También hay una sección ProxySQL con "habilitado:falso"; por lo general, uno elegiría cualquiera de los proxies inversos para cada clúster. La última sección es la configuración de la copia de seguridad, donde nos gustaría tener una copia de seguridad diaria programada a las 12:00 a. m. todos los días y mantener las últimas 5 copias de seguridad.

Ahora podemos comenzar a implementar nuestro clúster Percona XtraDB de 3 nodos:

$ kubectl apply -f deploy/cr.yaml

El proceso de creación llevará algún tiempo. El operador implementará los pods de Percona XtraDB Cluster como un Stateful Set, lo que significa que se creará un pod a la vez y a cada Pod en el StatefulSet se le asignará un ordinal entero, desde 0 hasta N-1, que es único en el conjunto. El proceso finaliza cuando tanto el operador como los Pods alcanzan su estado de ejecución:

$ 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

Dado que este operador es un recurso personalizado, podemos manipular el recurso perconaxtradbcluster para que le guste el recurso estándar de Kubernetes:

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

También puede usar el nombre de recurso más corto, "pxc", e intentar con los siguientes comandos:

$ kubectl describe pxc
$ kubectl edit pxc

Al mirar el conjunto de cargas de trabajo, podemos decir que el operador ha creado dos StatefulSets:

$ 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

El operador también creará los servicios correspondientes que equilibrarán la carga de las conexiones a los pods respectivos:

$ 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

El resultado anterior muestra que el operador ha creado 4 servicios:

  • clúster1-haproxy - El servicio para un maestro único de MySQL con carga balanceada (3306), protocolo Proxy (3309) y MySQL Admin (33062) - Un nuevo puerto administrativo introducido en MySQL 8.0.14 y versiones posteriores. Este es el nombre del servicio o la dirección IP del clúster que las aplicaciones necesitan para conectarse para tener una conexión maestra única al clúster de Galera.
  • cluster1-haproxy-réplicas - El servicio para un multi-maestro MySQL con balance de carga (3306). Este es el nombre del servicio o la dirección IP del clúster que las aplicaciones necesitan para conectarse para tener una conexión multimaestro al clúster de Galera con el algoritmo de equilibrio de turno rotativo.
  • clúster1-pxc - El servicio para pods PXC con equilibrio de carga, sin pasar por HAProxy. Al conectarse directamente a este servicio, Kubernetes enrutará la conexión por turnos a todos los pods de PXC, de forma similar a lo que proporciona cluster-haproxy-replicase. El servicio no tiene una dirección IP pública asignada y no está disponible fuera del clúster.
  • cluster1-pxc-no preparado - El servicio 'no preparado' es necesario para la detección de direcciones de pod durante el inicio de la aplicación, independientemente del estado del Pod. Los pods de Proxysql y pxc deben conocerse antes de que la base de datos esté completamente operativa. El servicio no preparado no tiene una dirección IP pública asignada y no está disponible fuera del clúster.

Para conectarse a través de un cliente MySQL, simplemente ejecute el siguiente comando:

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

Esto creará un Pod transitorio e ingresará inmediatamente al entorno del contenedor. Luego, ejecute el comando de cliente mysql estándar con una credencial adecuada:

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 |
+----------------+

Cuando observamos la ubicación de los pods, todos los pods de Percona XtraDB Cluster están ubicados en un host de Kubernetes diferente:

$ 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>

Esto definitivamente mejorará la disponibilidad del servicio, en caso de que uno de los hosts de Kubernetes se caiga.

Para escalar hasta 5 pods, debemos preparar otros 2 nuevos nodos de Kubernetes de antemano para respetar la configuración de afinidad de pods (predeterminada en affinity.antiAffinityTopologyKey.topologyKey="kubernetes.io/hostname"). Luego, ejecute el siguiente comando de parche para escalar Percona XtraDB Cluster a 5 nodos:

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

Supervise la creación del pod mediante el comando 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>

Se han creado otros 2 nuevos pods (cluster1-pxc-3 y cluster1-pxc-4) en otros 2 nuevos nodos de Kubernetes (gke-my-k8s-cluster-pool-1-ab14a45e-h1pf y gke-my-k8s-cluster-pool-1-ab14a45e-01qn). Para reducir la escala, simplemente cambie el valor a 3 en el comando de parche anterior. Tenga en cuenta que Percona XtraDB Cluster debe ejecutarse con un número impar de nodos para evitar el cerebro dividido.

Implementación de una aplicación (WordPress)

En este ejemplo, implementaremos una aplicación de WordPress sobre nuestro Percona XtraDB Cluster y HAProxy. Primero preparemos el archivo de definición YAML como el siguiente:

$ 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

Preste atención a las variables de entorno WORDPRESS_DB_HOST y WORDPRESS_DB_PASSWORD. La primera variable en la que definimos "cluster1-haproxy" como el host de la base de datos, en lugar de un nodo de base de datos individual, y para la última especificamos la contraseña de root al indicarle a Kubernetes que la leyera desde el objeto my-cluster-secrets bajo la clave "root", que es equivalente a "mypassword" (después de decodificar el valor base64). Omitimos definir la variable de entorno WORDPRESS_DB_USER ya que el valor predeterminado es "root".

Ahora podemos crear nuestra aplicación:

$ kubectl apply -f wordpress-deployment.yaml

Consulte el servicio:

$ 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

En este punto, podemos conectarnos a nuestra aplicación de WordPress en http://35.200.78.195/ (la dirección IP externa) y comenzar a configurar la aplicación de WordPress. En este punto, nuestra aplicación de WordPress está conectada a uno de los Percona XtraDB Cluster (conexión de maestro único) a través de uno de los pods HAProxy.

Eso es todo por ahora. Para obtener más información, consulte la documentación de Percona Kubernetes Operator for Percona XtraDB Cluster. ¡Feliz contenedorización!