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

Last reviewed 2019-05-10 UTC

En este instructivo, se explica el proceso de implementación de una base de datos de MySQL 5.6 en Google Cloud mediante un dispositivo de bloques replicados distribuidos (DRBD) y Compute Engine. DRBD es un sistema de almacenamiento replicado distribuido para la plataforma Linux.

Este instructivo te resultará útil si eres un administrador de sistemas, desarrollador, ingeniero, administrador de base de datos o ingeniero DevOps. Es posible que desees administrar tu propia instancia de MySQL en lugar de usar el servicio administrado por varias razones, entre ellas:

  • Usas instancias de MySQL entre regiones.
  • Debes configurar los parámetros que no están disponibles en la versión administrada de MySQL.
  • Deseas optimizar el rendimiento de formas que no se pueden configurar en la versión administrada.

DRBD proporciona replicación a nivel del dispositivo de bloques. Esto significa que no debes configurar la replicación en MySQL y obtienes beneficios de DRBD inmediatos, por ejemplo, compatibilidad con balanceo de cargas de lectura y conexiones seguras.

En el instructivo, se usan los siguientes sistemas:

No se requieren conocimientos avanzados para usar estos recursos, aunque en este documento, se hace referencia a competencias avanzadas como el agrupamiento en clústeres de MySQL, la configuración de DRBD y la administración de recursos de Linux.

Arquitectura

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

Implementarás un clúster administrado por Pacemaker de tres instancias de procesamiento. Instalarás MySQL en dos instancias, que actúan como la instancia principal y en espera. La tercera instancia actúa como un dispositivo de quórum.

En un clúster, cada nodo vota por el que debería 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 ocasionar problemas de cerebro dividido o tiempo de inactividad. Los problemas de cerebro dividido ocurren cuando ambos nodos toman el control porque solo se necesita un voto en una situación de dos nodos. El tiempo de inactividad se produce cuando el nodo que se detiene es el que está configurado para ser el principal en caso de pérdida de la conectividad. Si ambos nodos pierden conectividad entre sí, existe el riesgo de que más de un nodo de clúster suponga que es el nodo activo.

Agregar un dispositivo de quórum evita esta situación. Un dispositivo de quórum funciona como árbitro, su único trabajo es emitir un voto. De esta manera, en una situación en la que las instancias database1 y database2 no puedan comunicarse, este nodo de dispositivo de quórum puede comunicarse con una de las dos instancias y se puede llegar a una mayoría.

En el siguiente diagrama, se muestra la arquitectura del sistema descrito aquí.

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

Objetivos

  • Crear las instancias de clústeres
  • Instalar MySQL y DRBD en dos instancias
  • Configurar la replicación de DRBD
  • Instalar Pacemaker en las instancias
  • Configurar el agrupamiento en clústeres de Pacemaker en las instancias
  • Crear una instancia y configurarla como un dispositivo de quórum
  • Probar la conmutación por error

Costos

Usa la calculadora de precios para generar una estimación de los costos según el uso previsto.

Antes de comenzar

  1. Accede a tu cuenta de Google Cloud. Si eres nuevo en Google Cloud, crea una cuenta para evaluar el rendimiento de nuestros productos en situaciones reales. Los clientes nuevos también obtienen $300 en créditos gratuitos para ejecutar, probar y, además, implementar cargas de trabajo.
  2. En la página del selector de proyectos de la consola de Google Cloud, selecciona o crea un proyecto de Google Cloud.

    Ir al selector de proyectos

  3. Asegúrate de que la facturación esté habilitada para tu proyecto de Google Cloud.

  4. Habilita la API de Compute Engine.

    Habilita la API

  5. En la página del selector de proyectos de la consola de Google Cloud, selecciona o crea un proyecto de Google Cloud.

    Ir al selector de proyectos

  6. Asegúrate de que la facturación esté habilitada para tu proyecto de Google Cloud.

  7. Habilita la API de Compute Engine.

    Habilita la API

En este instructivo, ingresarás comandos con Cloud Shell, a menos que se indique lo contrario.

Cuando finalices las tareas que se describen en este documento, puedes borrar los recursos que creaste para evitar que continúe la facturación. Para obtener más información, consulta Cómo realizar una limpieza.

Configuración

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

Configura una cuenta de servicio para las instancias de clústeres

  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. Adjunta las funciones necesarias para este instructivo 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
    

Crea variables de entorno de Cloud Shell

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

    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 cargue de forma automática las variables cuando accedas en el futuro:

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

Reserva 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
    

Crea las instancias de Compute Engine

En los pasos siguientes, las instancias de clústeres usan Debian 9 y las instancias de 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 quórum para que Pacemaker lo use 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 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}"
    

Instala y configura DRBD

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

Configura DRBD en database1

  1. En la consola de Google Cloud, 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 recuperar 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 desde el 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 mkfs.ext4, consulta la página de manual 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 de 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 de DRBD r0:

    sudo drbdadm create-md r0
    
  12. Abre DRBD:

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

    sudo update-rc.d drbd disable
    

Configura DRBD en database2

Ahora instalarás y configurarás los paquetes de DRBD en la instancia database2.

  1. Conéctate a la instancia database2 a través de SSH.
  2. Crea un archivo .varsrc para recuperar 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 desde el 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 de kernel de DRBD:

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

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

    sudo drbdadm create-md r0
    
  11. Abre DRBD:

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

    sudo update-rc.d drbd disable
    

Inicia la replicación de DRBD de database1 a database2

  1. Conéctate a la instancia database1 a través de SSH.
  2. Reemplaza todos los recursos r0en 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 obtenida se verá así:

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

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

Instala MySQL y Pacemaker

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

Instala MySQL en database1

  1. Conéctate a la instancia database1 a través de SSH.
  2. Actualiza el repositorio de APT con las definiciones del paquete de 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. Agrega las claves de 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 solicite una contraseña, ingresa 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 a /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. Quita 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 administración de bases de datos de MySQL.

  13. Inicia MySQL:

    sudo /etc/init.d/mysql start
    
  14. Otorga acceso al usuario raíz para las conexiones remotas a fin de probar la implementación en el futuro:

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

    sudo update-rc.d -f mysql disable
    

Instala Pacemaker en database1

  1. Carga las variables de metadatos desde el archivo .varsrc que creaste antes:

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

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

    sudo apt -y install pcs
    
  4. Habilita pcsd, corosync y pacemaker cuando se inicie 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 comience antes de pacemaker:

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

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

    sudo corosync-keygen -l
    
  8. Copia authkey a la instancia database2. Cuando se te solicite una frase de contraseña, presiona 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"
    

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

    A continuación, se indican las opciones de configuración importantes:

    • 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 en el clúster y cómo se puede llegar 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. A fin de anular esto, especifica el valor “1” para two_node en la sección quorum.

    Esto te permite configurar el clúster y prepararlo para usarlo en el futuro, cuando agregues un tercer nodo que funcionará como un dispositivo de quórum.

  10. Crea el directorio de servicio para corosync:

    sudo mkdir -p /etc/corosync/service.d
    
  11. Configura corosync para que sea compatible con Pacemaker:

    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 de dispositivo de quórum de Corosync:

    sudo apt -y install corosync-qdevice
    
  15. Instala una secuencia de comandos de shell para controlar las fallas 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
    

Instala MySQL en database2

  1. Conéctate a la instancia database2 a través de SSH.
  2. Actualiza el repositorio de APT con el paquete de 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. Agrega las claves de 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 solicite una contraseña, ingresa 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. Quita los datos en /var/lib/mysql y agrega un vínculo simbólico al destino del punto de activación para el volumen replicado de DRBD. El volumen de DRBD (/dev/drbd0) se activará 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, del que se ocupa la administración de recursos del clúster:

    sudo update-rc.d -f mysql disable
    

Instala Pacemaker en database2

  1. Carga las variables de metadatos desde el archivo .varsrc:

    source ~/.varsrc
    
  2. Instala Pacemaker:

    sudo apt -y install pcs
    
  3. Mueve el archivo authkey de Corosync que copiaste antes en /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 cuando se inicie el sistema en la instancia en 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 comience antes de pacemaker:

    sudo update-rc.d corosync defaults 20 20
    sudo update-rc.d pacemaker defaults 30 10
    
  6. Establece la contraseña de usuario del clúster para la autenticación. La contraseña es la misma (haCLUSTER3) que usaste para la instancia 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 servicios de Corosync:

    sudo mkdir /etc/corosync/service.d
    
  9. Configura corosync para que sea compatible con Pacemaker:

    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 de dispositivo de quórum de Corosync:

    sudo apt -y install corosync-qdevice
    
  13. Instala una secuencia de comandos de shell para controlar las fallas 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. Verifica el estado del clúster de Corosync:

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

    La salida obtenida se verá así:

    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)
    

Inicia el clúster

  1. Conéctate a la instancia database2 a través de SSH.
  2. Carga las variables de metadatos desde el archivo .varsrc:

    source ~/.varsrc
    
  3. Autentica con 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 obtenida se verá así:

    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
    

Configura Pacemaker para administrar los recursos del clúster

Luego, configura Pacemaker con los recursos de DRBD, MySQL, quórum y del disco.

  1. Conéctate a la instancia database1 a través de SSH.
  2. Usa la utilidad pcs de Pacemaker para poner en cola varios cambios en un archivo y, luego, 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, ya que implementarás el dispositivo de quórum más adelante:

    sudo pcs -f clust_cfg property set stonith-enabled=false
    
  4. Inhabilita la configuración relacionada con el quórum. Configurarás el nodo del dispositivo de quórum más tarde.

    sudo pcs -f clust_cfg property set no-quorum-policy=stop
    
  5. Evita que Pacemaker retire los recursos después de una recuperación:

    sudo pcs -f clust_cfg resource defaults resource-stickiness=200
    
  6. Crea el recurso de 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 una función principal al recurso de 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 activar el disco de DRBD:

    sudo pcs -f clust_cfg resource create mystore_FS Filesystem \
        device="/dev/drbd0" \
        directory="/srv" \
        fstype="ext4"
    
  9. Configura el clúster para colocar el recurso de DRBD con el recurso del disco en la misma VM:

    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 el recurso del disco aparezca después de que el DRBD principal ascienda:

    sudo pcs -f clust_cfg constraint order promote primary_mysql then start mystore_FS
    
  11. Crea un servicio de 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 con el recurso del 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 de DRBD preceda al servicio de 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 agrega el parche al archivo de registro como su 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 en línea:

    sudo pcs status
    

    La salida obtenida se verá así:

    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
    

Configura un dispositivo de quórum

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

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

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

    sudo bash -c "echo  hacluster:haCLUSTER3 | chpasswd"
    
  5. Verifica el estado del dispositivo de quórum:

    sudo pcs qdevice status net --full
    

    La salida obtenida se verá así:

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

Establece la configuración del dispositivo de quórum en database1

  1. Conéctate al nodo database1 a través de SSH.
  2. Carga las variables de metadatos desde el archivo .varsrc:

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

    sudo pcs cluster auth --name mysql_cluster ${QUORUM_INSTANCE_NAME} -u hacluster -p haCLUSTER3
    
  4. Agrega el dispositivo de quórum al clúster. Usa el algoritmo ffsplit, que garantiza que el nodo activo se decidirá 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. Agrega la configuración 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 de corosync para volver a cargar la configuración nueva del dispositivo de quórum:

    sudo service corosync restart
    
  7. Inicia el daemon del dispositivo de quórum de corosync y ábrelo cuando comience el sistema:

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

Establece la configuración del dispositivo de quórum en database2

  1. Conéctate al nodo database2 a través de SSH.
  2. Carga las variables de metadatos desde el archivo .varsrc:

    source ~/.varsrc
    
  3. Agrega una configuración 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 de corosync para volver a cargar la configuración nueva 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 abra cuando comience el sistema:

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

Verifica el estado del clúster

El siguiente paso es verificar que los recursos del clúster estén en línea.

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

    sudo pcs status
    

    La salida obtenida se verá así:

    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. Muestra el estado del quórum:

    sudo pcs quorum status
    

    La salida obtenida se verá así:

    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 obtenida se verá así:

    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
    

Configura un balanceador de cargas interno como la IP del clúster

  1. Abre Cloud Shell:

    Abrir Cloud Shell

  2. Crea un grupo de instancias no administrado y agrégale 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 no administrado y agrégale 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 verificación de estado para port 3306:

    gcloud compute health-checks create tcp mysql-backend-healthcheck \
        --port 3306
    
  5. Crea un servicio de 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. Agrega 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 desvío para el balanceador de cargas:

    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 firewall para permitir una verificación de estado del balanceador de cargas 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 verificar el estado de tu balanceador de cargas, ve a la página Balanceo de cargas en la consola de Google Cloud.

    ABRIR LA PÁGINA BALANCEO DE CARGAS

  10. Haz clic en mysql-ilb:

    imagen

    Debido a que el clúster permite que una sola instancia ejecute MySQL en cualquier momento, solo una instancia se encuentra en buen estado desde la perspectiva del balanceador de cargas interno.

    imagen

Conéctate al clúster desde el cliente MySQL

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

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

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

    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
    

Prueba el clúster

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

  • Cierra la instancia database1 para probar 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 de manera correcta.
  • Cierra la instancia database2 para probar 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 de manera correcta y si la instancia database1 aún conserva la función 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. Verifica el estado del clúster:

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

    El resultado se verá de la siguiente manera. Verifica si se implementaron los cambios de configuración que hiciste:

    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. Verifica el estado del clúster:

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

    La salida obtenida se verá así:

    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. Verifica el estado del clúster:

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

    La salida obtenida se verá así:

    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. Verifica el estado del clúster:

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

    La salida obtenida se verá así:

    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. Después de unos minutos, verifica el estado del clúster. Observa que database1 mantiene su función principal, porque la política de quórum consiste en el nodo de ID más bajo primero en una situación de partición de red. Mientras tanto, el servicio de MySQL de database2 se detiene. Este mecanismo de quórum evita el problema de cerebro dividido cuando se produce la partición de red.

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

    La salida obtenida se verá así:

    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. Borra la regla de firewall de red para quitar la partición de red (presiona Y cuando se te solicite).

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

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

    La salida obtenida se verá así:

    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 a través de SSH.

  15. En tu shell, consulta la tabla que creaste con anterioridad:

    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"
    

    El resultado debe incluir 10 registros con el siguiente formato, que verifiquen 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 falla, la secuencia de conmutación por error se verá de la siguiente manera:

  1. El dispositivo de quórum y el nodo en espera pierden conectividad con el nodo principal.
  2. El dispositivo de quórum vota por el nodo en espera y el nodo en espera vota por sí mismo.
  3. El nodo en espera adquiere el quórum.
  4. El nodo en espera cambia a principal.
  5. El nodo principal nuevo realiza lo siguiente:
    1. Asciende DRBD a principal
    2. Activa el disco de datos de MySQL desde DRBD
    3. Inicia MySQL
    4. Adquiere buen estado para el balanceador de cargas
  6. El balanceador de cargas comienza a enviar tráfico al nodo principal nuevo.

Limpia

Borra el proyecto

  1. En la consola de Google Cloud, ve a la página Administrar recursos.

    Ir a Administrar recursos

  2. En la lista de proyectos, elige el proyecto que quieres borrar y haz clic en Borrar.
  3. En el diálogo, escribe el ID del proyecto y, luego, haz clic en Cerrar para borrar el proyecto.

¿Qué sigue?