最後の数件のブログでは、スタンドアロンの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を実行することは、ステートレスアプリケーションとして扱うことに似ています。ポッドの作成、削除、更新を調整し、Horizontal 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を実行するのに役立つことを願っています。