このドキュメントは、高可用性 MySQL トポロジを Google Kubernetes Engine にデプロイすることに関心があるデータベース管理者、クラウド アーキテクト、運用の担当者を対象としています。
このチュートリアルに沿って、GKE クラスタに MySQL Router ミドルウェアのみならず、MySQL InnoDB クラスタと MySQL InnoDB ClusterSet をデプロイする方法、およびアップグレードの実施方法を学びます。
目標
このチュートリアルの学習内容は次のとおりです。- ステートフルな Kubernetes Service を作成してデプロイする。
- 高可用性対応の MySQL InnoDB クラスタをデプロイする。
- データベース オペレーション ルーティング用のルーター ミドルウェアをデプロイする。
- 耐障害性のために MySQL InnoDB ClusterSet をデプロイする。
- MySQL クラスタのフェイルオーバーをシミュレーションする。
- MySQL のバージョン アップグレードを実行する。
以降のセクションでは、このチュートリアルで構築するソリューションのアーキテクチャについて説明します。
MySQL InnoDB クラスタ
リージョン GKE クラスタで、StatefulSet を使用して、必要な命名と構成の MySQL データベース インスタンスをデプロイし、MySQL InnoDB クラスタを作成します。フォールト トレラントと高可用性を実現するために、3 つのデータベース インスタンス Pod をデプロイします。これにより、コンセンサス プロトコルを使用してプライマリ選出が正常に行われたときに、異なるゾーンの Pod の大半が常に使用可能になり、MySQL InnoDB クラスタが単一ゾーンでの障害に耐えられるようになります。
デプロイしたら、1 つの Pod をプライマリ インスタンスに指定し、読み取りオペレーションと書き込みオペレーションの両方を処理します。他の 2 つの Pod はセカンダリ読み取り専用レプリカです。プライマリ インスタンスでインフラストラクチャに障害が発生した場合、この 2 つのレプリカ Pod のいずれかをプライマリに昇格できます。
別の Namespace に 3 つの MySQL Router Pod をデプロイして、復元力を高めるために接続ルーティングを提供します。アプリケーションはデータベース サービスに直接接続するのではなく、MySQL ルーター Pod に接続します。各 Router Pod は、各 MySQL InnoDB Cluster Pod のステータスと目的を認識し、アプリケーション オペレーションをそれぞれの正常な Pod にルーティングします。ルーティング状態は Router Pod でキャッシュに保存され、MySQL InnoDB クラスタの各ノードに保存されているクラスタ メタデータから更新されます。インスタンスに障害が発生した場合、Router はライブ インスタンスへの接続ルーティングを調整します。
MySQL InnoDB ClusterSet
最初の MySQL InnoDB クラスタから、MySQL InnoDB ClusterSet を作成できます。 プライマリ クラスタが使用不能になった場合、耐障害性を向上させることができます。
MySQL InnoDB クラスタのプライマリ インスタンスが使用できなくなった場合は、ClusterSet 内のレプリカ クラスタをプライマリに昇格できます。MySQL Router ミドルウェアを使用する場合、アプリケーションでプライマリ データベース インスタンスの正常性を追跡する必要はありません。選択が行われた後に、新しいプライマリに接続を送信するようにルーティングが調整されます。ただし、MySQL ルーター ミドルウェアに接続するアプリケーションが復元力を高めるベスト プラクティスに沿って、クラスタ フェイルオーバー中にエラーが発生した場合に接続を再試行するようにするのは、お客様の責任です。
費用
このドキュメントでは、Google Cloud の次の課金対象のコンポーネントを使用します。
料金計算ツールを使うと、予想使用量に基づいて費用の見積もりを生成できます。
このドキュメントに記載されているタスクの完了後、作成したリソースを削除すると、それ以上の請求は発生しません。詳細については、クリーンアップをご覧ください。
始める前に
プロジェクトを設定する
- Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
-
In the Google Cloud console, on the project selector page, click Create project to begin creating a new Google Cloud project.
-
Make sure that billing is enabled for your Google Cloud project.
-
Enable the GKE API.
-
In the Google Cloud console, on the project selector page, click Create project to begin creating a new Google Cloud project.
-
Make sure that billing is enabled for your Google Cloud project.
-
Enable the GKE API.
ロールの設定
-
Grant roles to your user account. Run the following command once for each of the following IAM roles:
role/storage.objectViewer, role/logging.logWriter, role/artifactregistry.Admin, roles/container.clusterAdmin, role/container.serviceAgent, roles/serviceusage.serviceUsageAdmin, roles/iam.serviceAccountAdmin
gcloud projects add-iam-policy-binding PROJECT_ID --member="user:USER_IDENTIFIER" --role=ROLE
- Replace
PROJECT_ID
with your project ID. -
Replace
USER_IDENTIFIER
with the identifier for your user account. For example,user:myemail@example.com
. - Replace
ROLE
with each individual role.
- Replace
環境の設定
このチュートリアルでは、Cloud Shell を使用して Google Cloud でホストされるリソースを管理します。Cloud Shell には、Docker と kubectl
および gcloud CLI がプリインストールされています。
Cloud Shell を使用して環境を設定するには:
環境変数を設定します。
export PROJECT_ID=PROJECT_ID export CLUSTER_NAME=gkemulti-west export REGION=COMPUTE_REGION
次の値を置き換えます。
- PROJECT_ID: Google Cloud プロジェクト ID
- COMPUTE_REGION: Compute Engine のリージョン。このチュートリアルでは、リージョンは
us-west1
です。通常、近くのリージョンがおすすめです。
デフォルトの環境変数を設定します。
gcloud config set project PROJECT_ID gcloud config set compute/region COMPUTE_REGION
コード リポジトリのクローンを作成します。
git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
作業ディレクトリを変更します。
cd kubernetes-engine-samples/databases/gke-stateful-mysql/kubernetes
GKE クラスタを作成する
このセクションでは、GKE のリージョン クラスタを作成します。ゾーンクラスタとは異なり、リージョン クラスタのコントロール プレーンは複数のゾーンにレプリケートされるので、1 つのゾーンでサービスが停止してもコントロール プレーンが使用できなくなることはありません。
GKE クラスタを作成するには、次の手順に沿って操作します。
Autopilot
Cloud Shell で、
us-west1
リージョンに GKE Autopilot クラスタを作成します。gcloud container clusters create-auto $CLUSTER_NAME \ --region=$REGION
GKE クラスタ認証情報を取得します。
gcloud container clusters get-credentials $CLUSTER_NAME \ --region=$REGION
3 つのゾーンに Service をデプロイします。
kubectl apply -f prepare-for-ha.yaml
デフォルトでは、Autopilot は 2 つのゾーンにリソースをプロビジョニングします。
prepare-for-ha.yaml
で定義された Deployment により、Autopilot は、replicas:3
、requiredDuringSchedulingIgnoredDuringExecution
のpodAntiAffinity
、topologyKey: "topology.kubernetes.io/zone"
を設定して、クラスタ内の 3 つのゾーンにノードをプロビジョニングします。Deployment のステータスを確認します。
kubectl get deployment prepare-three-zone-ha --watch
準備完了状態の Pod が 3 つ表示されたら、
CTRL+C
を使用してこのコマンドをキャンセルします。出力は次のようになります。NAME READY UP-TO-DATE AVAILABLE AGE prepare-three-zone-ha 0/3 3 0 9s prepare-three-zone-ha 1/3 3 1 116s prepare-three-zone-ha 2/3 3 2 119s prepare-three-zone-ha 3/3 3 3 2m16s
このスクリプトを実行して、Pod が 3 つのゾーンにデプロイされていることを確認します。
bash ../scripts/inspect_pod_node.sh default
出力の各行は Pod に対応し、2 番目の列はクラウドゾーンを示します。出力は次のようになります。
gk3-gkemulti-west1-default-pool-eb354e2d-z6mv us-west1-b prepare-three-zone-ha-7885d77d9c-8f7qb gk3-gkemulti-west1-nap-25b73chq-739a9d40-4csr us-west1-c prepare-three-zone-ha-7885d77d9c-98fpn gk3-gkemulti-west1-default-pool-160c3578-bmm2 us-west1-a prepare-three-zone-ha-7885d77d9c-phmhj
標準
Cloud Shell で、
us-west1
リージョンに GKE Standard クラスタを作成します。gcloud container clusters create $CLUSTER_NAME \ --region=$REGION \ --machine-type="e2-standard-2" \ --disk-type="pd-standard" \ --num-nodes="5"
GKE クラスタ認証情報を取得します。
gcloud container clusters get-credentials $CLUSTER_NAME \ --region=$REGION
MySQL StatefulSet をデプロイする
このセクションでは、1 つの MySQL StatefulSet をデプロイします。各 StatefulSet は、3 つの MySQL レプリカで構成されています。
MySQL StatefulSet をデプロイする手順は次のとおりです。
StatefulSet の名前空間を作成します。
kubectl create namespace mysql1
MySQL シークレットを作成します。
kubectl apply -n mysql1 -f secret.yaml
パスワードは各 Pod でデプロイされ、このチュートリアルの MySQL InnoDB クラスタと ClusterSet のデプロイの管理スクリプトとコマンドで使用されます。
StorageClass を作成します。
kubectl apply -n mysql1 -f storageclass.yaml
このストレージ クラスは、パフォーマンスとコストのバランスが取れた
pd-balanced
永続ディスクタイプを使用します。volumeBindingMode
フィールドはWaitForFirstConsumer
に設定されています。つまり、GKE は Pod が作成されるまで PersistentVolume のプロビジョニングを遅延します。これにより、Pod がスケジュールされている同じゾーンでディスクがプロビジョニングされます。MySQL インスタンス Pod の StatefulSet をデプロイします。
kubectl apply -n mysql1 -f c1-mysql.yaml
このコマンドは、3 つのレプリカで構成される StatefulSet をデプロイします。このチュートリアルでは、プライマリ MySQL クラスタは
us-west1
の 3 つのゾーンにデプロイされます。出力は次のようになります。service/mysql created statefulset.apps/dbc1 created
このチュートリアルでは、費用を節約するために、リソースの上限とリクエストを最小値に設定します。本番環境のワークロードを計画する場合は、これらの値を組織のニーズに合わせて 3 つの値を適切に設定してください。
StatefulSet が正常に作成されたことを確認します。
kubectl get statefulset -n mysql1 --watch
StatefulSet の準備が整うまでに 10 分ほどかかることがあります。
3 つの Pod がすべて準備完了の状態になったら、
Ctrl+C
を使用してコマンドを終了します。CPU またはメモリ不足が原因でPodUnscheduleable
エラーが発生した場合は、大きなワークロードに対応できるようにコントロール プレーンのサイズが変更されるまで数分待ちます。出力は次のようになります。
NAME READY AGE dbc1 1/3 39s dbc1 2/3 50s dbc1 3/3 73s
GKE クラスタノード上の Pod の配置を検査するには、次のスクリプトを実行します。
bash ../scripts/inspect_pod_node.sh mysql1 mysql
出力には、Pod 名、GKE ノード名、ノードがプロビジョニングされたゾーンが表示され、次のようになります。
gke-gkemulti-west-5-default-pool-4bcaca65-jch0 us-west1-b dbc1-0 gke-gkemulti-west-5-default-pool-1ac6e8b5-ddjx us-west1-c dbc1-1 gke-gkemulti-west-5-default-pool-1f5baa66-bf8t us-west1-a dbc1-2
出力の列は、ホスト名、クラウドゾーン、Pod 名をそれぞれ表します。
StatefulSet 仕様の
topologySpreadConstraints
ポリシー(c1-mysql.yaml
)は、障害発生ドメイン(topology.kubernetes.io/zone
)全体で Pod を均等に配置するようスケジューラに指示します。podAntiAffinity
ポリシーでは、同じ GKE クラスタノード(kubernetes.io/hostname
)に Pod を配置しないように制約が適用されます。MySQL インスタンス Pod の場合、このポリシーにより、Google Cloud リージョンの 3 つのゾーンに Pod が均等にデプロイされます。この配置により、各データベース インスタンスを別々の障害発生ドメインに配置することで、MySQL InnoDB クラスタの高可用性を実現できます。
プライマリ MySQL InnoDB クラスタを準備する
MySQL InnoDB クラスタを構成する手順は次のとおりです。
Cloud Shell ターミナルで、クラスタに追加する MySQL インスタンスのグループ レプリケーション構成を設定します。
bash ../scripts/c1-clustersetup.sh
このスクリプトは、3 つの MySQL インスタンスにそれぞれリモート接続し、次の環境変数を設定して保持します。
group_replication_ip_allowlist
: クラスタ内のインスタンスがグループ内の任意のインスタンスに接続できるようにします。binlog_transaction_dependency_tracking='WRITESET'
: 競合しない並列トランザクションを許可します。
8.0.22 より前の MySQL バージョンでは、
group_replication_ip_allowlist
ではなくgroup_replication_ip_whitelist
を使用します。Pod ごとにシェルを作成する必要がないように、2 つ目のターミナルを開きます。
Pod
dbc1-0
で MySQL Shell に接続します。kubectl -n mysql1 exec -it dbc1-0 -- \ /bin/bash \ -c 'mysqlsh --uri="root:$MYSQL_ROOT_PASSWORD@dbc1-0.mysql.mysql1.svc.cluster.local"'
他のインスタンスに接続するための MySQL グループ レプリケーション許可リストを確認します。
\sql SELECT @@group_replication_ip_allowlist;
出力は次のようになります。
+----------------------------------+ | @@group_replication_ip_allowlist | +----------------------------------+ | mysql.mysql1.svc.cluster.local | +----------------------------------+
server-id
が各インスタンスで一意であることを確認します。\sql SELECT @@server_id;
出力は次のようになります。
+-------------+ | @@server_id | +-------------+ | 21 | +-------------+
MySQL InnoDB クラスタを使用するように各インスタンスを構成し、各インスタンスに管理者アカウントを作成します。
\js dba.configureInstance('root@dbc1-0.mysql.mysql1.svc.cluster.local', {password: os.getenv("MYSQL_ROOT_PASSWORD"),clusterAdmin: 'icadmin', clusterAdminPassword: os.getenv("MYSQL_ADMIN_PASSWORD")}); dba.configureInstance('root@dbc1-1.mysql.mysql1.svc.cluster.local', {password: os.getenv("MYSQL_ROOT_PASSWORD"),clusterAdmin: 'icadmin', clusterAdminPassword: os.getenv("MYSQL_ADMIN_PASSWORD")}); dba.configureInstance('root@dbc1-2.mysql.mysql1.svc.cluster.local', {password: os.getenv("MYSQL_ROOT_PASSWORD"),clusterAdmin: 'icadmin', clusterAdminPassword: os.getenv("MYSQL_ADMIN_PASSWORD")});
MySQL InnoDB クラスタを正常に機能させるには、すべてのインスタンスで同じユーザー名とパスワードを使用する必要があります。各コマンドの出力は次のようになります。
... The instance 'dbc1-2.mysql:3306' is valid to be used in an InnoDB cluster. Cluster admin user 'icadmin'@'%' created. The instance 'dbc1-2.mysql.mysql1.svc.cluster.local:3306' is already ready to be used in an InnoDB cluster. Successfully enabled parallel appliers.
インスタンスが MySQL InnoDB クラスタで使用できる状態であることを確認します。
dba.checkInstanceConfiguration()
出力は次のようになります。
... The instance 'dbc1-0.mysql.mysql1.svc.cluster.local:3306' is valid to be used in an InnoDB cluster. { "status": "ok" }
必要に応じて、各 MySQL インスタンスに接続して、このコマンドを繰り返すことができます。たとえば、
dbc1-1
インスタンスのステータスを確認するには、次のコマンドを実行します。kubectl -n mysql1 exec -it dbc1-0 -- \ /bin/bash \ -c 'mysqlsh --uri="root:$MYSQL_ROOT_PASSWORD@dbc1-1.mysql.mysql1.svc.cluster.local" \ --js --execute "dba.checkInstanceConfiguration()"'
プライマリ MySQL InnoDB クラスタを作成する
次に、MySQL 管理の createCluster
コマンドを使用して MySQL InnoDB クラスタを作成します。dbc1-0
インスタンス(クラスタのプライマリ インスタンス)から始めて、2 つのレプリカをクラスタに追加します。
MySQL InnoDB クラスタを初期化する手順は次のとおりです。
MySQL InnoDB クラスタを作成します。
var cluster=dba.createCluster('mycluster');
createCluster
コマンドを実行すると、次のオペレーションがトリガーされます。- メタデータ スキーマをデプロイします。
- グループ レプリケーションの構成が正しいことを確認します。
- これを新しいクラスタのシード インスタンスとして登録します。
- レプリケーション ユーザー アカウントなど、必要な内部アカウントを作成します。
- グループのレプリケーションを開始する。
このコマンドは、ホスト
dbc1-0
をプライマリとして MySQL InnoDB クラスタを初期化します。クラスタ参照はクラスタ変数に格納されます。出力は次のようになります。
A new InnoDB cluster will be created on instance 'dbc1-0.mysql:3306'. Validating instance configuration at dbc1-0.mysql:3306... This instance reports its own address as dbc1-0.mysql.mysql1.svc.cluster.local:3306 Instance configuration is suitable. NOTE: Group Replication will communicate with other instances using 'dbc1-0.mysql:33061'. Use the localAddress option to override. Creating InnoDB cluster 'mycluster' on 'dbc1-0.mysql.mysql1.svc.cluster.local:3306'... Adding Seed Instance... Cluster successfully created. Use Cluster.addInstance() to add MySQL instances. At least 3 instances are needed for the cluster to be able to withstand up to one server failure.
2 つ目のインスタンスをクラスタに追加します。
cluster.addInstance('icadmin@dbc1-1.mysql', {password: os.getenv("MYSQL_ROOT_PASSWORD"), recoveryMethod: 'clone'});
残りのインスタンスをクラスタに追加します。
cluster.addInstance('icadmin@dbc1-2.mysql', {password: os.getenv("MYSQL_ROOT_PASSWORD"), recoveryMethod: 'clone'});
出力は次のようになります。
... The instance 'dbc1-2.mysql:3306' was successfully added to the cluster.
クラスタのステータスを確認します。
cluster.status()
このコマンドにより、クラスタのステータスが表示されます。このトポロジは、3 つのホスト(1 つのプライマリ インスタンスと 2 つのセカンダリ インスタンス)で構成されています。必要に応じて、
cluster.status({extended:1})
を呼び出すこともできます。出力は次のようになります。
{ "clusterName": "mysql1", "defaultReplicaSet": { "name": "default", "primary": "dbc1-0.mysql:3306", "ssl": "REQUIRED", "status": "OK", "statusText": "Cluster is ONLINE and can tolerate up to ONE failure.", "topology": { "dbc1-0.mysql:3306": { "address": "dbc1-0.mysql:3306", "memberRole": "PRIMARY", "mode": "R/W", "readReplicas": {}, "replicationLag": null, "role": "HA", "status": "ONLINE", "version": "8.0.28" }, "dbc1-1.mysql:3306": { "address": "dbc1-1.mysql:3306", "memberRole": "SECONDARY", "mode": "R/O", "readReplicas": {}, "replicationLag": null, "role": "HA", "status": "ONLINE", "version": "8.0.28" }, "dbc1-2.mysql:3306": { "address": "dbc1-2.mysql:3306", "memberRole": "SECONDARY", "mode": "R/O", "readReplicas": {}, "replicationLag": null, "role": "HA", "status": "ONLINE", "version": "8.0.28" } }, "topologyMode": "Single-Primary" }, "groupInformationSourceMember": "dbc1-0.mysql:3306" }
必要に応じて、
cluster.status({extended:1})
を呼び出して追加のステータスの詳細を取得できます。
サンプル データベースを作成する
サンプル データベースを作成する手順は次のとおりです。
データベースを作成し、データをデータベースに読み込みます。
\sql create database loanapplication; use loanapplication CREATE TABLE loan (loan_id INT unsigned AUTO_INCREMENT PRIMARY KEY, firstname VARCHAR(30) NOT NULL, lastname VARCHAR(30) NOT NULL , status VARCHAR(30) );
データベースにサンプルデータを挿入します。データを挿入するには、クラスタのプライマリ インスタンスに接続する必要があります。
INSERT INTO loan (firstname, lastname, status) VALUES ( 'Fred','Flintstone','pending'); INSERT INTO loan (firstname, lastname, status) VALUES ( 'Betty','Rubble','approved');
テーブルに、前の手順で挿入した 3 つの行が含まれていることを確認します。
SELECT * FROM loan;
出力は次のようになります。
+---------+-----------+------------+----------+ | loan_id | firstname | lastname | status | +---------+-----------+------------+----------+ | 1 | Fred | Flintstone | pending | | 2 | Betty | Rubble | approved | +---------+-----------+------------+----------+ 2 rows in set (0.0010 sec)
MySQL InnoDB ClusterSet を作成する
MySQL InnoDB ClusterSet を作成すると、専用の ClusterSet レプリケーション チャネルを使用して、プライマリ クラスタからレプリカ クラスタへのレプリケーションを管理できます。
MySQL InnoDB ClusterSet は、複数のゾーンや複数のリージョンなどの代替のロケーションにある複数のレプリカを使用してプライマリ MySQL InnoDB クラスタをリンクさせて、MySQL InnoDB クラスタ デプロイの耐障害性を提供します。
MySQL Shell を閉じた場合は、新しい Cloud Shell ターミナルで次のコマンドを実行して新しいシェルを作成します。
kubectl -n mysql1 exec -it dbc1-0 -- \
/bin/bash -c 'mysqlsh \
--uri="root:$MYSQL_ROOT_PASSWORD@dbc1-0.mysql.mysql1.svc.cluster.local"'
MySQL InnoDB ClusterSet を作成する手順は次のとおりです。
MySQL Shell ターミナルで、クラスタ オブジェクトを取得します。
\js cluster=dba.getCluster()
出力は次のようになります。
<Cluster:mycluster>
クラスタ オブジェクトにプライマリとして保存されている既存の MySQL InnoDB クラスタを使用して、MySQL InnoDB ClusterSet を初期化します。
clusterset=cluster.createClusterSet('clusterset')
出力は次のようになります。
A new ClusterSet will be created based on the Cluster 'mycluster'. * Validating Cluster 'mycluster' for ClusterSet compliance. * Creating InnoDB ClusterSet 'clusterset' on 'mycluster'... * Updating metadata... ClusterSet successfully created. Use ClusterSet.createReplicaCluster() to add Replica Clusters to it. <ClusterSet:clusterset>
MySQL InnoDB ClusterSet のステータスを確認します。
clusterset.status()
出力は次のようになります。
{ "clusters": { "mycluster": { "clusterRole": "PRIMARY", "globalStatus": "OK", "primary": "dbc1-0.mysql:3306" } }, "domainName": "clusterset", "globalPrimaryInstance": "dbc1-0.mysql:3306", "primaryCluster": "mycluster", "status": "HEALTHY", "statusText": "All Clusters available." }
必要に応じて、
clusterset.status({extended:1})
を呼び出して、クラスタに関する情報など、追加のステータスの詳細を取得できます。MySQL Shell を終了します。
\q
MySQL Router をデプロイする
MySQL Router をデプロイして、クライアント アプリケーションのトラフィックを適切なクラスタに転送できます。ルーティングは、データベース オペレーションを発行するアプリケーションの接続ポートに基づきます。
- 書き込みは、プライマリ ClusterSet のプライマリ クラスタ インスタンスにルーティングされます。
- 読み取りは、プライマリ クラスタ内の任意のインスタンスにルーティングできます。
MySQL Router を起動すると、MySQL InnoDB ClusterSet デプロイに対してブートストラップされます。MySQL InnoDB ClusterSet に接続されている MySQL Router インスタンスは、制御されたスイッチオーバーまたは緊急フェイルオーバーを認識し、トラフィックを新しいプライマリ クラスタに転送します。
MySQL Router をデプロイする手順は次のとおりです。
Cloud Shell ターミナルで、MySQL Router をデプロイします。
kubectl apply -n mysql1 -f c1-router.yaml
出力は次のようになります。
configmap/mysql-router-config created service/mysql-router created deployment.apps/mysql-router created
MySQL Router のデプロイの準備状況を確認します。
kubectl -n mysql1 get deployment mysql-router --watch
3 つの Pod がすべて準備完了になると、出力は次のようになります。
NAME READY UP-TO-DATE AVAILABLE AGE mysql-router 3/3 3 0 3m36s
コンソールに
PodUnschedulable
エラーが表示された場合は、GKE が追加のノードをプロビジョニングするまで 1~2 分待ちます。更新すると、3/3 OK
が表示されます。既存のクラスタの任意のメンバーで MySQL Shell を起動します。
kubectl -n mysql1 exec -it dbc1-0 -- \ /bin/bash -c 'mysqlsh --uri="root:$MYSQL_ROOT_PASSWORD@dbc1-0.mysql"'
このコマンドは、
dbc1-0
Pod に接続し、dbc1-0
MySQL インスタンスに接続されたシェルを起動します。ルーターの構成を確認します。
clusterset=dba.getClusterSet() clusterset.listRouters()
出力は次のようになります。
{ "domainName": "clusterset", "routers": { "mysql-router-7cd8585fbc-74pkm::": { "hostname": "mysql-router-7cd8585fbc-74pkm", "lastCheckIn": "2022-09-22 23:26:26", "roPort": 6447, "roXPort": 6449, "rwPort": 6446, "rwXPort": 6448, "targetCluster": null, "version": "8.0.27" }, "mysql-router-7cd8585fbc-824d4::": { ... }, "mysql-router-7cd8585fbc-v2qxz::": { ... } } }
MySQL Shell を終了します。
\q
このスクリプトを実行して、MySQL Router Pod の配置を調べます。
bash ../scripts/inspect_pod_node.sh mysql1 | sort
このスクリプトは、
mysql1
Namespace 内のすべての Pod のノードとクラウドゾーンの配置を表示します。出力は次のようになります。gke-gkemulti-west-5-default-pool-1ac6e8b5-0h9v us-west1-c mysql-router-6654f985f5-df97q gke-gkemulti-west-5-default-pool-1ac6e8b5-ddjx us-west1-c dbc1-1 gke-gkemulti-west-5-default-pool-1f5baa66-bf8t us-west1-a dbc1-2 gke-gkemulti-west-5-default-pool-1f5baa66-kt03 us-west1-a mysql-router-6654f985f5-qlfj9 gke-gkemulti-west-5-default-pool-4bcaca65-2l6s us-west1-b mysql-router-6654f985f5-5967d gke-gkemulti-west-5-default-pool-4bcaca65-jch0 us-west1-b dbc1-0
MySQL Router の Pod がゾーン間で均等に分散されていることがわかります。つまり、MySQL Pod と同じノードに配置されていないか、別の MySQL Router Pod と同じノードに配置されていません。
GKE と MySQL InnoDB クラスタのアップグレードを管理する
MySQL と Kubernetes の更新は定期的にリリースされます。運用のベスト プラクティスに従って、ソフトウェア環境を定期的に更新します。デフォルトでは、GKE はクラスタとノードプールを管理して、アップグレードします。Kubernetes と GKE には、MySQL ソフトウェアのアップグレードを容易にする追加機能も用意されています。
GKE のアップグレードを計画する
ステートフル サービスの実行時に、次のように、予防的な措置を講じて、リスクを軽減してクラスタのアップグレードをよりスムーズに行うための構成を設定することができます。
標準クラスタ: クラスタのアップグレードに関する GKE のベスト プラクティスに沿って実施します。適切なアップグレード戦略を選択して、メンテナンスの時間枠の期間内にアップグレードが確実に行われるようにします。
- コストの最適化が重要であり、ワークロードが 60 分未満で正常なシャットダウンを許容できる場合は、サージ アップグレードを選択します。
- ワークロードの中断を許容できず、リソース使用量の増加によって一時的な費用の増加が許容される場合は、Blue/Green アップグレードを選択します。
詳細については、ステートフル ワークロードを実行するクラスタをアップグレードするをご覧ください。Autopilot クラスタは、選択したリリース チャンネルに基づいて自動的にアップグレードされます。
メンテナンスの時間枠を使用すると、アップグレードが意図したときに行われるようになります。メンテナンスの時間枠の前に、データベースのバックアップが成功したことを確認します。
アップグレードされた MySQL ノードへのトラフィックを許可する前に、Readiness プローブと Liveness プローブを使用して、トラフィックの準備ができていることを確認します。
トラフィックの受信前に、レプリケーションが同期しているかどうかを評価するプローブを作成します。これは、データベースの複雑さと規模に応じて、カスタム スクリプトを通じて実行できます。
Pod 停止予算(PDB)ポリシーを設定する
MySQL InnoDB クラスタが GKE で実行されている場合、クォーラムの要件を満たすために十分な数のインスタンスが常に実行されている必要があります。
このチュートリアルでは、3 つのインスタンスから成る MySQL クラスタを想定し、クォーラムを形成するために 2 つのインスタンスを使用できる必要があります。PodDisruptionBudget
ポリシーによって、任意の時点で終了できる Pod の数の制限が可能になります。これは、ステートフル サービスの安定状態でのオペレーションと、クラスタのアップグレードの両方に役立ちます。
同時に中断される Pod の数を限定するには、ワークロードの PDB を maxUnavailable: 1
に設定します。これにより、サービス オペレーションのどの時点でも、複数の Pod が実行されないことが保証されます。
次の PodDisruptionBudget
ポリシー マニフェストは、MySQL アプリケーションで使用できない Pod の最大数を 1 に設定します。
PDB ポリシーをクラスタに適用する手順は次のとおりです。
kubectl
を使用して PDB ポリシーを適用します。kubectl apply -n mysql1 -f mysql-pdb-maxunavailable.yaml
PDB のステータスを表示します。
kubectl get poddisruptionbudgets -n mysql1 mysql-pdb -o yaml
出力の
status
セクションで、currentHealthy
とdesiredHealthy
の Pod 数を確認します。出力は次のようになります。status: ... currentHealthy: 3 desiredHealthy: 2 disruptionsAllowed: 1 expectedPods: 3 ...
MySQL のバイナリ アップグレードを計画する
Kubernetes と GKE には、MySQL バイナリのアップグレードを容易にする機能があります。ただし、アップグレードの準備として、いくつかの操作を行う必要があります。
アップグレード プロセスを開始する前に、次の点を考慮してください。
- アップグレードは、まずテスト環境で実施する必要があります。本番環境システムのために、本番前環境でさらにテストを実施する必要があります。
- 一部のバイナリ リリースでは、アップグレードを実行した後にバージョンをダウングレードすることはできません。時間をかけてアップグレードの影響を理解してください。
- レプリケーション ソースは新しいバージョンに複製できます。ただし、通常、新しいバージョンから古いバージョンにコピーすることはできません。
- アップグレードされたバージョンをデプロイする前に、データベースに完全なバックアップがあることを確認してください。
- Kubernetes Pod のエフェメラルであるという特性に注意してください。Pod が再デプロイされると、永続ボリュームにない Pod に保存されている構成状態はすべて失われます。
- MySQL のバイナリ アップグレードの場合は、前述と同じ PDB、ノードプールの更新戦略、プローブを使用します。
本番環境では、次のベスト プラクティスに沿って実施してください。
- 新しいバージョンの MySQL でコンテナ イメージを作成します。
- イメージのビルド手順をソース コントロール リポジトリに保持します。
- Cloud Build などの自動化されたイメージのビルドとテスト パイプラインを使用し、Artifact Registry などのイメージ レジストリにイメージ バイナリを保存します。
このチュートリアルをシンプルにするため、コンテナ イメージをビルドして永続化するのではなく、公開されている MySQL イメージを使用します。
アップグレードされた MySQL バイナリをデプロイする
MySQL バイナリのアップグレードを実行するには、StatefulSet リソースのイメージ バージョンを変更する宣言型コマンドを実行します。現在の Pod を停止して、アップグレードされたバイナリで新しい Pod をデプロイし、新しい Pod に永続ディスクを接続するために必要な手順が GKE により行われます。
PDB が作成されたことを確認します。
kubectl get poddisruptionbudgets -n mysql1
ステートフル セットのリストを取得します。
kubectl get statefulsets -n mysql1
app
ラベルを使用して、実行中の Pod のリストを取得します。kubectl get pods --selector=app=mysql -n mysql1
ステートフル セット内の MySQL イメージを更新します。
kubectl -n mysql1 \ set image statefulset/dbc1 \ mysql=mysql/mysql-server:8.0.30
出力は次のようになります。
statefulset.apps/mysql image updated
終了元の Pod と新しい Pod のステータスを確認します。
kubectl get pods --selector=app=mysql -n mysql1
MySQL バイナリのアップグレードを検証する
アップグレード中に、ロールアウト、新しい Pod、既存の Service のステータスを確認できます。
rollout status
コマンドを実行してアップグレードを確認します。kubectl rollout status statefulset/dbc1 -n mysql1
出力は次のようになります。
partitioned roll out complete: 3 new pods have been updated...
ステートフル セットを調べてイメージのバージョンを確認します。
kubectl get statefulsets -o wide -n mysql1
出力は次のようになります。
NAME READY AGE CONTAINERS IMAGES dbc1 3/3 37m mysql mysql/mysql-server:8.0.30
クラスタのステータスを確認します。
kubectl -n mysql1 \ exec -it dbc1-0 -- \ /bin/bash \ -c 'mysqlsh \ --uri="root:$MYSQL_ROOT_PASSWORD@dbc1-1.mysql.mysql1.svc.cluster.local" \ --js \ --execute "print(dba.getClusterSet().status({extended:1})); print(\"\\n\")"'
クラスタ インスタンスごとに、出力でステータスとバージョンの値を探します。出力は次のようになります。
... "status": "ONLINE", "version": "8.0.30" ...
最後のアプリのデプロイのロールアウトをロールバックする
アップグレードされたバイナリ バージョンの Deployment を元に戻すと、ロールアウト プロセスが逆になり、前のイメージ バージョンで Pod の新しいセットがデプロイされます。
Deployment を以前の作業バージョンに戻すには、rollout undo
コマンドを使用します。
kubectl rollout undo statefulset/dbc1 -n mysql1
出力は次のようになります。
statefulset.apps/dbc1 rolled back
データベース クラスタの水平スケーリング
MySQL InnoDB クラスタを水平方向にスケーリングするには、GKE クラスタのノードプールにノードを追加し(標準クラスタを使用している場合にのみ必要)、追加の MySQL インスタンスをデプロイして、各インスタンスを既存の MySQL InnoDB クラスタに追加します。
Standard クラスタにノードを追加する
Autopilot クラスタを使用している場合、このオペレーションは必要ありません。
標準クラスタにノードを追加するには、Cloud Shell または Google Cloud コンソールの次の手順を行います。詳しい手順については、ノードプールのサイズを変更するをご覧ください。
gcloud
Cloud Shell で、デフォルトのノードプールを各マネージド インスタンス グループ内の 8 つのインスタンスにサイズ変更します。
gcloud container clusters resize ${CLUSTER_NAME} \
--node-pool default-pool \
--num-nodes=8
Console
Standard クラスタにノードを追加するには:
- Google Cloud コンソールで
gkemulti-west1
クラスタページを開きます。 - [ノード] を選択し、[デフォルト プール] をクリックします。
- [インスタンス グループ] までスクロールします。
- インスタンス グループごとに、
Number of nodes
値を 5 から 8 ノードにサイズ変更します。
MySQL Pod をプライマリ クラスタに追加する
追加の MySQL Pod をデプロイしてクラスタを水平方向にスケーリングする手順は次のとおりです。
Cloud Shell で、MySQL Deployment のレプリカ数を 3 から 5 に更新します。
kubectl scale -n mysql1 --replicas=5 -f c1-mysql.yaml
デプロイの進行状況を確認します。
kubectl -n mysql1 get pods --selector=app=mysql -o wide
Pod の準備ができているかどうかを確認するには、
--watch
フラグを使用してデプロイを監視します。Autopilot クラスタを使用していて、Pod Unschedulable
エラーが表示される場合は、GKE が追加の Pod に対応するようにノードをプロビジョニングしている可能性があります。クラスタに追加する新しい MySQL インスタンスのグループ レプリケーション設定を構成します。
bash ../scripts/c1-clustersetup.sh 3 4
このスクリプトは、序数 3~4 で Pod で実行されているインスタンスにコマンドを送信します。
MySQL Shell を開きます。
kubectl -n mysql1 \ exec -it dbc1-0 -- \ /bin/bash \ -c 'mysqlsh \ --uri="root:$MYSQL_ROOT_PASSWORD@dbc1-0.mysql"'
2 つの新しい MySQL インスタンスを構成します。
dba.configureInstance('root:$MYSQL_ROOT_PASSWORD@dbc1-3.mysql', {password: os.getenv("MYSQL_ROOT_PASSWORD"),clusterAdmin: 'icadmin', clusterAdminPassword: os.getenv("MYSQL_ADMIN_PASSWORD")}); dba.configureInstance('root:$MYSQL_ROOT_PASSWORD@dbc1-4.mysql', {password: os.getenv("MYSQL_ROOT_PASSWORD"),clusterAdmin: 'icadmin', clusterAdminPassword: os.getenv("MYSQL_ADMIN_PASSWORD")});
このコマンドにより、インスタンスが MySQL InnoDB クラスタの使用に適切に構成されているかを確認し、必要な構成の変更を行います。
新しいインスタンスのいずれかをプライマリ クラスタに追加します。
cluster = dba.getCluster() cluster.addInstance('icadmin@dbc1-3.mysql', {password: os.getenv("MYSQL_ROOT_PASSWORD"), recoveryMethod: 'clone'});
プライマリ クラスタに 2 つ目の新しいインスタンスを追加します。
cluster.addInstance('icadmin@dbc1-4.mysql', {password: os.getenv("MYSQL_ROOT_PASSWORD"), recoveryMethod: 'clone'});
ClusterSet のステータスを取得します。これにはクラスタのステータスも含まれます。
clusterset = dba.getClusterSet() clusterset.status({extended: 1})
出力は次のようになります。
"domainName": "clusterset", "globalPrimaryInstance": "dbc1-0.mysql:3306", "metadataServer": "dbc1-0.mysql:3306", "primaryCluster": "mycluster", "status": "HEALTHY", "statusText": "All Clusters available."
MySQL Shell を終了します。
\q
クリーンアップ
このチュートリアルで使用したリソースについて、Google Cloud アカウントに課金されないようにするには、リソースを含むプロジェクトを削除するか、プロジェクトを維持して個々のリソースを削除します。
プロジェクトを削除する
課金が発生しないようにする最も簡単な方法は、チュートリアル用に作成したプロジェクトを削除することです。
Delete a Google Cloud project:
gcloud projects delete PROJECT_ID
次のステップ
- Google Cloud Observability MySQL インテグレーションが InnoDB に関連するパフォーマンス指標を収集する仕組みを確認する。
- GKE でワークロードをバックアップおよび復元するためのサービスである Backup for GKE の詳細を確認する。
- 永続ボリュームの詳細を確認する。