Note:

Configuración de un failover de IP virtual de Linux en Oracle Cloud Infrastructure gestionado por Pacemaker

Introducción

En muchos entornos, sigue siendo esencial utilizar infraestructuras con un cluster de Linux activo o pasivo, que requieren el uso de IP flotantes. En la infraestructura en la nube, la dirección IP secundaria debe ser gestionada no solo por el sistema operativo, sino también por la infraestructura en la nube.

En este tutorial, veremos cómo la IP flotante de un cluster de Linux puede ser gestionada como un recurso integrado por Pacemaker, de una manera sencilla y sin código personalizado. Para obtener más información, consulte Tarea 3: configuración del cluster de Samba y Failover automático de IP virtual en Oracle Cloud Infrastructure.

Diseño de la arquitectura

image

Objetivos

Requisitos

Tarea 1: Configuración del entorno

  1. Inicie dos instancias informáticas. Seleccione Ubuntu 22 como sistema operativo para cada instancia.

  2. Asigne una dirección IP privada secundaria a la tarjeta de interfaz de red virtual (VNIC) en node1. Para obtener más información, consulte Assigning a New Secondary Private IP to a VNIC. Esta será la IP flotante. Por ejemplo, 10.10.1.115.

  3. Crear un grupo dinámico.

    1. Conéctese a la consola de OCI, vaya a Identidad y seguridad, Grupos dinámicos y haga clic en Crear grupo dinámico.

    2. Introduzca la siguiente información.

      • Nombre: introduzca OCIVIP.
      • Agregue la siguiente regla para incluir instancias en el compartimento especificado.

        All {instance.compartment.id = 'Your compartment OCI ID'}
        
  4. Agregue una política al grupo dinámico.

    1. Vaya a Identidad y seguridad, Políticas y haga clic en Crear política.

    2. Introduzca la siguiente información.

      • Nombre: introduzca OCIVIP_policy.

      • Agregue la siguiente sentencia para permitir que el grupo dinámico utilice la familia de redes virtuales:

        allow dynamic-group OracleIdentityCloudService/OCIVIP to use virtual-network-family in compartment id 'Your compartment OCI ID'
        

Tarea 2: Configuración del cluster y la IP flotante

Después de configurar el entorno, podemos continuar con la configuración del marcapasos y la integración del agente de recursos OCIVIP. Conéctese a las instancias mediante SSH y realice las operaciones de instalación del cluster en ambos nodos hasta el paso 10 incluido.

  1. Actualice el sistema operativo.

    sudo apt update
    sudo apt upgrade
    
  2. Instale la CLI de OCI y verifique su funcionalidad.

    bash -c "$(curl -L https://raw.githubusercontent.com/oracle/oci-cli/master/scripts/install/install.sh)"
    

    Configuración de la CLI de OCI.

    oci setup config
    

    Verifique la instalación de la CLI de OCI.

    oci os ns get
    
  3. Para un entorno de prueba, puede eliminar la regla reject en la línea 6 de la sección INPUT de iptables y, a continuación, convertirla en persistente para permitir la comunicación de instancias. Recuerde configurar iptables de forma segura y adecuada en entornos de producción.

    sudo iptables -D INPUT 6
    sudo su
    sudo iptables-save > /etc/iptables/rules.v4
    sudo ip6tables-save > /etc/iptables/rules.v6
    
  4. Actualice el archivo /etc/hosts con las direcciones IP privadas asignadas a sus dos instancias: node1 y node2.

    Ejecute el siguiente comando para editar el archivo.

    sudo nano /etc/hosts
    

    Agregue sus nombres de nodo y direcciones IP.

    10.10.1.111 node1
    10.10.1.118 node2
    
  5. Instale los paquetes relacionados con el cluster, incluido jq.

    sudo apt install -y pacemaker corosync pcs jq
    
  6. Realice la copia de seguridad del archivo corosync.conf.

    sudo cp /etc/corosync/corosync.conf /etc/corosync/corosync.conf.bk
    

    Edite el archivo corosync.conf.

    sudo nano /etc/corosync/corosync.conf
    

    Copie el siguiente contenido en el archivo corosync.conf.

     # Please read the corosync.conf.5 manual page
     system {
             # This is required to use transport=knet in an unprivileged
             # environment, such as a container. See man page for details.
             allow_knet_handle_fallback: yes
     }
    
     totem {
             version: 2
    
             # Corosync itself works without a cluster name, but DLM needs one.
             # The cluster name is also written into the VG metadata of newly
             # created shared LVM volume groups, if lvmlockd uses DLM locking.
            cluster_name: ha_cluster
             transport: udpu
             secauth: off
             # crypto_cipher and crypto_hash: Used for mutual node authentication.
             # If you choose to enable this, then do remember to create a shared
             # secret with "corosync-keygen".
             # enabling crypto_cipher, requires also enabling of crypto_hash.
             # crypto works only with knet transport
             crypto_cipher: none
             crypto_hash: none
     }
    
     logging {
             # Log the source file and line where messages are being
             # generated. When in doubt, leave off. Potentially useful for
             # debugging.
             fileline: off
             # Log to standard error. When in doubt, set to yes. Useful when
             # running in the foreground (when invoking "corosync -f")
             to_stderr: yes
             # Log to a log file. When set to "no", the "logfile" option
             # must not be set.
             to_logfile: yes
             logfile: /var/log/corosync/corosync.log
             # Log to the system log daemon. When in doubt, set to yes.
             to_syslog: yes
             # Log debug messages (very verbose). When in doubt, leave off.
             debug: off
             # Log messages with time stamps. When in doubt, set to hires (or on)
             #timestamp: hires
             logger_subsys {
                     subsys: QUORUM
                     debug: off
             }
     }
    
     quorum {
             # Enable and configure quorum subsystem (default: off)
             # see also corosync.conf.5 and votequorum.5
             provider: corosync_votequorum
             two_node: 1
             wait_for_all: 1
             last_man_standing: 1
             auto_tie_breaker: 0
     }
    
     nodelist {
             # Change/uncomment/add node sections to match cluster configuration
    
             node {
                     # Hostname of the node.
                     # name: node1
                     # Cluster membership node identifier
                     nodeid: 101
                     # Address of first link
                     ring0_addr: node1
                     # When knet transport is used it's possible to define up to 8 links
                     #ring1_addr: 192.168.1.1
             }
             # ...
             node {
                     ring0_addr: node2
                     nodeid: 102
                 }
    }
    
  7. Agregue el recurso que Pacemaker utilizará para gestionar la IP flotante de OCI de forma nativa en el directorio /usr/lib/ocf/resource.d/heartbeat/. Descargue el contenido del archivo desde aquí: ocivip.txt.

    Nota: Este recurso no lo ha desarrollado Oracle, sino desarrolladores de terceros.

    Este es el contenido del archivo ocivip.

    #!/bin/sh
    #
    #
    # Manage Secondary Private IP in Oracle Cloud Infrastructure with Pacemaker
    #
    #
    # Copyright 2016-2018 Lorenzo Garuti <garuti.lorenzo@gmail.com>
    #
    # Licensed under the Apache License, Version 2.0 (the "License");
    # you may not use this file except in compliance with the License.
    # You may obtain a copy of the License at
    #
    #     http://www.apache.org/licenses/LICENSE-2.0
    #
    # Unless required by applicable law or agreed to in writing, software
    # distributed under the License is distributed on an "AS IS" BASIS,
    # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    # See the License for the specific language governing permissions and
    # limitations under the License.
    #
    #
    
    #
    #  Prerequisites:
    #
    #  - OCI CLI installed (https://docs.oracle.com/en-us/iaas/Content/API/SDKDocs/climanualinst.htm)
    #  - jq installed
    #  - dynamic group with a policy attached
    #  - the policy must have this statement:
    #    allow dynamic-group <GROUP_NAME> to use virtual-network-family in compartment id <COMPARTMENT_ID>
    #  - a reserved secondary private IP address for Compute Instances high availability
    #
    
    #######################################################################
    # Initialization:
    
    : ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
    . ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
    
    #######################################################################
    
    #
    # Defaults
    #
    OCF_RESKEY_ocicli_default="/usr/local/bin/oci"
    OCF_RESKEY_api_delay_default="3"
    OCF_RESKEY_cidr_netmask_default="24"
    OCF_RESKEY_interface_alias_default="0"
    export OCI_CLI_AUTH=instance_principal
    
    : ${OCF_RESKEY_ocicli=${OCF_RESKEY_ocicli_default}}
    : ${OCF_RESKEY_api_delay=${OCF_RESKEY_api_delay_default}}
    : ${OCF_RESKEY_cidr_netmask=${OCF_RESKEY_cidr_netmask_default}}
    : ${OCF_RESKEY_interface_alias=${OCF_RESKEY_interface_alias_default}}
    
    meta_data() {
        cat <<END
    <?xml version="1.0"?>
    <!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
    <resource-agent name="ocivip">
    <version>1.0</version>
    
    <longdesc lang="en">
    Resource Agent for OCI Compute instance Secondary Private IP Addresses.
    
    It manages OCI Secondary Private IP Addresses for Compute instances with oci cli.
    
    See https://docs.oracle.com/en-us/iaas/Content/API/Concepts/cliconcepts.htm for more information about oci cli.
    
    Prerequisites:
    
    - OCI CLI installed (https://docs.oracle.com/en-us/iaas/Content/API/SDKDocs/climanualinst.htm)
    - jq installed
    - dynamic group with a policy attached
    - the policy must have this statement: allow dynamic-group GROUP_NAME to use virtual-network-family in compartment id COMPARTMENT_ID
    - a reserved secondary private IP address for Compute Instances high availability
    
    </longdesc>
    <shortdesc lang="en">OCI Secondary Private IP Address for Compute instances Resource Agent</shortdesc>
    
    <parameters>
    
    <parameter name="ocicli" unique="0">
    <longdesc lang="en">
    OCI Command line interface (CLI) tools
    </longdesc>
    <shortdesc lang="en">OCI cli tools</shortdesc>
    <content type="string" default="${OCF_RESKEY_ocicli_default}" />
    </parameter>
    
    <parameter name="secondary_private_ip" unique="1" required="1">
    <longdesc lang="en">
    reserved secondary private ip for compute instance
    </longdesc>
    <shortdesc lang="en">reserved secondary private ip for compute instance</shortdesc>
    <content type="string" default="" />
    </parameter>
    
    <parameter name="cidr_netmask" unique="0">
    <longdesc lang="en">
    netmask for the secondary_private_ip
    </longdesc>
    <shortdesc lang="en">netmask for the secondary_private_ip</shortdesc>
    <content type="integer" default="${OCF_RESKEY_cidr_netmask_default}" />
    </parameter>
    
    <parameter name="interface_alias" unique="0">
    <longdesc lang="en">
    numeric alias for the interface
    </longdesc>
    <shortdesc lang="en">numeric alias for the interface</shortdesc>
    <content type="integer" default="${OCF_RESKEY_interface_alias_default}" />
    </parameter>
    
    <parameter name="api_delay" unique="0">
    <longdesc lang="en">
    a short delay between API calls, to avoid sending API too quick
    </longdesc>
    <shortdesc lang="en">a short delay between API calls</shortdesc>
    <content type="integer" default="${OCF_RESKEY_api_delay_default}" />
    </parameter>
    
    </parameters>
    
    <actions>
    <action name="start"        timeout="30s" />
    <action name="stop"         timeout="30s" />
    <action name="monitor"      timeout="30s" interval="20s" depth="0" />
    <action name="migrate_to"   timeout="30s" />
    <action name="migrate_from" timeout="30s" />
    <action name="meta-data"    timeout="5s" />
    <action name="validate"     timeout="10s" />
    <action name="validate-all" timeout="10s" />
    </actions>
    </resource-agent>
    END
    }
    
    #######################################################################
    
    ocivip_usage() {
        cat <<END
    usage: $0 {start|stop|monitor|migrate_to|migrate_from|validate|validate-all|meta-data}
    
    Expects to have a fully populated OCF RA-compliant environment set.
    END
    }
    
    ocivip_start() {
        ocivip_monitor && return $OCF_SUCCESS
    
        $OCICLI network vnic assign-private-ip --vnic-id $VNIC_ID \
            --unassign-if-already-assigned \
            --ip-address ${SECONDARY_PRIVATE_IP}
        RETOCI=$?
        ip addr add ${SECONDARY_PRIVATE_IP}/${CIDR_NETMASK} dev ${PRIMARY_IFACE} label ${PRIMARY_IFACE}:${INTERFACE_ALIAS}
        RETIP=$?
    
        # delay to avoid sending request too fast
        sleep ${OCF_RESKEY_api_delay}
    
        if [ $RETOCI -ne 0 ] || [ $RETIP -ne 0 ]; then
            return $OCF_NOT_RUNNING
        fi
    
        ocf_log info "secondary_private_ip has been successfully brought up (${SECONDARY_PRIVATE_IP})"
        return $OCF_SUCCESS
    }
    
    ocivip_stop() {
        ocivip_monitor || return $OCF_SUCCESS
    
        $OCICLI network vnic unassign-private-ip --vnic-id $VNIC_ID \
            --ip-address ${SECONDARY_PRIVATE_IP}
        RETOCI=$?
        ip addr del ${SECONDARY_PRIVATE_IP}/${CIDR_NETMASK} dev ${PRIMARY_IFACE}:${INTERFACE_ALIAS}
        RETIP=$?
    
        # delay to avoid sending request too fast
        sleep ${OCF_RESKEY_api_delay}
    
        if [ $RETOCI -ne 0 ] || [ $RETIP -ne 0 ]; then
            return $OCF_NOT_RUNNING
        fi
    
        ocf_log info "secondary_private_ip has been successfully brought down (${SECONDARY_PRIVATE_IP})"
        return $OCF_SUCCESS
    }
    
    ocivip_monitor() {
        $OCICLI network private-ip list --vnic-id $VNIC_ID | grep -q "${SECONDARY_PRIVATE_IP}"
        RETOCI=$?
    
        if [ $RETOCI -ne 0 ]; then
            return $OCF_NOT_RUNNING
        fi
        return $OCF_SUCCESS
    }
    
    ocivip_validate() {
        check_binary ${OCICLI}
        check_binary jq
    
        if [ -z "${VNIC_ID}" ]; then
            ocf_exit_reason "vnic_id not found. Is this a Compute instance?"
            return $OCF_ERR_GENERIC
        fi
    
        return $OCF_SUCCESS
    }
    
    case $__OCF_ACTION in
        meta-data)
            meta_data
            exit $OCF_SUCCESS
            ;;
    esac
    
    OCICLI="${OCF_RESKEY_ocicli}"
    SECONDARY_PRIVATE_IP="${OCF_RESKEY_secondary_private_ip}"
    CIDR_NETMASK="${OCF_RESKEY_cidr_netmask}"
    INTERFACE_ALIAS="${OCF_RESKEY_interface_alias}"
    VNIC_ID="$(curl -s -H "Authorization: Bearer Oracle" -L http://169.254.169.254/opc/v2/vnics/ | jq -r '.[0].vnicId')"
    PRIMARY_IFACE=$(ip -4 route ls | grep default | grep -Po '(?<=dev )(\S+)' | head -n1)
    
    case $__OCF_ACTION in
        start)
            ocivip_validate || exit $?
            ocivip_start
            ;;
        stop)
            ocivip_stop
            ;;
        monitor)
            ocivip_monitor
            ;;
        migrate_to)
            ocf_log info "Migrating ${OCF_RESOURCE_INSTANCE} to ${OCF_RESKEY_CRM_meta_migrate_target}."
            ocivip_stop
            ;;
        migrate_from)
            ocf_log info "Migrating ${OCF_RESOURCE_INSTANCE} from ${OCF_RESKEY_CRM_meta_migrate_source}."
            ocivip_start
            ;;
        reload)
            ocf_log info "Reloading ${OCF_RESOURCE_INSTANCE} ..."
            ;;
        validate|validate-all)
            ocivip_validate
            ;;
        usage|help)
            ocivip_usage
            exit $OCF_SUCCESS
            ;;
        *)
            ocivip_usage
            exit $OCF_ERR_UNIMPLEMENTED
            ;;
    esac
    
    rc=$?
    ocf_log debug "${OCF_RESOURCE_INSTANCE} $__OCF_ACTION : $rc"
    exit $rc
    
  8. Edite el archivo ocivip y cambie la ruta del ejecutable de la CLI de OCI en la variable OCF_RESKEY_ocicli_default con la ruta de la CLI de OCI.

    Si ha mantenido la ruta por defecto durante la instalación de la CLI de OCI en Ubuntu, la variable será /home/ubuntu/bin/oci.

    OCF_RESKEY_ocicli_default="/home/ubuntu/bin/oci"
    

    Cree el archivo y copie el código descargado del paso 7 con la variable actualizada.

    sudo nano /usr/lib/ocf/resource.d/heartbeat/ocivip
    

    Cambie el permiso y el propietario del archivo.

    sudo chown root /usr/lib/ocf/resource.d/heartbeat/ocivip
    sudo chmod 755 /usr/lib/ocf/resource.d/heartbeat/ocivip
    
  9. Active en el inicio y reinicie los servicios, además de comprobar que funcionan correctamente.

    sudo systemctl enable corosync
    sudo systemctl enable pacemaker
    sudo systemctl enable pcsd
    sudo systemctl restart pcsd
    sudo systemctl restart corosync
    sudo systemctl restart pacemaker
    sudo systemctl status pcsd
    sudo systemctl status corosync
    sudo systemctl status pacemaker
    
  10. Configure la contraseña para el usuario ocicluster.

    sudo passwd ocicluster
    
  11. Ejecute el siguiente comando para autenticar los nodos.

    sudo pcs cluster auth node1 node2 -u ocicluster -p YOUR_PASSWORD
    
  12. Cree el cluster.

    sudo pcs cluster setup ha_cluster node1 node2
    
  13. Inicie y active el cluster al iniciar en todos los nodos.

    sudo pcs cluster start --all
    sudo pcs cluster enable --all
    
  14. Compruebe que el cluster esté activo y en funcionamiento.

    sudo pcs status
    
  15. Agregue el recurso OCIVIP para gestionar la IP flotante.

    Nota: Cambie la dirección IP virtual por la asignada como secundaria a la VNIC en el paso 2 de este tutorial.

    sudo pcs resource create OCIVIP ocf:heartbeat:ocivip secondary_private_ip="10.10.1.115" cidr_netmask="24" op monitor timeout="30s" interval="20s" OCF_CHECK_LEVEL="0"
    
  16. Compruebe que el recurso se haya agregado correctamente y que funcione correctamente.

    sudo pcs status
    
  17. Verifique que la dirección IP secundaria puede migrar entre instancias, por ejemplo, reiniciando node1, y compruebe en la consola de OCI que está asignada a la otra instancia y viceversa.

    Antes de reiniciar node1, también puede hacer ping en la dirección flotante desde una tercera máquina virtual y comprobar que sigue respondiendo después de cerrar node1. Una breve interrupción de algunos saltos es normal.

El cluster activo y pasivo está activo y en ejecución. Ahora puede agregar los servicios que requieren continuidad del negocio.

Confirmaciones

Más recursos de aprendizaje

Explore otros laboratorios en docs.oracle.com/learn o acceda a más contenido de formación gratuita en el canal YouTube de Oracle Learning. Además, visita education.oracle.com/learning-explorer para convertirte en un Oracle Learning Explorer.

Para obtener documentación sobre el producto, visite Oracle Help Center.