ノート:

Pacemakerによって管理されるOracle Cloud InfrastructureでのLinux仮想IPフェイルオーバーの設定

イントロダクション

多くの環境では、浮動IPの使用を必要とするアクティブまたはパッシブなLinuxクラスタを持つインフラストラクチャを使用することがまだ不可欠です。クラウド・インフラストラクチャでは、セカンダリIPアドレスはオペレーティング・システムだけでなく、クラウド・インフラストラクチャでも管理する必要があります。

このチュートリアルでは、Linuxクラスタの浮動IPをPacemakerによって、簡単な方法で、カスタムコードなしで統合リソースとして管理する方法を説明します。詳細は、タスク3: Sambaクラスタの設定およびOracle Cloud Infrastructureでの自動仮想IPフェイルオーバーを参照してください。

建築設計

イメージ

目的

前提条件

タスク1: 環境の設定

  1. 2つのコンピュート・インスタンスを起動し、各インスタンスのオペレーティング・システムとして「Ubuntu 22」を選択します。

  2. セカンダリ・プライベートIPアドレスを仮想ネットワーク・インタフェース・カード(VNIC)にnode1に割り当てます。詳細は、VNICへの新規セカンダリ・プライベートIPの割当てを参照してください。これが浮遊IPになります。例: 10.10.1.115

  3. 動的グループの作成

    1. OCIコンソールにログインし、「アイデンティティとセキュリティ」「動的グループ」に移動して、「動的グループの作成」をクリックします。

    2. 次の情報を入力します

      • 名前: OCIVIPと入力します。
      • 次のルールを追加して、指定したコンパートメントにインスタンスを含めます。

        All {instance.compartment.id = 'Your compartment OCI ID'}
        
  4. ポリシーを動的グループに追加します。

    1. 「アイデンティティとセキュリティ」「ポリシー」にナビゲートし、「ポリシーの作成」をクリックします。

    2. 次の情報を入力します

      • 名前: OCIVIP_policyと入力します。

      • 動的グループが仮想ネットワーク・ファミリを使用できるようにするには、次の文を追加します。

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

タスク2: クラスタおよび浮動IPの構成

環境の設定後、Pacemakerの構成およびOCIVIPリソース・エージェントの統合を続行できます。SSHを使用してインスタンスに接続し、ステップ10までの両方のノードでクラスタ・インストール操作を実行します。

  1. オペレーティング・システムを更新してください。

    sudo apt update
    sudo apt upgrade
    
  2. OCI CLIをインストールし、その機能を確認します。

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

    OCI CLIの設定

    oci setup config
    

    OCI CLIインストールを確認します。

    oci os ns get
    
  3. テスト環境では、iptablesのINPUTセクションの6行目でrejectルールを削除してから、インスタンス通信を許可するように永続化できます。本番環境では、iptablesをセキュアかつ適切に構成することを忘れないでください。

    sudo iptables -D INPUT 6
    sudo su
    sudo iptables-save > /etc/iptables/rules.v4
    sudo ip6tables-save > /etc/iptables/rules.v6
    
  4. /etc/hostsファイルを、2つのインスタンス(node1およびnode2)に割り当てられたプライベートIPアドレスで更新します。

    次のコマンドを実行してファイルを編集します。

    sudo nano /etc/hosts
    

    ノード名とIPアドレスを追加します。

    10.10.1.111 node1
    10.10.1.118 node2
    
  5. jqを含むクラスタに関連するパッケージをインストールします。

    sudo apt install -y pacemaker corosync pcs jq
    
  6. corosync.confファイルのバックアップを作成します。

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

    corosync.confファイルを編集します。

    sudo nano /etc/corosync/corosync.conf
    

    次のコンテンツを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. PacemakerがOCIフローティングIPをネイティブに管理するために使用するリソースを/usr/lib/ocf/resource.d/heartbeat/ディレクトリに追加します。ocivip.txtからファイルの内容をダウンロードします。

    ノート: このリソースは、Oracleによって開発されるのではなく、サードパーティの開発者が開発します。

    これは、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. ocivipファイルを編集し、OCI CLIパスを使用して、OCF_RESKEY_ocicli_default変数のOCI CLI実行可能ファイルのパスを変更します。

    UbuntuでのOCI CLIのインストール中にデフォルト・パスを保持した場合、変数は/home/ubuntu/bin/ociになります。

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

    ファイルを作成し、更新された変数を使用してステップ7からダウンロードしたコードをコピーします。

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

    アクセス権とファイルの所有者を変更します。

    sudo chown root /usr/lib/ocf/resource.d/heartbeat/ocivip
    sudo chmod 755 /usr/lib/ocf/resource.d/heartbeat/ocivip
    
  9. ブート時に有効にしてサービスを再起動し、正しく機能していることを確認します。

    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. ユーザーociclusterのパスワードを設定します。

    sudo passwd ocicluster
    
  11. 次のコマンドを実行して、ノードを認証します。

    sudo pcs cluster auth node1 node2 -u ocicluster -p YOUR_PASSWORD
    
  12. クラスタを作成します。

    sudo pcs cluster setup ha_cluster node1 node2
    
  13. すべてのノードでのブート時にクラスタを起動して有効にします。

    sudo pcs cluster start --all
    sudo pcs cluster enable --all
    
  14. クラスタがアクティブで機能していることを確認します。

    sudo pcs status
    
  15. 浮動IPを管理するためのOCIVIPリソースを追加します。

    ノート:このチュートリアルのステップ2で、仮想IPアドレスをVNICにセカンダリとして割り当てられたものに変更します。

    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. リソースが正常に追加され、正常に機能していることを確認します。

    sudo pcs status
    
  17. node1を再起動するなどして、セカンダリIPアドレスがインスタンス間で移行できることを確認し、OCIコンソールが他のインスタンスに割り当てられていることを確認します(その逆も同様です)。

    node1を再起動する前に、3番目の仮想マシンからフローティング・アドレスをpingして、node1が停止した後も応答し続けることを確認することもできます。いくつかのホップの短い中断は正常です。

アクティブでパッシブなクラスタが稼働しています。ビジネス継続性を必要とするサービスを追加できるようになりました。

確認

その他の学習リソース

docs.oracle.com/learnの他のラボを確認するか、Oracle Learning YouTubeチャネルで無料のラーニング・コンテンツにアクセスしてください。また、education.oracle.com/learning-explorerにアクセスしてOracle Learning Explorerになります。

製品ドキュメントは、Oracle Help Centerを参照してください。