Desplegar un clúster de alta disponibilidad de MySQL 5.6 con DRBD en Compute Engine

En este tutorial se explica cómo desplegar una base de datos MySQL 5.6 enGoogle Cloud mediante Distributed Replicated Block Device (DRBD) y Compute Engine. DRBD es un sistema de almacenamiento replicado distribuido para la plataforma Linux.

Este tutorial es útil si eres administrador de sistemas, desarrollador, ingeniero, administrador de bases de datos o ingeniero de DevOps. Puede que quieras gestionar tu propia instancia de MySQL en lugar de usar el servicio gestionado por varios motivos, entre los que se incluyen los siguientes:

  • Estás usando instancias de MySQL entre regiones.
  • Debes definir parámetros que no estén disponibles en la versión gestionada de MySQL.
  • Quieres optimizar el rendimiento de formas que no se pueden configurar en la versión gestionada.

DRBD proporciona replicación a nivel de dispositivo de bloque. Esto significa que no tienes que configurar la replicación en MySQL y que obtienes las ventajas de DRBD de inmediato, como la compatibilidad con el equilibrio de carga de lectura y las conexiones seguras.

En el tutorial se utiliza lo siguiente:

No es necesario tener conocimientos avanzados para usar estos recursos, aunque en este documento se hace referencia a funciones avanzadas, como la agrupación en clústeres de MySQL, la configuración de DRBD y la gestión de recursos de Linux.

Arquitectura

Pacemaker es un gestor de recursos de clústeres. Corosync es un paquete de comunicación y participación de clústeres que usa Pacemaker. En este tutorial, usarás DRBD para replicar el disco de MySQL de la instancia principal a la de espera. Para que los clientes se conecten al clúster de MySQL, también debes implementar un balanceador de carga interno.

Despliega un clúster de tres instancias de proceso gestionado por Pacemaker. Instalas MySQL en dos de las instancias, que actúan como instancias principal y de reserva. La tercera instancia actúa como dispositivo de quórum.

En un clúster, cada nodo vota por el nodo que debe ser el nodo activo, es decir, el que ejecuta MySQL. En un clúster de dos nodos, solo se necesita un voto para determinar el nodo activo. En ese caso, el comportamiento del clúster puede provocar problemas de cerebro dividido o tiempos de inactividad. Los problemas de cerebro dividido se producen cuando ambos nodos toman el control, ya que solo se necesita un voto en un escenario de dos nodos. El tiempo de inactividad se produce cuando el nodo que se apaga es el que está configurado para ser siempre el principal en caso de pérdida de conectividad. Si los dos nodos pierden la conectividad entre sí, existe el riesgo de que más de un nodo del clúster asuma que es el nodo activo.

Si añades un dispositivo de quórum, se evitará esta situación. Un dispositivo de quórum actúa como árbitro, cuya única tarea es emitir un voto. De esta forma, en una situación en la que las instancias de database1 y database2 no puedan comunicarse, este nodo de dispositivo de quórum podrá comunicarse con una de las dos instancias y se podrá alcanzar una mayoría.

En el siguiente diagrama se muestra la arquitectura del sistema descrito en este artículo.

Arquitectura que muestra una base de datos MySQL 5.6 desplegada en Google Cloud mediante DRBD y Compute Engine

Configuración

En esta sección, configurará una cuenta de servicio, creará variables de entorno y reservará direcciones IP.

Configurar una cuenta de servicio para las instancias del clúster

  1. Abre Cloud Shell:

    ABRIR Cloud Shell

  2. Crea la cuenta de servicio:

    gcloud iam service-accounts create mysql-instance \
        --display-name "mysql-instance"
    
  3. Asigna los roles necesarios para este tutorial a la cuenta de servicio:

    gcloud projects add-iam-policy-binding ${DEVSHELL_PROJECT_ID} \
        --member=serviceAccount:mysql-instance@${DEVSHELL_PROJECT_ID}.iam.gserviceaccount.com \
        --role=roles/compute.instanceAdmin.v1
    
    gcloud projects add-iam-policy-binding ${DEVSHELL_PROJECT_ID} \
        --member=serviceAccount:mysql-instance@${DEVSHELL_PROJECT_ID}.iam.gserviceaccount.com \
        --role=roles/compute.viewer
    
    gcloud projects add-iam-policy-binding ${DEVSHELL_PROJECT_ID} \
        --member=serviceAccount:mysql-instance@${DEVSHELL_PROJECT_ID}.iam.gserviceaccount.com \
        --role=roles/iam.serviceAccountUser
    

Crear variables de entorno de Cloud Shell

  1. Crea un archivo con las variables de entorno necesarias para este tutorial:

    cat <<EOF > ~/.mysqldrbdrc
    # Cluster instance names
    DATABASE1_INSTANCE_NAME=database1
    DATABASE2_INSTANCE_NAME=database2
    QUORUM_INSTANCE_NAME=qdevice
    CLIENT_INSTANCE_NAME=mysql-client
    # Cluster IP addresses
    DATABASE1_INSTANCE_IP="10.140.0.2"
    DATABASE2_INSTANCE_IP="10.140.0.3"
    QUORUM_INSTANCE_IP="10.140.0.4"
    ILB_IP="10.140.0.6"
    # Cluster zones and region
    DATABASE1_INSTANCE_ZONE="asia-east1-a"
    DATABASE2_INSTANCE_ZONE="asia-east1-b"
    QUORUM_INSTANCE_ZONE="asia-east1-c"
    CLIENT_INSTANCE_ZONE="asia-east1-c"
    CLUSTER_REGION="asia-east1"
    EOF
    
  2. Carga las variables de entorno en la sesión actual y configura Cloud Shell para que las cargue automáticamente en futuros inicios de sesión:

    source ~/.mysqldrbdrc
    grep -q -F "source ~/.mysqldrbdrc" ~/.bashrc || echo "source ~/.mysqldrbdrc" >> ~/.bashrc
    

Reservar direcciones IP

  • En Cloud Shell, reserva una dirección IP interna para cada uno de los tres nodos del clúster:

    gcloud compute addresses create ${DATABASE1_INSTANCE_NAME} ${DATABASE2_INSTANCE_NAME} ${QUORUM_INSTANCE_NAME} \
        --region=${CLUSTER_REGION} \
        --addresses "${DATABASE1_INSTANCE_IP},${DATABASE2_INSTANCE_IP},${QUORUM_INSTANCE_IP}" \
        --subnet=default
    

Crear las instancias de Compute Engine

En los siguientes pasos, las instancias del clúster usan Debian 9 y las instancias del cliente usan Ubuntu 16.

  1. En Cloud Shell, crea una instancia de MySQL llamada database1 en la zona asia-east1-a:

    gcloud compute instances create ${DATABASE1_INSTANCE_NAME} \
        --zone=${DATABASE1_INSTANCE_ZONE} \
        --machine-type=n1-standard-2  \
        --network-tier=PREMIUM \
        --maintenance-policy=MIGRATE \
        --image-family=debian-9 \
        --image-project=debian-cloud \
        --boot-disk-size=50GB \
        --boot-disk-type=pd-standard \
        --boot-disk-device-name=${DATABASE1_INSTANCE_NAME} \
        --create-disk=mode=rw,size=300,type=pd-standard,name=disk-1 \
        --private-network-ip=${DATABASE1_INSTANCE_NAME} \
        --tags=mysql --service-account=mysql-instance@${DEVSHELL_PROJECT_ID}.iam.gserviceaccount.com \
        --scopes="https://www.googleapis.com/auth/compute,https://www.googleapis.com/auth/servicecontrol,https://www.googleapis.com/auth/service.management.readonly" \
        --metadata="DATABASE1_INSTANCE_IP=${DATABASE1_INSTANCE_IP},DATABASE2_INSTANCE_IP=${DATABASE2_INSTANCE_IP},DATABASE1_INSTANCE_NAME=${DATABASE1_INSTANCE_NAME},DATABASE2_INSTANCE_NAME=${DATABASE2_INSTANCE_NAME},QUORUM_INSTANCE_NAME=${QUORUM_INSTANCE_NAME},DATABASE1_INSTANCE_ZONE=${DATABASE1_INSTANCE_ZONE},DATABASE2_INSTANCE_ZONE=${DATABASE2_INSTANCE_ZONE}"
    
  2. Crea una instancia de MySQL llamada database2 en la zona asia-east1-b:

    gcloud compute instances create ${DATABASE2_INSTANCE_NAME} \
        --zone=${DATABASE2_INSTANCE_ZONE} \
        --machine-type=n1-standard-2  \
        --network-tier=PREMIUM \
        --maintenance-policy=MIGRATE \
        --image-family=debian-9 \
        --image-project=debian-cloud \
        --boot-disk-size=50GB \
        --boot-disk-type=pd-standard \
        --boot-disk-device-name=${DATABASE2_INSTANCE_NAME} \
        --create-disk=mode=rw,size=300,type=pd-standard,name=disk-2 \
        --private-network-ip=${DATABASE2_INSTANCE_NAME} \
        --tags=mysql \
        --service-account=mysql-instance@${DEVSHELL_PROJECT_ID}.iam.gserviceaccount.com \
        --scopes="https://www.googleapis.com/auth/compute,https://www.googleapis.com/auth/servicecontrol,https://www.googleapis.com/auth/service.management.readonly" \
        --metadata="DATABASE1_INSTANCE_IP=${DATABASE1_INSTANCE_IP},DATABASE2_INSTANCE_IP=${DATABASE2_INSTANCE_IP},DATABASE1_INSTANCE_NAME=${DATABASE1_INSTANCE_NAME},DATABASE2_INSTANCE_NAME=${DATABASE2_INSTANCE_NAME},QUORUM_INSTANCE_NAME=${QUORUM_INSTANCE_NAME},DATABASE1_INSTANCE_ZONE=${DATABASE1_INSTANCE_ZONE},DATABASE2_INSTANCE_ZONE=${DATABASE2_INSTANCE_ZONE}"
    
  3. Crea un nodo de quorum para que lo use Pacemaker en la zona asia-east1-c:

    gcloud compute instances create ${QUORUM_INSTANCE_NAME} \
        --zone=${QUORUM_INSTANCE_ZONE} \
        --machine-type=n1-standard-1 \
        --network-tier=PREMIUM \
        --maintenance-policy=MIGRATE \
        --image-family=debian-9  \
        --image-project=debian-cloud \
        --boot-disk-size=10GB \
        --boot-disk-type=pd-standard \
        --boot-disk-device-name=${QUORUM_INSTANCE_NAME} \
        --private-network-ip=${QUORUM_INSTANCE_NAME}
    
  4. Crea una instancia de cliente de MySQL:

    gcloud compute instances create ${CLIENT_INSTANCE_NAME} \
        --image-family=ubuntu-1604-lts \
        --image-project=ubuntu-os-cloud \
        --tags=mysql-client \
        --zone=${CLIENT_INSTANCE_ZONE} \
        --boot-disk-size=10GB \
        --metadata="ILB_IP=${ILB_IP}"
    

Instalar y configurar DRBD

En esta sección, instalarás y configurarás los paquetes de DRBD en las instancias database1 y database2 y, a continuación, iniciarás la replicación de DRBD de database1 a database2.

Configurar DRBD en database1

  1. En la Google Cloud consola, ve a la página Instancias de VM:

    PÁGINA INSTANCIAS DE VM

  2. En la fila de la instancia database1, haz clic en SSH para conectarte a la instancia.

    .
  3. Crea un archivo para obtener y almacenar metadatos de instancias en variables de entorno:

    sudo bash -c cat <<EOF  > ~/.varsrc
    DATABASE1_INSTANCE_IP=$(curl -s "http://metadata.google.internal/computeMetadata/v1/instance/attributes/DATABASE1_INSTANCE_IP" -H "Metadata-Flavor: Google")
    DATABASE2_INSTANCE_IP=$(curl -s "http://metadata.google.internal/computeMetadata/v1/instance/attributes/DATABASE2_INSTANCE_IP" -H "Metadata-Flavor: Google")
    DATABASE1_INSTANCE_NAME=$(curl -s "http://metadata.google.internal/computeMetadata/v1/instance/attributes/DATABASE1_INSTANCE_NAME" -H "Metadata-Flavor: Google")
    DATABASE2_INSTANCE_NAME=$(curl -s "http://metadata.google.internal/computeMetadata/v1/instance/attributes/DATABASE2_INSTANCE_NAME" -H "Metadata-Flavor: Google")
    DATABASE2_INSTANCE_ZONE=$(curl -s "http://metadata.google.internal/computeMetadata/v1/instance/attributes/DATABASE2_INSTANCE_ZONE" -H "Metadata-Flavor: Google")
    DATABASE1_INSTANCE_ZONE=$(curl -s "http://metadata.google.internal/computeMetadata/v1/instance/attributes/DATABASE1_INSTANCE_ZONE" -H "Metadata-Flavor: Google")
    QUORUM_INSTANCE_NAME=$(curl -s "http://metadata.google.internal/computeMetadata/v1/instance/attributes/QUORUM_INSTANCE_NAME" -H "Metadata-Flavor: Google")
    
    EOF
    
  4. Carga las variables de metadatos del archivo:

    source ~/.varsrc
    
  5. Formatea el disco de datos:

    sudo bash -c  "mkfs.ext4 -m 0 -F -E \
    lazy_itable_init=0,lazy_journal_init=0,discard /dev/sdb"
    

    Para obtener una descripción detallada de las opciones de mkfs.ext4, consulta la página del manual de mkfs.ext4.

  6. Instala DRBD:

    sudo apt -y install drbd8-utils
    
  7. Crea el archivo de configuración de DRBD:

    sudo bash -c 'cat <<EOF  > /etc/drbd.d/global_common.conf
    global {
        usage-count no;
    }
    common {
        protocol C;
    }
    EOF'
    
  8. Crea un archivo de recursos de DRBD:

    sudo bash -c "cat <<EOF  > /etc/drbd.d/r0.res
    resource r0 {
        meta-disk internal;
        device /dev/drbd0;
        net {
            allow-two-primaries no;
            after-sb-0pri discard-zero-changes;
            after-sb-1pri discard-secondary;
            after-sb-2pri disconnect;
            rr-conflict disconnect;
        }
        on database1 {
            disk /dev/sdb;
            address 10.140.0.2:7789;
        }
        on database2 {
            disk /dev/sdb;
            address 10.140.0.3:7789;
        }
    }
    EOF"
    
  9. Carga el módulo del kernel de DRBD:

    sudo modprobe drbd
    
  10. Borra el contenido del disco /dev/sdb:

    sudo dd if=/dev/zero of=/dev/sdb bs=1k count=1024
    
  11. Crea el recurso DRBD r0:

    sudo drbdadm create-md r0
    
  12. Activa DRBD:

    sudo drbdadm up r0
    
  13. Inhabilita DRBD cuando se inicie el sistema para que el software de gestión de recursos del clúster inicie todos los servicios necesarios en el orden correcto:

    sudo update-rc.d drbd disable
    

Configurar DRBD en database2

Ahora, instala y configura los paquetes DRBD en la instancia database2.

  1. Conéctate a la instancia database2 mediante SSH.
  2. Crea un archivo .varsrc para obtener y almacenar metadatos de instancias en variables de entorno:

    sudo bash -c cat <<EOF  > ~/.varsrc
    DATABASE1_INSTANCE_IP=$(curl -s "http://metadata.google.internal/computeMetadata/v1/instance/attributes/DATABASE1_INSTANCE_IP" -H "Metadata-Flavor: Google")
    DATABASE2_INSTANCE_IP=$(curl -s "http://metadata.google.internal/computeMetadata/v1/instance/attributes/DATABASE2_INSTANCE_IP" -H "Metadata-Flavor: Google")
    DATABASE1_INSTANCE_NAME=$(curl -s "http://metadata.google.internal/computeMetadata/v1/instance/attributes/DATABASE1_INSTANCE_NAME" -H "Metadata-Flavor: Google")
    DATABASE2_INSTANCE_NAME=$(curl -s "http://metadata.google.internal/computeMetadata/v1/instance/attributes/DATABASE2_INSTANCE_NAME" -H "Metadata-Flavor: Google")
    DATABASE2_INSTANCE_ZONE=$(curl -s "http://metadata.google.internal/computeMetadata/v1/instance/attributes/DATABASE2_INSTANCE_ZONE" -H "Metadata-Flavor: Google")
    DATABASE1_INSTANCE_ZONE=$(curl -s "http://metadata.google.internal/computeMetadata/v1/instance/attributes/DATABASE1_INSTANCE_ZONE" -H "Metadata-Flavor: Google")
    QUORUM_INSTANCE_NAME=$(curl -s "http://metadata.google.internal/computeMetadata/v1/instance/attributes/QUORUM_INSTANCE_NAME" -H "Metadata-Flavor: Google")
    EOF
    
  3. Carga las variables de metadatos del archivo:

    source ~/.varsrc
    
  4. Formatea el disco de datos:

    sudo bash -c  "mkfs.ext4 -m 0 -F -E  lazy_itable_init=0,lazy_journal_init=0,discard /dev/sdb"
    
  5. Instala los paquetes de DRBD:

    sudo apt -y install drbd8-utils
    
  6. Crea el archivo de configuración de DRBD:

    sudo bash -c 'cat <<EOF  > /etc/drbd.d/global_common.conf
    global {
        usage-count no;
    }
    common {
        protocol C;
    }
    EOF'
    
  7. Crea un archivo de recursos de DRBD:

    sudo bash -c "cat <<EOF  > /etc/drbd.d/r0.res
    resource r0 {
        meta-disk internal;
        device /dev/drbd0;
        net {
            allow-two-primaries no;
            after-sb-0pri discard-zero-changes;
            after-sb-1pri discard-secondary;
            after-sb-2pri disconnect;
            rr-conflict disconnect;
        }
        on ${DATABASE1_INSTANCE_NAME} {
            disk /dev/sdb;
            address ${DATABASE1_INSTANCE_IP}:7789;
        }
        on ${DATABASE2_INSTANCE_NAME} {
            disk /dev/sdb;
            address ${DATABASE2_INSTANCE_IP}:7789;
        }
    }
    EOF"
    
  8. Carga el módulo del kernel de DRBD:

    sudo modprobe drbd
    
  9. Borra el /dev/sdb disco:

    sudo dd if=/dev/zero of=/dev/sdb bs=1k count=1024
    
  10. Crea el recurso DRBD r0:

    sudo drbdadm create-md r0
    
  11. Activa DRBD:

    sudo drbdadm up r0
    
  12. Inhabilita DRBD cuando se inicie el sistema para que el software de gestión de recursos del clúster inicie todos los servicios necesarios en el orden correcto:

    sudo update-rc.d drbd disable
    

Inicia la replicación de DRBD de database1 a database2

  1. Conéctate a la instancia database1 mediante SSH.
  2. Sobrescribe todos los recursos r0 en el nodo principal:

    sudo drbdadm -- --overwrite-data-of-peer primary r0
    sudo mkfs.ext4 -m 0 -F -E lazy_itable_init=0,lazy_journal_init=0,discard /dev/drbd0
    
  3. Verifica el estado de DRBD:

    sudo cat /proc/drbd | grep ============
    

    La salida tiene este aspecto:

    [===================>] sync'ed:100.0% (208/307188)M
    
  4. Montar /dev/drbd en /srv:

    sudo mount -o discard,defaults /dev/drbd0 /srv
    

Instalar MySQL y Pacemaker

En esta sección, instalarás MySQL y Pacemaker en cada instancia.

Instalar MySQL en database1

  1. Conéctate a la instancia database1 mediante SSH.
  2. Actualiza el repositorio APT con las definiciones del paquete MySQL 5.6:

    sudo bash -c 'cat <<EOF  > /etc/apt/sources.list.d/mysql.list
    deb http://repo.mysql.com/apt/debian/ stretch mysql-5.6\ndeb-src http://repo.mysql.com/apt/debian/ stretch mysql-5.6
    EOF'
    
  3. Añade las claves GPG al archivo repository.srv de APT:

    wget -O /tmp/RPM-GPG-KEY-mysql https://repo.mysql.com/RPM-GPG-KEY-mysql
    sudo apt-key add /tmp/RPM-GPG-KEY-mysql
    
  4. Actualiza la lista de paquetes:

    sudo apt update
    
  5. Instala el servidor MySQL:

    sudo apt -y install mysql-server
    

    Cuando se te pida una contraseña, introduce DRBDha2.

  6. Detén el servidor MySQL:

    sudo /etc/init.d/mysql stop
    
  7. Crea el archivo de configuración de MySQL:

    sudo bash -c 'cat <<EOF  > /etc/mysql/mysql.conf.d/my.cnf
    [mysqld]
    bind-address = 0.0.0.0  # You may want to listen at localhost at the beginning
    datadir = /var/lib/mysql
    tmpdir = /srv/tmp
    user = mysql
    EOF'
    
  8. Crea un directorio temporal para el servidor MySQL (configurado en mysql.conf):

    sudo mkdir /srv/tmp
    sudo chmod 1777 /srv/tmp
    
  9. Mueve todos los datos de MySQL al directorio de DRBD /srv/mysql:

    sudo mv /var/lib/mysql /srv/mysql
    
  10. Vincula /var/lib/mysql con /srv/mysql en el volumen de almacenamiento replicado de DRBD:

    sudo ln -s /srv/mysql /var/lib/mysql
    
  11. Cambia el propietario de /srv/mysql a un proceso de mysql:

    sudo chown -R mysql:mysql /srv/mysql
    
  12. Elimina los datos iniciales de InnoDB para asegurarte de que el disco esté lo más limpio posible:

    sudo bash -c "cd /srv/mysql && rm ibdata1 && rm ib_logfile*"
    

    InnoDB es un motor de almacenamiento para el sistema de gestión de bases de datos MySQL.

  13. Inicia MySQL:

    sudo /etc/init.d/mysql start
    
  14. Concede acceso al usuario root para las conexiones remotas con el fin de probar la implementación más adelante:

    mysql -uroot -pDRBDha2 -e "GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'DRBDha2' WITH GRANT OPTION;"
    
  15. Inhabilita el inicio automático de MySQL, que se encarga de la gestión de recursos del clúster:

    sudo update-rc.d -f mysql disable
    

Instala Pacemaker en database1

  1. Cargue las variables de metadatos del archivo .varsrc que ha creado anteriormente:

    source ~/.varsrc
    
  2. Detén el servidor MySQL:

    sudo /etc/init.d/mysql stop
    
  3. Instalar Pacemaker:

    sudo apt -y install pcs
    
  4. Habilita pcsd, corosync y pacemaker al iniciar el sistema en la instancia principal:

    sudo update-rc.d -f pcsd enable
    sudo update-rc.d -f corosync enable
    sudo update-rc.d -f pacemaker enable
    
  5. Configura corosync para que se inicie antes que pacemaker:

    sudo update-rc.d corosync defaults 20 20
    sudo update-rc.d pacemaker defaults 30 10
    
  6. Define la contraseña del usuario del clúster como haCLUSTER3 para la autenticación:

    sudo bash -c "echo  hacluster:haCLUSTER3 | chpasswd"
    
  7. Ejecuta la secuencia de comandos corosync-keygen para generar una clave de autorización de clúster de 128 bits y escribirla en /etc/corosync/authkey:

    sudo corosync-keygen -l
    
  8. Copia authkey en la instancia database2. Cuando se te pida una contraseña, pulsa Enter:

    sudo chmod 444 /etc/corosync/authkey
    gcloud beta compute scp /etc/corosync/authkey ${DATABASE2_INSTANCE_NAME}:~/authkey --zone=${DATABASE2_INSTANCE_ZONE} --internal-ip
    sudo chmod 400 /etc/corosync/authkey
    
  9. Crea un archivo de configuración de clúster de Corosync:

    sudo bash -c "cat <<EOF  > /etc/corosync/corosync.conf
    
    totem {
        version: 2
        cluster_name: mysql_cluster
        transport: udpu
        interface {
            ringnumber: 0
            Bindnetaddr: ${DATABASE1_INSTANCE_IP}
            broadcast: yes
            mcastport: 5405
        }
    }
    quorum {
        provider: corosync_votequorum
    two_node: 1
    }
    
    nodelist {
        node {
            ring0_addr: ${DATABASE1_INSTANCE_NAME}
        name:  ${DATABASE1_INSTANCE_NAME}
    
        nodeid: 1
        }
        node {
            ring0_addr:  ${DATABASE2_INSTANCE_NAME}
            name:  ${DATABASE2_INSTANCE_NAME}
            nodeid: 2
        }
    }
    logging {
        to_logfile: yes
        logfile: /var/log/corosync/corosync.log
        timestamp: on
    }
    
    EOF"
    

    La sección totem configura el protocolo Totem para una comunicación fiable. Corosync usa esta comunicación para controlar la pertenencia al clúster y especifica cómo deben comunicarse entre sí los miembros del clúster.

    Los ajustes importantes de la configuración son los siguientes:

    • transport: especifica el modo de unidifusión (udpu).
    • Bindnetaddr: especifica la dirección de red a la que se vincula Corosync.
    • nodelist: define los nodos del clúster y cómo se puede acceder a ellos. En este caso, los nodos database1 y database2.
    • quorum/two_node: de forma predeterminada, en un clúster de dos nodos, ningún nodo adquirirá un quórum. Para anularlo, especifique el valor "1" para two_node en la sección quorum.

    Esta configuración te permite configurar el clúster y prepararlo para cuando añadas un tercer nodo que actuará como dispositivo de quórum.

  10. Crea el directorio de servicio de corosync:

    sudo mkdir -p /etc/corosync/service.d
    
  11. Configura corosync para que detecte el marcapasos:

    sudo bash -c 'cat <<EOF  > /etc/corosync/service.d/pcmk
    service {
        name: pacemaker
        ver: 1
    }
    EOF'
    
  12. Habilita el servicio corosync de forma predeterminada:

    sudo bash -c 'cat <<EOF  > /etc/default/corosync
    # Path to corosync.conf
    COROSYNC_MAIN_CONFIG_FILE=/etc/corosync/corosync.conf
    # Path to authfile
    COROSYNC_TOTEM_AUTHKEY_FILE=/etc/corosync/authkey
    # Enable service by default
    START=yes
    EOF'
    
  13. Reinicia los servicios corosync y pacemaker:

    sudo service corosync restart
    sudo service pacemaker restart
    
  14. Instala el paquete del dispositivo de quórum de Corosync:

    sudo apt -y install corosync-qdevice
    
  15. Instala un script de shell para gestionar los eventos de fallo de DRBD:

    sudo bash -c 'cat << 'EOF'  > /var/lib/pacemaker/drbd_cleanup.sh
    #!/bin/sh
    if [ -z \$CRM_alert_version ]; then
        echo "\$0 must be run by Pacemaker version 1.1.15 or later"
        exit 0
    fi
    
    tstamp="\$CRM_alert_timestamp: "
    
    case \$CRM_alert_kind in
        resource)
            if [ \${CRM_alert_interval} = "0" ]; then
                CRM_alert_interval=""
            else
                CRM_alert_interval=" (\${CRM_alert_interval})"
            fi
    
            if [ \${CRM_alert_target_rc} = "0" ]; then
                CRM_alert_target_rc=""
            else
                CRM_alert_target_rc=" (target: \${CRM_alert_target_rc})"
            fi
    
            case \${CRM_alert_desc} in
                Cancelled) ;;
                *)
                    echo "\${tstamp}Resource operation "\${CRM_alert_task}\${CRM_alert_interval}" for "\${CRM_alert_rsc}" on "\${CRM_alert_node}": \${CRM_alert_desc}\${CRM_alert_target_rc}" >> "\${CRM_alert_recipient}"
                    if [ "\${CRM_alert_task}" = "stop" ] && [ "\${CRM_alert_desc}" = "Timed Out" ]; then
                        echo "Executing recovering..." >> "\${CRM_alert_recipient}"
                        pcs resource cleanup \${CRM_alert_rsc}
                    fi
                    ;;
            esac
            ;;
        *)
            echo "\${tstamp}Unhandled \$CRM_alert_kind alert" >> "\${CRM_alert_recipient}"
            env | grep CRM_alert >> "\${CRM_alert_recipient}"
            ;;
    esac
    EOF'
    sudo chmod 0755 /var/lib/pacemaker/drbd_cleanup.sh
    sudo touch /var/log/pacemaker_drbd_file.log
    sudo chown hacluster:haclient /var/log/pacemaker_drbd_file.log
    

Instalar MySQL en database2

  1. Conéctate a la instancia database2 mediante SSH.
  2. Actualiza el repositorio APT con el paquete MySQL 5.6:

    sudo bash -c 'cat <<EOF  > /etc/apt/sources.list.d/mysql.list
    deb http://repo.mysql.com/apt/debian/ stretch mysql-5.6\ndeb-src http://repo.mysql.com/apt/debian/ stretch mysql-5.6
    EOF'
    
  3. Añade las claves GPG al repositorio de APT:

    wget -O /tmp/RPM-GPG-KEY-mysql https://repo.mysql.com/RPM-GPG-KEY-mysql
    sudo apt-key add /tmp/RPM-GPG-KEY-mysql
    
  4. Actualiza la lista de paquetes:

    sudo apt update
    
  5. Instala el servidor MySQL:

    sudo apt -y install mysql-server
    

    Cuando se te pida una contraseña, introduce DRBDha2.

  6. Detén el servidor MySQL:

    sudo /etc/init.d/mysql stop
    
  7. Crea el archivo de configuración de MySQL:

    sudo bash -c 'cat <<EOF  > /etc/mysql/mysql.conf.d/my.cnf
    [mysqld]
    bind-address = 0.0.0.0  # You may want to listen at localhost at the beginning
    datadir = /var/lib/mysql
    tmpdir = /srv/tmp
    user = mysql
    EOF'
    
  8. Elimina los datos de /var/lib/mysql y añade un enlace simbólico al destino del punto de montaje del volumen DRBD replicado. El volumen de DRBD (/dev/drbd0) se montará en /srv solo cuando se produzca una conmutación por error.

    sudo rm -rf /var/lib/mysql
    sudo ln -s /srv/mysql /var/lib/mysql
    
  9. Inhabilita el inicio automático de MySQL, que se encarga de la gestión de recursos del clúster:

    sudo update-rc.d -f mysql disable
    

Instalar Pacemaker en database2

  1. Cargue las variables de metadatos del archivo .varsrc:

    source ~/.varsrc
    
  2. Instalar Pacemaker:

    sudo apt -y install pcs
    
  3. Mueve el archivo authkey de Corosync que has copiado antes a /etc/corosync/:

    sudo mv ~/authkey /etc/corosync/
    sudo chown root: /etc/corosync/authkey
    sudo chmod 400 /etc/corosync/authkey
    
  4. Habilita pcsd, corosync y pacemaker al iniciar el sistema en la instancia de espera:

    sudo update-rc.d -f pcsd enable
    sudo update-rc.d -f corosync enable
    sudo update-rc.d -f pacemaker enable
    
  5. Configura corosync para que se inicie antes que pacemaker:

    sudo update-rc.d corosync defaults 20 20
    sudo update-rc.d pacemaker defaults 30 10
    
  6. Define la contraseña del usuario del clúster para la autenticación. La contraseña es la misma (haCLUSTER3) que usaste para la instancia de database1.

    sudo bash -c "echo  hacluster:haCLUSTER3 | chpasswd"
    
  7. Crea el archivo de configuración corosync:

    sudo bash -c "cat <<EOF  > /etc/corosync/corosync.conf
    
    totem {
        version: 2
        cluster_name: mysql_cluster
        transport: udpu
        interface {
            ringnumber: 0
            Bindnetaddr: ${DATABASE2_INSTANCE_IP}
            broadcast: yes
            mcastport: 5405
        }
    }
    quorum {
        provider: corosync_votequorum
        two_node: 1
    }
    nodelist {
        node {
            ring0_addr: ${DATABASE1_INSTANCE_NAME}
            name: ${DATABASE1_INSTANCE_NAME}
            nodeid: 1
        }
        node {
            ring0_addr: ${DATABASE2_INSTANCE_NAME}
            name: ${DATABASE2_INSTANCE_NAME}
            nodeid: 2
        }
    }
    logging {
        to_logfile: yes
        logfile: /var/log/corosync/corosync.log
    timestamp: on
    }
    EOF"
    
  8. Crea el directorio de servicio de Corosync:

    sudo mkdir /etc/corosync/service.d
    
  9. Configura corosync para que detecte el marcapasos:

    sudo bash -c 'cat <<EOF  > /etc/corosync/service.d/pcmk
    service {
    name: pacemaker
    ver: 1
    }
    EOF'
    
  10. Habilita el servicio corosync de forma predeterminada:

    sudo bash -c 'cat <<EOF  > /etc/default/corosync
    # Path to corosync.conf
    COROSYNC_MAIN_CONFIG_FILE=/etc/corosync/corosync.conf
    # Path to authfile
    COROSYNC_TOTEM_AUTHKEY_FILE=/etc/corosync/authkey
    # Enable service by default
    START=yes
    EOF'
    
  11. Reinicia los servicios corosync y pacemaker:

    sudo service corosync restart
    sudo service pacemaker restart
    
  12. Instala el paquete del dispositivo de quórum de Corosync:

    sudo apt -y install corosync-qdevice
    
  13. Instala un script de shell para gestionar los eventos de fallo de DRBD:

    sudo bash -c 'cat << 'EOF'  > /var/lib/pacemaker/drbd_cleanup.sh
    #!/bin/sh
    if [ -z \$CRM_alert_version ]; then
        echo "\$0 must be run by Pacemaker version 1.1.15 or later"
        exit 0
    fi
    
    tstamp="\$CRM_alert_timestamp: "
    
    case \$CRM_alert_kind in
        resource)
            if [ \${CRM_alert_interval} = "0" ]; then
                CRM_alert_interval=""
            else
                CRM_alert_interval=" (\${CRM_alert_interval})"
            fi
    
            if [ \${CRM_alert_target_rc} = "0" ]; then
                CRM_alert_target_rc=""
            else
                CRM_alert_target_rc=" (target: \${CRM_alert_target_rc})"
            fi
    
            case \${CRM_alert_desc} in
                Cancelled) ;;
                *)
                    echo "\${tstamp}Resource operation "\${CRM_alert_task}\${CRM_alert_interval}" for "\${CRM_alert_rsc}" on "\${CRM_alert_node}": \${CRM_alert_desc}\${CRM_alert_target_rc}" >> "\${CRM_alert_recipient}"
                    if [ "\${CRM_alert_task}" = "stop" ] && [ "\${CRM_alert_desc}" = "Timed Out" ]; then
                        echo "Executing recovering..." >> "\${CRM_alert_recipient}"
                        pcs resource cleanup \${CRM_alert_rsc}
                    fi
                    ;;
            esac
            ;;
        *)
            echo "\${tstamp}Unhandled \$CRM_alert_kind alert" >> "\${CRM_alert_recipient}"
            env | grep CRM_alert >> "\${CRM_alert_recipient}"
            ;;
    esac
    EOF'
    sudo chmod 0755 /var/lib/pacemaker/drbd_cleanup.sh
    sudo touch /var/log/pacemaker_drbd_file.log
    sudo chown hacluster:haclient /var/log/pacemaker_drbd_file.log
    
  14. Comprueba el estado del clúster de Corosync:

    sudo corosync-cmapctl | grep "members...ip"
    

    La salida tiene este aspecto:

    runtime.totem.pg.mrp.srp.members.1.ip (str) = r(0) ip(10.140.0.2)
    runtime.totem.pg.mrp.srp.members.2.ip (str) = r(0) ip(10.140.0.3)
    

Iniciar el clúster

  1. Conéctate a la instancia database2 mediante SSH.
  2. Cargue las variables de metadatos del archivo .varsrc:

    source ~/.varsrc
    
  3. Autentícate en los nodos del clúster:

    sudo pcs cluster auth --name mysql_cluster ${DATABASE1_INSTANCE_NAME} ${DATABASE2_INSTANCE_NAME} -u hacluster -p haCLUSTER3
    
  4. Inicia el clúster:

    sudo pcs cluster start --all
    
  5. Verifica el estado del clúster:

    sudo pcs status
    

    La salida tiene este aspecto:

    Cluster name: mysql_cluster
    WARNING: no stonith devices and stonith-enabled is not false
    Stack: corosync
    Current DC: database2 (version 1.1.16-94ff4df) - partition with quorum
    Last updated: Sat Nov  3 07:24:53 2018
    Last change: Sat Nov  3 07:17:17 2018 by hacluster via crmd on database2
    
    2 nodes configured
    0 resources configured
    
    Online: [ database1 database2 ]
    
    No resources
    
    Daemon Status:
      corosync: active/enabled
      pacemaker: active/enabled
      pcsd: active/enabled
    

Configurar Pacemaker para gestionar los recursos del clúster

A continuación, configura Pacemaker con los recursos DRBD, de disco, MySQL y de quórum.

  1. Conéctate a la instancia database1 mediante SSH.
  2. Usa la utilidad Pacemaker pcs para poner en cola varios cambios en un archivo y, más adelante, enviar esos cambios a la base de información del clúster (CIB) de forma atómica:

    sudo pcs cluster cib clust_cfg
    
  3. Inhabilita STONITH, porque implementarás el dispositivo de quórum más adelante:

    sudo pcs -f clust_cfg property set stonith-enabled=false
    
  4. Inhabilita los ajustes relacionados con el quórum. Configurarás el nodo del dispositivo de quórum más adelante.

    sudo pcs -f clust_cfg property set no-quorum-policy=stop
    
  5. Para evitar que Pacemaker vuelva a mover los recursos después de una recuperación, haz lo siguiente:

    sudo pcs -f clust_cfg resource defaults resource-stickiness=200
    
  6. Crea el recurso DRBD en el clúster:

    sudo pcs -f clust_cfg resource create mysql_drbd ocf:linbit:drbd \
        drbd_resource=r0 \
        op monitor role=Master interval=110 timeout=30 \
        op monitor role=Slave interval=120 timeout=30 \
        op start timeout=120 \
        op stop timeout=60
    
  7. Asegúrate de que solo se asigne un rol principal al recurso DRBD:

    sudo pcs -f clust_cfg resource master primary_mysql mysql_drbd \
        master-max=1 master-node-max=1 \
        clone-max=2 clone-node-max=1 \
        notify=true
    
  8. Crea el recurso del sistema de archivos para montar el disco DRBD:

    sudo pcs -f clust_cfg resource create mystore_FS Filesystem \
        device="/dev/drbd0" \
        directory="/srv" \
        fstype="ext4"
    
  9. Configura el clúster para que coloque el recurso DRBD junto con el recurso de disco en la misma máquina virtual:

    sudo pcs -f clust_cfg constraint colocation add mystore_FS with primary_mysql INFINITY with-rsc-role=Master
    
  10. Configura el clúster para que active el recurso de disco solo después de que se haya promovido el primario de DRBD:

    sudo pcs -f clust_cfg constraint order promote primary_mysql then start mystore_FS
    
  11. Crea un servicio MySQL:

    sudo pcs -f clust_cfg resource create mysql_service ocf:heartbeat:mysql \
        binary="/usr/bin/mysqld_safe" \
        config="/etc/mysql/my.cnf" \
        datadir="/var/lib/mysql" \
        pid="/var/run/mysqld/mysql.pid" \
        socket="/var/run/mysqld/mysql.sock" \
        additional_parameters="--bind-address=0.0.0.0" \
        op start timeout=60s \
        op stop timeout=60s \
        op monitor interval=20s timeout=30s
    
  12. Configura el clúster para colocar el recurso de MySQL junto con el recurso de disco en la misma VM:

    sudo pcs -f clust_cfg constraint colocation add mysql_service with mystore_FS INFINITY
    
  13. Asegúrate de que el sistema de archivos DRBD preceda al servicio MySQL en el orden de inicio:

    sudo pcs -f clust_cfg constraint order mystore_FS then mysql_service
    
  14. Crea el agente de alerta y añade el parche al archivo de registro como destinatario:

    sudo pcs -f clust_cfg alert create id=drbd_cleanup_file description="Monitor DRBD events and perform post cleanup" path=/var/lib/pacemaker/drbd_cleanup.sh
    sudo pcs -f clust_cfg alert recipient add drbd_cleanup_file id=logfile value=/var/log/pacemaker_drbd_file.log
    
  15. Confirma los cambios en el clúster:

    sudo pcs cluster cib-push clust_cfg
    
  16. Verifica que todos los recursos estén online:

    sudo pcs status
    

    La salida tiene este aspecto:

    Online: [ database1 database2 ]
    
    Full list of resources:
     Master/Slave Set: primary_mysql [mysql_drbd]
         Masters: [ database1 ]
         Slaves: [ database2 ]
     mystore_FS     (ocf::heartbeat:Filesystem):    Started database1
     mysql_service  (ocf::heartbeat:mysql): Started database1
    

Configurar un dispositivo de quórum

  1. Conéctate a la instancia qdevice mediante SSH.
  2. Instala pcs y corosync-qnetd:

    sudo apt update && sudo apt -y install pcs corosync-qnetd
    
  3. Inicia el daemon del sistema de configuración de Pacemaker o Corosync (pcsd) service y habilítalo al iniciar el sistema:

    sudo service pcsd start
    sudo update-rc.d pcsd enable
    
  4. Define la contraseña del usuario del clúster (haCLUSTER3) para la autenticación:

    sudo bash -c "echo  hacluster:haCLUSTER3 | chpasswd"
    
  5. Comprueba el estado del dispositivo de quorum:

    sudo pcs qdevice status net --full
    

    La salida tiene este aspecto:

    QNetd address:                  *:5403
    TLS:                            Supported (client certificate required)
    Connected clients:              0
    Connected clusters:             0
    Maximum send/receive size:      32768/32768 bytes
    

Configurar los ajustes del dispositivo de quórum en database1

  1. Conéctate al nodo database1 mediante SSH.
  2. Cargue las variables de metadatos del archivo .varsrc:

    source ~/.varsrc
    
  3. Autentica el nodo del dispositivo de quórum del clúster:

    sudo pcs cluster auth --name mysql_cluster ${QUORUM_INSTANCE_NAME} -u hacluster -p haCLUSTER3
    
  4. Añade el dispositivo de quorum al clúster. Usa el algoritmo ffsplit, que asegura que el nodo activo se decida en función del 50% de los votos o más:

    sudo pcs quorum device add model net host=${QUORUM_INSTANCE_NAME} algorithm=ffsplit
    
  5. Añade el ajuste de quórum a corosync.conf:

    sudo bash -c "cat <<EOF  > /etc/corosync/corosync.conf
    
    totem {
        version: 2
        cluster_name: mysql_cluster
        transport: udpu
        interface {
            ringnumber: 0
            Bindnetaddr: ${DATABASE1_INSTANCE_IP}
            broadcast: yes
            mcastport: 5405
        }
    }
    
    quorum {
        provider: corosync_votequorum
        device {
            votes: 1
            model: net
            net {
                tls: on
                host: ${QUORUM_INSTANCE_NAME}
                algorithm: ffsplit
            }
        }
    }
    
    nodelist {
        node {
            ring0_addr: ${DATABASE1_INSTANCE_NAME}
            name: ${DATABASE1_INSTANCE_NAME}
            nodeid: 1
        }
        node {
            ring0_addr: ${DATABASE2_INSTANCE_NAME}
            name: ${DATABASE2_INSTANCE_NAME}
            nodeid: 2
        }
    }
    
    logging {
        to_logfile: yes
        logfile: /var/log/corosync/corosync.log
        timestamp: on
    }
    
    EOF"
    
  6. Reinicia el servicio corosync para volver a cargar el nuevo ajuste del dispositivo de quórum:

    sudo service corosync restart
    
  7. Inicia el daemon del dispositivo de quórum corosync y actívalo al inicio del sistema:

    sudo service corosync-qdevice start
    sudo update-rc.d corosync-qdevice defaults
    

Configurar los ajustes del dispositivo de quórum en database2

  1. Conéctate al nodo database2 mediante SSH.
  2. Cargue las variables de metadatos del archivo .varsrc:

    source ~/.varsrc
    
  3. Añadir un ajuste de quórum a corosync.conf:

    sudo bash -c "cat <<EOF  > /etc/corosync/corosync.conf
    
    totem {
        version: 2
        cluster_name: mysql_cluster
        transport: udpu
        interface {
            ringnumber: 0
            Bindnetaddr: ${DATABASE2_INSTANCE_IP}
            broadcast: yes
            mcastport: 5405
        }
    }
    
    quorum {
        provider: corosync_votequorum
        device {
            votes: 1
            model: net
            net {
                tls: on
                host: ${QUORUM_INSTANCE_NAME}
                algorithm: ffsplit
            }
        }
    }
    
    nodelist {
        node {
            ring0_addr: ${DATABASE1_INSTANCE_NAME}
            name: ${DATABASE1_INSTANCE_NAME}
            nodeid: 1
        }
        node {
            ring0_addr: ${DATABASE2_INSTANCE_NAME}
            name: ${DATABASE2_INSTANCE_NAME}
            nodeid: 2
        }
    }
    
    logging {
        to_logfile: yes
        logfile: /var/log/corosync/corosync.log
        timestamp: on
    }
    
    EOF"
    
  4. Reinicia el servicio corosync para volver a cargar el nuevo ajuste del dispositivo de quórum:

    sudo service corosync restart
    
  5. Inicia el daemon del dispositivo de quórum de Corosync y configúralo para que se inicie al arrancar el sistema:

    sudo service corosync-qdevice start
    sudo update-rc.d corosync-qdevice defaults
    

Verificar el estado del clúster

El siguiente paso es verificar que los recursos del clúster estén online.

  1. Conéctate a la instancia database1 mediante SSH.
  2. Verifica el estado del clúster:

    sudo pcs status
    

    La salida tiene este aspecto:

    Cluster name: mysql_cluster
    Stack: corosync
    Current DC: database1 (version 1.1.16-94ff4df) - partition with quorum
    Last updated: Sun Nov  4 01:49:18 2018
    Last change: Sat Nov  3 15:48:21 2018 by root via cibadmin on database1
    
    2 nodes configured
    4 resources configured
    
    Online: [ database1 database2 ]
    
    Full list of resources:
    
     Master/Slave Set: primary_mysql [mysql_drbd]
         Masters: [ database1 ]
         Slaves: [ database2 ]
     mystore_FS     (ocf::heartbeat:Filesystem):    Started database1
     mysql_service  (ocf::heartbeat:mysql): Started database1
    
    Daemon Status:
      corosync: active/enabled
      pacemaker: active/enabled
      pcsd: active/enabled
    
  3. Mostrar el estado del quórum:

    sudo pcs quorum status
    

    La salida tiene este aspecto:

    Quorum information
    ------------------
    Date:             Sun Nov  4 01:48:25 2018
    Quorum provider:  corosync_votequorum
    Nodes:            2
    Node ID:          1
    Ring ID:          1/24
    Quorate:          Yes
    
    Votequorum information
    ----------------------
    Expected votes:   3
    Highest expected: 3
    Total votes:      3
    Quorum:           2
    Flags:            Quorate Qdevice
    
    Membership information
    ----------------------
        Nodeid      Votes    Qdevice Name
             1          1    A,V,NMW database1 (local)
             2          1    A,V,NMW database2
             0          1            Qdevice
    
  4. Muestra el estado del dispositivo de quórum:

    sudo pcs quorum device status
    

    La salida tiene este aspecto:

    Qdevice information
    -------------------
    Model:                  Net
    Node ID:                1
    Configured node list:
        0   Node ID = 1
        1   Node ID = 2
    Membership node list:   1, 2
    
    Qdevice-net information
    ----------------------
    Cluster name:           mysql_cluster
    QNetd host:             qdevice:5403
    Algorithm:              Fifty-Fifty split
    Tie-breaker:            Node with lowest node ID
    State:                  Connected
    

Configurar un balanceador de carga interno como IP de clúster

  1. Abre Cloud Shell:

    ABRIR Cloud Shell

  2. Crea un grupo de instancias sin gestionar y añade la instancia database1:

    gcloud compute instance-groups unmanaged create ${DATABASE1_INSTANCE_NAME}-instance-group \
        --zone=${DATABASE1_INSTANCE_ZONE} \
        --description="${DATABASE1_INSTANCE_NAME} unmanaged instance group"
    
    gcloud compute instance-groups unmanaged add-instances ${DATABASE1_INSTANCE_NAME}-instance-group \
        --zone=${DATABASE1_INSTANCE_ZONE} \
        --instances=${DATABASE1_INSTANCE_NAME}
    
  3. Crea un grupo de instancias sin gestionar y añade la instancia database2:

    gcloud compute instance-groups unmanaged create ${DATABASE2_INSTANCE_NAME}-instance-group \
        --zone=${DATABASE2_INSTANCE_ZONE} \
        --description="${DATABASE2_INSTANCE_NAME} unmanaged instance group"
    
    gcloud compute instance-groups unmanaged add-instances ${DATABASE2_INSTANCE_NAME}-instance-group \
        --zone=${DATABASE2_INSTANCE_ZONE} \
        --instances=${DATABASE2_INSTANCE_NAME}
    
  4. Crea una comprobación del estado para port 3306:

    gcloud compute health-checks create tcp mysql-backend-healthcheck \
        --port 3306
    
  5. Crea un servicio backend interno regional:

    gcloud compute backend-services create mysql-ilb \
        --load-balancing-scheme internal \
        --region ${CLUSTER_REGION} \
        --health-checks mysql-backend-healthcheck \
        --protocol tcp
    
  6. Añade los dos grupos de instancias como backends al servicio de backend:

    gcloud compute backend-services add-backend mysql-ilb \
        --instance-group ${DATABASE1_INSTANCE_NAME}-instance-group \
        --instance-group-zone ${DATABASE1_INSTANCE_ZONE} \
        --region ${CLUSTER_REGION}
    
    gcloud compute backend-services add-backend mysql-ilb \
        --instance-group ${DATABASE2_INSTANCE_NAME}-instance-group \
        --instance-group-zone ${DATABASE2_INSTANCE_ZONE} \
        --region ${CLUSTER_REGION}
    
  7. Crea una regla de reenvío para el balanceador de carga:

    gcloud compute forwarding-rules create mysql-ilb-forwarding-rule \
        --load-balancing-scheme internal \
        --ports 3306 \
        --network default \
        --subnet default \
        --region ${CLUSTER_REGION} \
        --address ${ILB_IP} \
        --backend-service mysql-ilb
    
  8. Crea una regla de cortafuegos para permitir una comprobación del estado de un balanceador de carga interno:

    gcloud compute firewall-rules create allow-ilb-healthcheck \
        --direction=INGRESS --network=default \
        --action=ALLOW --rules=tcp:3306 \
        --source-ranges=130.211.0.0/22,35.191.0.0/16 --target-tags=mysql
    
  9. Para comprobar el estado de tu balanceador de carga, ve a la página Balanceo de carga de la Google Cloud consola.

    ABRIR LA PÁGINA DE BALANCEO DE CARGA

  10. Haz clic en mysql-ilb:

    imagen

    Como el clúster solo permite que se ejecute una instancia de MySQL en un momento dado, solo una instancia está en buen estado desde la perspectiva del balanceador de carga interno.

    imagen

Conectarse al clúster desde el cliente MySQL

  1. Conéctate a la instancia mysql-client mediante SSH.
  2. Actualiza las definiciones de los paquetes:

    sudo apt-get update
    
  3. Instala el cliente de MySQL:

    sudo apt-get install -y mysql-client
    
  4. Crea un archivo de secuencia de comandos que cree y rellene una tabla con datos de ejemplo:

    cat <<EOF > db_creation.sql
    CREATE DATABASE source_db;
    use source_db;
    CREATE TABLE source_table
    (
        id BIGINT NOT NULL AUTO_INCREMENT,
        timestamp timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
        event_data float DEFAULT NULL,
        PRIMARY KEY (id)
    );
    DELIMITER $$
    CREATE PROCEDURE simulate_data()
    BEGIN
    DECLARE i INT DEFAULT 0;
    WHILE i < 100 DO
        INSERT INTO source_table (event_data) VALUES (ROUND(RAND()*15000,2));
        SET i = i + 1;
    END WHILE;
    END$$
    DELIMITER ;
    CALL simulate_data()
    EOF
    
  5. Crea la tabla:

    ILB_IP=$(curl -s "http://metadata.google.internal/computeMetadata/v1/instance/attributes/ILB_IP" -H "Metadata-Flavor: Google")
    mysql -u root -pDRBDha2 "-h${ILB_IP}" < db_creation.sql
    

Probar el clúster

Para probar la capacidad de alta disponibilidad del clúster implementado, puedes realizar las siguientes pruebas:

  • Cierra la instancia database1 para comprobar si la base de datos principal puede conmutar por error a la instancia database2.
  • Inicia la instancia database1 para ver si database1 puede volver a unirse al clúster correctamente.
  • Cierra la instancia database2 para comprobar si la base de datos principal puede conmutar por error a la instancia database1.
  • Inicia la instancia database2 para ver si database2 puede volver a unirse al clúster correctamente y si la instancia database1 sigue teniendo el rol principal.
  • Crea una partición de red entre database1 y database2 para simular un problema de cerebro dividido.

  1. Abre Cloud Shell:

    ABRIR Cloud Shell

  2. Detén la instancia database1:

    gcloud compute instances stop ${DATABASE1_INSTANCE_NAME} \
        --zone=${DATABASE1_INSTANCE_ZONE}
    
  3. Comprueba el estado del clúster:

    gcloud compute ssh ${DATABASE2_INSTANCE_NAME} \
        --zone=${DATABASE2_INSTANCE_ZONE} \
        --command="sudo pcs status"
    

    La salida tiene el siguiente aspecto. Verifica que los cambios de configuración que has realizado se hayan aplicado:

    2 nodes configured
    4 resources configured
    
    Online: [ database2 ]
    OFFLINE: [ database1 ]
    
    Full list of resources:
    
     Master/Slave Set: primary_mysql [mysql_drbd]
         Masters: [ database2 ]
         Stopped: [ database1 ]
     mystore_FS     (ocf::heartbeat:Filesystem):    Started database2
     mysql_service  (ocf::heartbeat:mysql): Started database2
    
    Daemon Status:
      corosync: active/enabled
      pacemaker: active/enabled
      pcsd: active/enabled
    
  4. Inicia la instancia database1:

    gcloud compute instances start ${DATABASE1_INSTANCE_NAME} \
        --zone=${DATABASE1_INSTANCE_ZONE}
    
  5. Comprueba el estado del clúster:

    gcloud compute ssh ${DATABASE1_INSTANCE_NAME} \
        --zone=${DATABASE1_INSTANCE_ZONE} \
        --command="sudo pcs status"
    

    La salida tiene este aspecto:

    2 nodes configured
    4 resources configured
    
    Online: [ database1 database2 ]
    
    Full list of resources:
    
     Master/Slave Set: primary_mysql [mysql_drbd]
         Masters: [ database2 ]
         Slaves: [ database1 ]
     mystore_FS     (ocf::heartbeat:Filesystem):    Started database2
     mysql_service  (ocf::heartbeat:mysql): Started database2
    
    Daemon Status:
      corosync: active/enabled
      pacemaker: active/enabled
      pcsd: active/enabled
    
  6. Detén la instancia database2:

    gcloud compute instances stop ${DATABASE2_INSTANCE_NAME} \
        --zone=${DATABASE2_INSTANCE_ZONE}
    
  7. Comprueba el estado del clúster:

    gcloud compute ssh ${DATABASE1_INSTANCE_NAME} \
        --zone=${DATABASE1_INSTANCE_ZONE} \
        --command="sudo pcs status"
    

    La salida tiene este aspecto:

    2 nodes configured
    4 resources configured
    
    Online: [ database1 ]
    OFFLINE: [ database2 ]
    
    Full list of resources:
    
     Master/Slave Set: primary_mysql [mysql_drbd]
         Masters: [ database1 ]
         Stopped: [ database2 ]
     mystore_FS     (ocf::heartbeat:Filesystem):    Started database1
     mysql_service  (ocf::heartbeat:mysql): Started database1
    
    Daemon Status:
      corosync: active/enabled
      pacemaker: active/enabled
      pcsd: active/enabled
    
  8. Inicia la instancia database2:

    gcloud compute instances start ${DATABASE2_INSTANCE_NAME} \
        --zone=${DATABASE2_INSTANCE_ZONE}
    
  9. Comprueba el estado del clúster:

    gcloud compute ssh ${DATABASE1_INSTANCE_NAME} \
        --zone=${DATABASE1_INSTANCE_ZONE} \
        --command="sudo pcs status"
    

    La salida tiene este aspecto:

    2 nodes configured
    4 resources configured
    
    Online: [ database1 database2 ]
    
    Full list of resources:
    
     Master/Slave Set: primary_mysql [mysql_drbd]
         Masters: [ database1 ]
         Slaves: [ database2 ]
     mystore_FS     (ocf::heartbeat:Filesystem):    Started database1
     mysql_service  (ocf::heartbeat:mysql): Started database1
    
    Daemon Status:
      corosync: active/enabled
      pacemaker: active/enabled
      pcsd: active/enabled
    
  10. Crea una partición de red entre database1 y database2:

    gcloud compute firewall-rules create block-comms \
        --description="no MySQL communications" \
        --action=DENY \
        --rules=all \
        --source-tags=mysql \
        --target-tags=mysql \
        --priority=800
    
  11. Al cabo de un par de minutos, comprueba el estado del clúster. Fíjate en cómo database1 mantiene su rol principal, ya que la política de quórum es el nodo con el ID más bajo en primer lugar en caso de partición de red. Mientras tanto, el servicio MySQL database2 se detiene. Este mecanismo de quórum evita el problema de cerebro dividido cuando se produce la partición de la red.

    gcloud compute ssh ${DATABASE1_INSTANCE_NAME} \
        --zone=${DATABASE1_INSTANCE_ZONE} \
        --command="sudo pcs status"
    

    La salida tiene este aspecto:

    2 nodes configured
    4 resources configured
    
    Online: [ database1 ]
    OFFLINE: [ database2 ]
    
    Full list of resources:
     Master/Slave Set: primary_mysql [mysql_drbd]
         Masters: [ database1 ]
         Stopped: [ database2 ]
     mystore_FS     (ocf::heartbeat:Filesystem):    Started database1
     mysql_service  (ocf::heartbeat:mysql): Started database1
    
  12. Elimina la regla de cortafuegos de la red para quitar la partición de la red. (Pulsa Y cuando se te solicite).

    gcloud compute firewall-rules delete block-comms
    
  13. Verifica que el estado del clúster haya vuelto a la normalidad:

    gcloud compute ssh ${DATABASE1_INSTANCE_NAME} \
        --zone=${DATABASE1_INSTANCE_ZONE} \
        --command="sudo pcs status"
    

    La salida tiene este aspecto:

    2 nodes configured
    4 resources configured
    
    Online: [ database1 database2 ]
    
    Full list of resources:
    
     Master/Slave Set: primary_mysql [mysql_drbd]
         Masters: [ database1 ]
         Slaves: [ database2 ]
     mystore_FS     (ocf::heartbeat:Filesystem):    Started database1
     mysql_service  (ocf::heartbeat:mysql): Started database1
    
  14. Conéctate a la instancia mysql-client mediante SSH.

  15. En tu shell, consulta la tabla que has creado anteriormente:

    ILB_IP=$(curl -s "http://metadata.google.internal/computeMetadata/v1/instance/attributes/ILB_IP" -H "Metadata-Flavor: Google")
    
    mysql -uroot "-h${ILB_IP}" -pDRBDha2 -e "select * from source_db.source_table LIMIT 10"
    

    La salida debe mostrar 10 registros con el siguiente formato para verificar la coherencia de los datos en el clúster:

    +----+---------------------+------------+
    | id | timestamp           | event_data |
    +----+---------------------+------------+
    |  1 | 2018-11-27 21:00:09 |    1279.06 |
    |  2 | 2018-11-27 21:00:09 |    4292.64 |
    |  3 | 2018-11-27 21:00:09 |    2626.01 |
    |  4 | 2018-11-27 21:00:09 |     252.13 |
    |  5 | 2018-11-27 21:00:09 |    8382.64 |
    |  6 | 2018-11-27 21:00:09 |    11156.8 |
    |  7 | 2018-11-27 21:00:09 |      636.1 |
    |  8 | 2018-11-27 21:00:09 |    14710.1 |
    |  9 | 2018-11-27 21:00:09 |    11642.1 |
    | 10 | 2018-11-27 21:00:09 |    14080.3 |
    +----+---------------------+------------+
    

Secuencia de conmutación por error

Si el nodo principal del clúster deja de funcionar, la secuencia de conmutación por error será la siguiente:

  1. Tanto el dispositivo de quórum como el nodo de reserva pierden la conectividad con el nodo principal.
  2. El dispositivo de quórum vota por el nodo de espera y el nodo de espera vota por sí mismo.
  3. El nodo en espera adquiere el quórum.
  4. El nodo de reserva se convierte en principal.
  5. El nuevo nodo principal hace lo siguiente:
    1. Promueve DRBD a primario
    2. Monta el disco de datos de MySQL desde DRBD.
    3. Inicia MySQL.
    4. Se pone en buen estado para el balanceador de carga.
  6. El balanceador de carga empieza a enviar tráfico al nuevo nodo principal.