Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Uma visão geral do operador de Kubernetes do cluster Percona XtraDB

Se você já esteve no mundo dos contêineres, sabe que é bastante desafiador adotar uma automação completa do Kubernetes para um sistema de banco de dados em cluster, que geralmente adiciona um nível de complexidade ao sistema baseado em contêiner arquitetura para esses aplicativos com estado. É aí que um Operador do Kubernetes pode nos ajudar a resolver esse problema. Um operador do Kubernetes é um tipo especial de controlador introduzido para simplificar implantações complexas que basicamente estendem a API do Kubernetes com recursos personalizados. Ele se baseia nos conceitos básicos de recursos e controladores do Kubernetes, mas inclui conhecimento específico de domínio ou aplicativo para automatizar todo o ciclo de vida do software que ele gerencia.

O Percona XtraDB Cluster Operator é uma maneira elegante de automatizar as tarefas específicas do Percona XtraDB Cluster, como implantação, dimensionamento, backups e atualizações no Kubernetes, criadas e mantidas pela Percona. Ele implanta o cluster em um StatefulSet com um Volume Persistente, o que nos permite manter uma identidade consistente para cada Pod no cluster e nossos dados a serem mantidos.

Nesta postagem do blog, testaremos a implantação do Percona XtraDB Cluster 8.0 em um ambiente em contêiner, orquestrado pelo Percona XtraDB Cluster Kubernetes Operator no Google Cloud Platform.

Criando um cluster Kubernetes no Google Cloud


Neste passo a passo, usaremos o cluster Kubernetes no Google Cloud porque é relativamente simples e fácil colocar o Kubernetes em funcionamento. Faça login no painel do Google Cloud Platform -> Computação -> Kubernetes Engine -> Criar cluster e você verá a seguinte caixa de diálogo:

Basta digitar o nome do cluster Kubernetes, escolher sua zona preferida e clicar em "CRIAR " (no final da página). Em 5 minutos, um cluster Kubernetes de 3 nós estará pronto. Agora, em sua estação de trabalho, instale o SDK gcloud conforme mostrado neste guia e extraia a configuração do Kubernetes em sua estação de trabalho:

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

Você deve conseguir se conectar ao cluster Kubernetes neste momento. Execute o seguinte 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

A saída acima significa que podemos nos conectar ao mestre do Kubernetes e recuperar os nós do cluster do Kubernetes. Agora, estamos prontos para executar as cargas de trabalho do Kubernetes.

Implantando um cluster Percona XtraDB no Kubernetes


Para implantação de carga de trabalho, seguiremos as instruções conforme indicado na documentação do Operador de cluster Percona XtraDB. Basicamente, executamos o seguinte comando em nossa estação de trabalho para criar os recursos personalizados, namespace, controle de acesso baseado em função e também o próprio operador do 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

Em seguida, temos que preparar nossas senhas (chamadas Secrets no termo Kubernetes) atualizando os valores dentro de deploy/secrets.yaml em um formato codificado em base64. Você pode usar ferramentas online como https://www.base64encode.org/ para criar uma ou usar uma ferramenta de linha de comando como a seguinte:

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

Em seguida, atualize o deploy/secrets.yaml, conforme mostrado abaixo:

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

O acima é uma super simplificação do gerenciamento de segredos, onde definimos todas as senhas para serem as mesmas para todos os usuários. Na produção, use uma senha mais complexa e especifique uma senha diferente para cada usuário.

Agora, podemos enviar a configuração secreta para o Kubernetes:

$ kubectl apply -f deploy/secrets.yaml

Antes de avançarmos para implantar um Percona XtraDB Cluster, precisamos revisitar a definição de implantação padrão dentro de deploy/cr.yaml para o cluster. Existem muitos objetos do Kubernetes definidos aqui, mas a maioria deles é comentada. Para nossa carga de trabalho, faríamos a modificação conforme abaixo:
$ 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

Fizemos algumas modificações no cr.yaml fornecido para que funcione com nosso aplicativo, conforme mostrado acima. Antes de tudo, temos que comentar (ou remover) todas as linhas relacionadas à CPU, por exemplo [*].resources.requests.cpu:600m, para garantir que o Kubernetes seja capaz de agendar a criação de pod corretamente em nós com CPU limitada. Em seguida, precisamos adicionar algumas opções de compatibilidade para o Percona XtraDB Cluster 8.0 que é baseado no MySQL 8.0, para funcionar sem problemas com nosso aplicativo WordPress que vamos implantar posteriormente, conforme mostrado no trecho a seguir:

   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

O acima corresponderá ao conjunto de caracteres padrão do servidor MySQL com o driver MySQLi PHP em nosso contêiner WordPress. A próxima seção é a implementação do HAProxy em que ele é definido como "ativado:verdadeiro". Há também uma seção ProxySQL com "enabled:false" - normalmente alguém escolheria um dos proxies reversos para cada cluster. A última seção é a configuração de backup, onde gostaríamos de ter um backup diário agendado às 00:00 todos os dias e manter os últimos 5 backups.

Agora podemos começar a implantar nosso cluster Percona XtraDB de 3 nós:

$ kubectl apply -f deploy/cr.yaml

O processo de criação levará algum tempo. O operador implantará os pods do Percona XtraDB Cluster como um Stateful Set, o que significa uma criação de pod por vez e cada Pod no StatefulSet receberá um ordinal inteiro, de 0 a N-1, que é exclusivo no conjunto. O processo termina quando o operador e os pods atingem o status Running:
$ 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

Como esse operador é um recurso personalizado, podemos manipular o recurso perconaxtradbcluster para gostar do recurso padrão do Kubernetes:

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

Você também pode usar o nome de recurso mais curto, "pxc", e tentar com os seguintes comandos:

$ kubectl describe pxc
$ kubectl edit pxc

Ao olhar para o conjunto de carga de trabalho, podemos dizer que o operador criou dois 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

O operador também criará os serviços correspondentes que farão conexões com balanceamento de carga para os respectivos pods:

$ 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

A saída acima mostra que o operador criou 4 serviços:

  • cluster1-haproxy - O serviço para um único mestre MySQL com balanceamento de carga (3306), protocolo Proxy (3309) e MySQL Admin (33062) - Uma nova porta administrativa introduzida no MySQL 8.0.14 e posterior. Este é o nome do serviço ou o endereço IP do cluster que os aplicativos precisam conectar para ter uma conexão de mestre único com o cluster Galera.
  • cluster1-haproxy-replicas - O serviço para um multimestre MySQL com balanceamento de carga (3306). Este é o nome do serviço ou o endereço IP do cluster que os aplicativos precisam conectar para ter uma conexão multimestre com o cluster Galera com algoritmo de balanceamento round-robin.
  • cluster1-pxc - O serviço para pods PXC com balanceamento de carga, ignorando o HAProxy. Ao se conectar diretamente a esse serviço, o Kubernetes roteará a conexão de forma round-robin para todos os pods PXC, semelhante ao que o cluster-haproxy-replicase fornece. O serviço não tem endereço IP público atribuído e não está disponível fora do cluster.
  • cluster1-pxc-unready - O serviço 'unready' é necessário para a descoberta do endereço do pod durante a inicialização do aplicativo, independentemente do estado do pod. Os pods Proxysql e pxc devem se conhecer antes que o banco de dados fique totalmente operacional. O serviço não pronto não tem endereço IP público atribuído e não está disponível fora do cluster.

Para se conectar através de um cliente MySQL, basta executar o seguinte comando:
$ kubectl run -i --rm --tty percona-client --image=percona:8.0 --restart=Never -- bash -il

Isso criará um pod temporário e entrará imediatamente no ambiente do contêiner. Em seguida, execute o comando padrão do cliente mysql com uma credencial adequada:

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

Quando analisamos o posicionamento do pod, todos os pods do Percona XtraDB Cluster estão localizados em um host 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>

Isso definitivamente melhorará a disponibilidade do serviço, caso um dos hosts do Kubernetes fique inativo.

Para escalar até 5 pods, precisamos preparar outros 2 novos nós do Kubernetes com antecedência para respeitar a configuração de afinidade do pod (padrão para identity.antiAffinityTopologyKey.topologyKey="kubernetes.io/hostname"). Em seguida, execute o seguinte comando de patch para dimensionar o Percona XtraDB Cluster para 5 nós:

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

Monitore a criação do pod usando o 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>

Outros 2 novos pods (cluster1-pxc-3 e cluster1-pxc-4) foram criados em outros 2 novos nós do Kubernetes (gke-my-k8s-cluster-pool-1-ab14a45e-h1pf e gke-my-k8s-cluster-pool-1-ab14a45e-01qn). Para reduzir, basta alterar o valor de volta para 3 no comando patch acima. Observe que o Percona XtraDB Cluster deve ser executado com um número ímpar de nós para evitar a divisão do cérebro.

Implantando um aplicativo (WordPress)


Neste exemplo, vamos implantar um aplicativo WordPress em cima do nosso Percona XtraDB Cluster e HAProxy. Vamos primeiro preparar o arquivo de definição YAML da seguinte forma:
$ 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 atenção às variáveis ​​de ambiente WORDPRESS_DB_HOST e WORDPRESS_DB_PASSWORD. A primeira variável onde definimos "cluster1-haproxy" como o host do banco de dados, em vez de um nó de banco de dados individual e, para o último, especificamos a senha do root instruindo o Kubernetes a lê-la do objeto my-cluster-secrets na chave "root", que é equivalente a "mypassword" (depois que o valor base64 foi decodificado). Ignoramos a definição da variável de ambiente WORDPRESS_DB_USER, pois o valor padrão é "root".

Agora podemos criar nossa aplicação:

$ kubectl apply -f wordpress-deployment.yaml

Verifique o serviço:

$ 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

Neste ponto, podemos nos conectar ao nosso aplicativo WordPress em http://35.200.78.195/ (o endereço IP externo) e começar a configurar o aplicativo WordPress. Neste ponto, nosso aplicativo WordPress está conectado a um dos Percona XtraDB Cluster (conexão de mestre único) por meio de um dos pods HAProxy.

É isso por enquanto. Para obter mais informações, confira a documentação do Percona Kubernetes Operator for Percona XtraDB Cluster. Feliz conteinerização!