sql >> データベース >  >> RDS >> Mysql

KubernetesでGaleraクラスターを実行する

    最後の数件のブログでは、スタンドアロンのDockerでも、オーバーレイネットワークを備えたマルチホストのDocker Swarmでも、DockerでGaleraクラスターを実行する方法について説明しました。このブログ投稿では、コンテナを大規模に実行するためのオーケストレーションツールであるKubernetesでのGaleraClusterの実行について説明します。アプリケーションがクラスタに接続する方法、Kubernetesがフェイルオーバーを処理する方法、Kubernetesでの負荷分散がどのように機能するかなど、いくつかの部分が異なります。

    Kubernetes vs Docker Swarm

    私たちの最終的な目標は、GaleraClusterがコンテナ環境で確実に実行されるようにすることです。以前にDockerSwarmについて説明しましたが、Galera Clusterを実行すると、本番環境に対応できない多くのブロッカーが存在することがわかりました。私たちの旅は、本番環境グレードのコンテナオーケストレーションツールであるKubernetesで継続されます。 GaleraClusterのようなステートフルサービスを実行するときにサポートできる「本番環境」のレベルを見てみましょう。

    先に進む前に、コンテナでGalera Clusterを実行する場合のKubernetes(1.6)とDocker Swarm(17.03)の主な違いのいくつかを強調しましょう。

    • Kubernetesは、ライブネスとレディネスの2つのヘルスチェックプローブをサポートしています。ライブのGaleraコンテナは、サービスを提供する準備ができていることを意味するわけではなく、負荷分散セットに含める必要があるため、これはコンテナでGalera Clusterを実行する場合に重要です(ジョイナー/ドナー状態を考えてみてください)。 Docker Swarmは、Kubernetesの活性と同様に1つのヘルスチェックプローブのみをサポートします。コンテナは正常で実行を継続するか、異常であり、スケジュールが変更されます。詳細については、こちらをお読みください。
    • Kubernetesには、「kubectlproxy」を介してアクセスできるUIダッシュボードがあります。
    • Docker Swarmはラウンドロビン負荷分散(入力)のみをサポートしますが、Kubernetesは最小限の接続を使用します。
    • Docker Swarmはルーティングメッシュをサポートしてサービスを外部ネットワークに公開しますが、KubernetesはNodePortと呼ばれるもの、外部ロードバランサー(GCE GLB / AWS ELB)および外部DNS名(v1.7の場合)をサポートします

    Kubeadmを使用したKubernetesのインストール

    kubeadmを使用して、CentOS 7に3ノードのKubernetesクラスターをインストールします。これは、1つのマスターと2つのノード(ミニオン)で構成されます。私たちの物理アーキテクチャは次のようになります:

    1.すべてのノードにkubeletとDockerをインストールします:

    $ ARCH=x86_64
    cat <<EOF > /etc/yum.repos.d/kubernetes.repo
    [kubernetes]
    name=Kubernetes
    baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-${ARCH}
    enabled=1
    gpgcheck=1
    repo_gpgcheck=1
    gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg
            https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
    EOF
    $ setenforce 0
    $ yum install -y docker kubelet kubeadm kubectl kubernetes-cni
    $ systemctl enable docker && systemctl start docker
    $ systemctl enable kubelet && systemctl start kubelet

    2.マスターで、マスターを初期化し、構成ファイルをコピーし、Weaveを使用してポッドネットワークをセットアップし、Kubernetesダッシュボードをインストールします。

    $ kubeadm init
    $ cp /etc/kubernetes/admin.conf $HOME/
    $ export KUBECONFIG=$HOME/admin.conf
    $ kubectl apply -f https://git.io/weave-kube-1.6
    $ kubectl create -f https://git.io/kube-dashboard

    3.次に、他の残りのノードで:

    $ kubeadm join --token 091d2a.e4862a6224454fd6 192.168.55.140:6443

    4.ノードの準備ができていることを確認します:

    $ kubectl get nodes
    NAME          STATUS    AGE       VERSION
    kube1.local   Ready     1h        v1.6.3
    kube2.local   Ready     1h        v1.6.3
    kube3.local   Ready     1h        v1.6.3

    これで、GaleraクラスターをデプロイするためのKubernetesクラスターができました。

    Kubernetes上のGaleraクラスター

    この例では、DockerHubリポジトリから取得したDockerイメージを使用してMariaDB GaleraCluster10.1をデプロイします。このデプロイで使用されるYAML定義ファイルは、Githubリポジトリのexample-kubernetesディレクトリにあります。

    Kubernetesは、多数のデプロイコントローラーをサポートしています。ガレラクラスターを展開するには、次を使用できます。

    • ReplicaSet
    • StatefulSet

    それぞれに長所と短所があります。それぞれを調べて、違いを確認します。

    前提条件

    作成したイメージには、サービス検出用のetcd(スタンドアロンまたはクラスター)が必要です。 etcdクラスターを実行するには、各etcdインスタンスが異なるコマンドで実行されている必要があるため、Deploymentの代わりにPodsコントローラーを使用し、etcdポッドのエンドポイントとして「etcd-client」というサービスを作成します。 etcd-cluster.yaml定義ファイルがすべてを教えてくれます。

    3ポッドetcdクラスターをデプロイするには、次のコマンドを実行するだけです。

    $ kubectl create -f etcd-cluster.yaml

    etcdクラスターの準備ができているかどうかを確認します:

    $ kubectl get po,svc
    NAME                        READY     STATUS    RESTARTS   AGE
    po/etcd0                    1/1       Running   0          1d
    po/etcd1                    1/1       Running   0          1d
    po/etcd2                    1/1       Running   0          1d
     
    NAME              CLUSTER-IP       EXTERNAL-IP   PORT(S)             AGE
    svc/etcd-client   10.104.244.200   <none>        2379/TCP            1d
    svc/etcd0         10.100.24.171    <none>        2379/TCP,2380/TCP   1d
    svc/etcd1         10.108.207.7     <none>        2379/TCP,2380/TCP   1d
    svc/etcd2         10.101.9.115     <none>        2379/TCP,2380/TCP   1d

    現在、アーキテクチャは次のようになっています。

    Docker上のSeveralninesMySQL:データベースをコンテナ化する方法MySQLサービスの実行を検討する際に理解する必要があるすべてを発見するDockerコンテナ仮想化のトップホワイトペーパーをダウンロード

    ReplicaSetの使用

    ReplicaSetは、指定された数のポッド「レプリカ」が常に実行されていることを確認します。ただし、Deploymentは、ReplicaSetを管理し、他の多くの便利な機能とともにポッドに宣言型の更新を提供する、より高いレベルの概念です。したがって、カスタム更新オーケストレーションが必要な場合や更新がまったく必要ない場合を除いて、ReplicaSetを直接使用するのではなく、デプロイメントを使用することをお勧めします。デプロイメントを使用する場合、それらが作成するレプリカセットの管理について心配する必要はありません。デプロイメントはReplicaSetを所有および管理します。

    この例では、このYAML定義に示されているように、Deploymentをワークロードコントローラーとして使用します。次のコマンドを実行して、GaleraClusterReplicaSetとServiceを直接作成できます。

    $ kubectl create -f mariadb-rs.yml

    ReplicaSet(rs)、pods(po)、services(svc)を調べて、クラスターの準備ができているかどうかを確認します。

    $ kubectl get rs,po,svc
    NAME                  DESIRED   CURRENT   READY     AGE
    rs/galera-251551564   3         3         3         5h
     
    NAME                        READY     STATUS    RESTARTS   AGE
    po/etcd0                    1/1       Running   0          1d
    po/etcd1                    1/1       Running   0          1d
    po/etcd2                    1/1       Running   0          1d
    po/galera-251551564-8c238   1/1       Running   0          5h
    po/galera-251551564-swjjl   1/1       Running   1          5h
    po/galera-251551564-z4sgx   1/1       Running   1          5h
     
    NAME              CLUSTER-IP       EXTERNAL-IP   PORT(S)             AGE
    svc/etcd-client   10.104.244.200   <none>        2379/TCP            1d
    svc/etcd0         10.100.24.171    <none>        2379/TCP,2380/TCP   1d
    svc/etcd1         10.108.207.7     <none>        2379/TCP,2380/TCP   1d
    svc/etcd2         10.101.9.115     <none>        2379/TCP,2380/TCP   1d
    svc/galera-rs     10.107.89.109    <nodes>       3306:30000/TCP      5h
    svc/kubernetes    10.96.0.1        <none>        443/TCP             1d

    上記の出力から、ポッドとサービスを次のように説明できます。

    ReplicaSetでGaleraClusterを実行することは、ステートレスアプリケーションとして扱うことに似ています。ポッドの作成、削除、更新を調整し、Horizo​​ntal Pod Autoscales(HPA)の対象にすることができます。つまり、ReplicaSetは、特定のしきい値またはターゲット(CPU使用率、1秒あたりのパケット数、1秒あたりの要求数)を満たす場合に自動スケーリングできます。など)。

    Kubernetesノードの1つがダウンした場合、目的のレプリカを満たすために、使用可能なノードで新しいポッドがスケジュールされます。ポッドが削除または再スケジュールされると、ポッドに関連付けられているボリュームが削除されます。ポッドのホスト名はランダムに生成されるため、ホスト名を確認するだけでコンテナがどこに属しているかを追跡するのが難しくなります。

    これはすべて、テスト環境とステージング環境で非常にうまく機能します。この環境では、依存関係なしに、展開、スケーリング、更新、破棄などの完全なコンテナライフサイクルを実行できます。 YAMLファイルを更新してKubernetesクラスターに投稿するか、scaleコマンドを使用することで、スケールアップとスケールダウンを簡単に行うことができます。

    $ kubectl scale replicaset galera-rs --replicas=5

    StatefulSetの使用

    1.6より前のバージョンではPetSetとして知られているStatefulSetは、GaleraClusterを本番環境にデプロイするための最良の方法です。理由は次のとおりです。

    • StatefulSetを削除またはスケールダウンしても、StatefulSetに関連付けられているボリュームは削除されません。これは、データの安全性を確保するために行われます。これは、関連するすべてのStatefulSetリソースの自動パージよりも一般的に価値があります。
    • N個のレプリカを持つStatefulSetの場合、ポッドが展開されると、それらは{0 .. N-1の順に順番に作成されます。 }。
    • ポッドが削除されると、{ N-1から逆の順序で終了します。 ..0}。
    • スケーリング操作をポッドに適用する前に、その前身のすべてが実行中で準備ができている必要があります。
    • ポッドを終了する前に、後続のすべてのポッドを完全にシャットダウンする必要があります。

    StatefulSetは、ステートフルコンテナのファーストクラスのサポートを提供します。展開とスケーリングの保証を提供します。 3ノードのGaleraClusterが作成されると、3つのポッドがdb-0、db-1、db-2の順序でデプロイされます。 db-0が「RunningandReady」になる前にdb-1はデプロイされず、db-1が「RunningandReady」になるまでdb-2はデプロイされません。 db-0が失敗した場合、db-1が「実行中および準備完了」になった後、db-2が起動される前に、db-0が正常に再起動されて「実行中および準備完了」になるまで、db-2は起動されません。

    PersistentVolumeおよびPersistentVolumeClaimと呼ばれる永続ストレージのKubernetes実装を使用します。これは、ポッドが他のノードに再スケジュールされた場合にデータの永続性を確保するためです。 Galera Clusterは各レプリカのデータの正確なコピーを提供しますが、すべてのポッドでデータを永続化することは、トラブルシューティングとリカバリの目的に適しています。

    永続ストレージを作成するには、最初にすべてのポッドに対してPersistentVolumeを作成する必要があります。 PVはDockerのボリュームのようなボリュームプラグインですが、PVを使用する個々のポッドから独立したライフサイクルを持っています。 3ノードのGaleraClusterを展開するため、3つのPVを作成する必要があります。

    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name: datadir-galera-0
      labels:
        app: galera-ss
        podindex: "0"
    spec:
      accessModes:
      - ReadWriteOnce
      capacity:
        storage: 10Gi
      hostPath:
        path: /data/pods/galera-0/datadir
    ---
    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name: datadir-galera-1
      labels:
        app: galera-ss
        podindex: "1"
    spec:
      accessModes:
      - ReadWriteOnce
      capacity:
        storage: 10Gi
      hostPath:
        path: /data/pods/galera-1/datadir
    ---
    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name: datadir-galera-2
      labels:
        app: galera-ss
        podindex: "2"
    spec:
      accessModes:
      - ReadWriteOnce
      capacity:
        storage: 10Gi
      hostPath:
        path: /data/pods/galera-2/datadir

    上記の定義は、10GBのストレージスペースを持つKubernetesノードの物理パスにマッピングされた3つのPVを作成することを示しています。 ReadWriteOnceを定義しました。これは、ボリュームを単一のノードのみが読み取り/書き込みとしてマウントできることを意味します。上記の行をmariadb-pv.ymlに保存し、Kubernetesに投稿します:

    $ kubectl create -f mariadb-pv.yml
    persistentvolume "datadir-galera-0" created
    persistentvolume "datadir-galera-1" created
    persistentvolume "datadir-galera-2" created

    次に、PersistentVolumeClaimリソースを定義します。

    kind: PersistentVolumeClaim
    apiVersion: v1
    metadata:
      name: mysql-datadir-galera-ss-0
    spec:
      accessModes:
        - ReadWriteOnce
      resources:
        requests:
          storage: 10Gi
      selector:
        matchLabels:
          app: galera-ss
          podindex: "0"
    ---
    kind: PersistentVolumeClaim
    apiVersion: v1
    metadata:
      name: mysql-datadir-galera-ss-1
    spec:
      accessModes:
        - ReadWriteOnce
      resources:
        requests:
          storage: 10Gi
      selector:
        matchLabels:
          app: galera-ss
          podindex: "1"
    ---
    kind: PersistentVolumeClaim
    apiVersion: v1
    metadata:
      name: mysql-datadir-galera-ss-2
    spec:
      accessModes:
        - ReadWriteOnce
      resources:
        requests:
          storage: 10Gi
      selector:
        matchLabels:
          app: galera-ss
          podindex: "2"

    上記の定義は、PVリソースを要求し、 spec.selector.matchLabelsを使用することを示しています。 PVを探すには( metadata.labels.app:galera-ss )それぞれのポッドインデックス( metadata.labels.podindex )Kubernetesによって割り当てられます。 metadata.name リソースは、 spec.templates.containersで定義されている「{volumeMounts.name}-{pod}-{ordinalindex}」の形式を使用する必要があります そのため、Kubernetesは、クレームをポッドにマッピングするマウントポイントを認識しています。

    上記の行をmariadb-pvc.ymlに保存し、Kubernetesに投稿します:

    $ kubectl create -f mariadb-pvc.yml
    persistentvolumeclaim "mysql-datadir-galera-ss-0" created
    persistentvolumeclaim "mysql-datadir-galera-ss-1" created
    persistentvolumeclaim "mysql-datadir-galera-ss-2" created

    これで永続ストレージの準備が整いました。次に、mariadb-ss.yml:

    に示すように、ヘッドレスサービスリソースと一緒にStatefulSetリソースを作成することで、GaleraClusterのデプロイを開始できます。
    $ kubectl create -f mariadb-ss.yml
    service "galera-ss" created
    statefulset "galera-ss" created

    次に、StatefulSetの展開の概要を取得します。

    $ kubectl get statefulsets,po,pv,pvc -o wide
    NAME                     DESIRED   CURRENT   AGE
    statefulsets/galera-ss   3         3         1d        galera    severalnines/mariadb:10.1   app=galera-ss
     
    NAME                        READY     STATUS    RESTARTS   AGE       IP          NODE
    po/etcd0                    1/1       Running   0          7d        10.36.0.1   kube3.local
    po/etcd1                    1/1       Running   0          7d        10.44.0.2   kube2.local
    po/etcd2                    1/1       Running   0          7d        10.36.0.2   kube3.local
    po/galera-ss-0              1/1       Running   0          1d        10.44.0.4   kube2.local
    po/galera-ss-1              1/1       Running   1          1d        10.36.0.5   kube3.local
    po/galera-ss-2              1/1       Running   0          1d        10.44.0.5   kube2.local
     
    NAME                  CAPACITY   ACCESSMODES   RECLAIMPOLICY   STATUS    CLAIM                               STORAGECLASS   REASON    AGE
    pv/datadir-galera-0   10Gi       RWO           Retain          Bound     default/mysql-datadir-galera-ss-0                            4d
    pv/datadir-galera-1   10Gi       RWO           Retain          Bound     default/mysql-datadir-galera-ss-1                            4d
    pv/datadir-galera-2   10Gi       RWO           Retain          Bound     default/mysql-datadir-galera-ss-2                            4d
     
    NAME                            STATUS    VOLUME             CAPACITY   ACCESSMODES   STORAGECLASS   AGE
    pvc/mysql-datadir-galera-ss-0   Bound     datadir-galera-0   10Gi       RWO                          4d
    pvc/mysql-datadir-galera-ss-1   Bound     datadir-galera-1   10Gi       RWO                          4d
    pvc/mysql-datadir-galera-ss-2   Bound     datadir-galera-2   10Gi       RWO                          4d

    この時点で、StatefulSetで実行されているGaleraClusterを次の図のように示すことができます。

    StatefulSetで実行すると、ホスト名、IPアドレス、ネットワークID、クラスタードメイン、ポッドDNS、ストレージなどの一貫した識別子が保証されます。これにより、ポッドはポッドのグループ内の他のポッドと簡単に区別できます。ボリュームはホスト上に保持され、ポッドが削除されたり、別のノードに再スケジュールされたりしても削除されません。これにより、データの回復が可能になり、データ全体が失われるリスクが軽減されます。

    マイナス面として、展開時間は N-1になります。 リソースのデプロイ、再スケジュール、または削除時にKubernetesが通常のシーケンスに従うため、時間(N =レプリカ)が長くなります。クラスタのスケーリングを検討する前に、PVとクレームを準備するのは少し面倒です。現在、既存のStatefulSetの更新は手動プロセスであり、 spec.replicasのみを更新できることに注意してください。 現時点では。

    ガレラクラスターサービスとポッドへの接続

    データベースクラスターに接続するには、いくつかの方法があります。ポートに直接接続できます。 「galera-rs」サービスの例では、NodePortを使用して、静的ポート(NodePort)で各ノードのIPにサービスを公開します。 NodePortサービスがルーティングされるClusterIPサービスが自動的に作成されます。 {NodeIP}:{NodePort} をリクエストすると、クラスターの外部からNodePortサービスに接続できます。 。

    ガレラクラスターに外部から接続する例:

    (external)$ mysql -udb_user -ppassword -h192.168.55.141 -P30000
    (external)$ mysql -udb_user -ppassword -h192.168.55.142 -P30000
    (external)$ mysql -udb_user -ppassword -h192.168.55.143 -P30000

    Kubernetesネットワークスペース内で、ポッドはクラスターIPまたはサービス名を介して内部的に接続できます。これは、次のコマンドを使用して取得できます。

    $ kubectl get services -o wide
    NAME          CLUSTER-IP       EXTERNAL-IP   PORT(S)             AGE       SELECTOR
    etcd-client   10.104.244.200   <none>        2379/TCP            1d        app=etcd
    etcd0         10.100.24.171    <none>        2379/TCP,2380/TCP   1d        etcd_node=etcd0
    etcd1         10.108.207.7     <none>        2379/TCP,2380/TCP   1d        etcd_node=etcd1
    etcd2         10.101.9.115     <none>        2379/TCP,2380/TCP   1d        etcd_node=etcd2
    galera-rs     10.107.89.109    <nodes>       3306:30000/TCP      4h        app=galera-rs
    galera-ss     None             <none>        3306/TCP            3m        app=galera-ss
    kubernetes    10.96.0.1        <none>        443/TCP             1d        <none>

    サービスリストから、Galera ClusterReplicaSetCluster-IPが10.107.89.109であることがわかります。内部的には、別のポッドが、公開されたポート3306を使用して、このIPアドレスまたはサービス名を介してデータベースにアクセスできます。

    (etcd0 pod)$ mysql -udb_user -ppassword -hgalera-rs -P3306 -e 'select @@hostname'
    +------------------------+
    | @@hostname             |
    +------------------------+
    | galera-251551564-z4sgx |
    +------------------------+

    ポート30000の任意のポッド内から外部NodePortに接続することもできます:

    (etcd0 pod)$ mysql -udb_user -ppassword -h192.168.55.143 -P30000 -e 'select @@hostname'
    +------------------------+
    | @@hostname             |
    +------------------------+
    | galera-251551564-z4sgx |
    +------------------------+

    バックエンドポッドへの接続は、最小の接続アルゴリズムに基づいてそれに応じて負荷分散されます。

    概要

    この時点で、本番環境のKubernetesでGalera Clusterを実行することは、DockerSwarmと比較してはるかに有望であるように思われます。前回のブログ投稿で説明したように、提起された懸念は、KubernetesがStatefulSetでコンテナを調整する方法とは異なる方法で対処されます(ただし、v1.6ではまだベータ機能です)。提案されたアプローチが、本番環境で大規模なコンテナでGaleraClusterを実行するのに役立つことを願っています。


    1. MySQLでゼロ除算を回避する方法

    2. 割り当て順序スキャン

    3. oraclesqlplusでテーブルデータをより明確に表示する方法

    4. PL / SQLコレクション:Oracleデータベースのネストされたテーブル