コンテナの世界にいる場合は、クラスタ化されたデータベースシステムに完全なKubernetes自動化を採用するのはかなり難しいことをご存知でしょう。これにより、通常、コンテナベースにある程度の複雑さが加わります。これらのステートフルアプリケーションのアーキテクチャ。そこで、Kubernetesオペレーターがこの問題の解決に役立てることができます。 Kubernetesオペレーターは、複雑なデプロイを簡素化するために導入された特殊なタイプのコントローラーであり、基本的にカスタムリソースでKubernetesAPIを拡張します。 Kubernetesの基本的なリソースとコントローラーの概念に基づいていますが、管理するソフトウェアのライフサイクル全体を自動化するためのドメインまたはアプリケーション固有の知識が含まれています。
Percona XtraDB Cluster Operatorは、Perconaによって構築および保守される、Kubernetes内でのデプロイ、スケーリング、バックアップ、アップグレードなど、PerconaXtraDBClusterの特定のタスクを自動化するための優れた方法です。永続ボリュームを備えたStatefulSetにクラスターをデプロイします。これにより、クラスター内の各ポッドと維持するデータの一貫したIDを維持できます。
このブログ投稿では、GoogleCloudPlatform上のPerconaXtraDBCluster Kubernetes Operatorによって調整された、コンテナ化された環境でのPercona XtraDBCluster8.0のデプロイをテストします。
GoogleCloudでのKubernetesクラスターの作成
このウォークスルーでは、Kubernetesを起動して実行するのが比較的簡単で簡単なため、GoogleCloudでKubernetesクラスターを使用します。 Google CloudPlatformダッシュボード->コンピューティング->Kubernetesエンジン->クラスターの作成にログインすると、次のダイアログが表示されます。
Kubernetesクラスター名を入力し、希望のゾーンを選択して、[作成]をクリックするだけです。 "(ページの下部にあります)。 5分以内に、3ノードのKubernetesクラスターの準備が整います。次に、ワークステーションに、このガイドに示されているようにgcloud SDKをインストールしてから、Kubernetes構成をワークステーションにプルします。
$ gcloud container clusters get-credentials my-k8s-cluster --zone asia-northeast1-a --project s9s-qa
Fetching cluster endpoint and auth data.
kubeconfig entry generated for my-k8s-cluster.
この時点で、Kubernetesクラスターに接続できるはずです。次のコマンドを実行して確認します。
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
gke-my-k8s-cluster-default-pool-b80902cd-gp09 Ready <none> 139m v1.16.13-gke.401
gke-my-k8s-cluster-default-pool-b80902cd-jdc3 Ready <none> 139m v1.16.13-gke.401
gke-my-k8s-cluster-default-pool-b80902cd-rdv8 Ready <none> 139m v1.16.13-gke.401
上記の出力は、Kubernetesマスターに接続して、Kubernetesクラスターノードを取得できることを意味します。これで、Kubernetesワークロードを実行する準備が整いました。
KubernetesでのPerconaXtraDBクラスターのデプロイ
ワークロードの展開については、Percona XtraDBClusterOperatorのドキュメントに記載されている手順に従います。基本的に、ワークステーションで次のコマンドを実行して、カスタムリソース、名前空間、ロールベースのアクセス制御、およびKubernetesオペレーター自体を作成します。
$ git clone -b v1.6.0 https://github.com/percona/percona-xtradb-cluster-operator
$ cd percona-xtradb-cluster-operator/
$ kubectl apply -f deploy/crd.yaml
$ kubectl create namespace pxc
$ kubectl config set-context $(kubectl config current-context) --namespace=pxc
$ kubectl create clusterrolebinding cluster-admin-binding --clusterrole=cluster-admin --user=$(gcloud config get-value core/account)
$ kubectl apply -f deploy/rbac.yaml
$ kubectl apply -f deploy/operator.yaml
次に、deploy / secrets.yaml内の値をbase64エンコード形式で更新して、パスワード(Kubernetes用語ではSecretsと呼ばれます)を準備する必要があります。 https://www.base64encode.org/などのオンラインツールを使用して作成するか、次のようなコマンドラインツールを使用できます。
$ echo -n 'mypassword' | base64
bXlwYXNzd29yZA==
次に、以下に示すように、deploy/secrets.yamlを更新します。
apiVersion: v1
kind: Secret
metadata:
name: my-cluster-secrets
type: Opaque
data:
root: bXlwYXNzd29yZA==
xtrabackup: bXlwYXNzd29yZA==
monitor: bXlwYXNzd29yZA==
clustercheck: bXlwYXNzd29yZA==
proxyadmin: bXlwYXNzd29yZA==
pmmserver: bXlwYXNzd29yZA==
operator: bXlwYXNzd29yZA==
上記は、すべてのユーザーに対してすべてのパスワードが同じになるように設定する、シークレット管理を非常に単純化したものです。本番環境では、より複雑なパスワードを使用し、ユーザーごとに異なるパスワードを指定してください。
これで、シークレット構成をKubernetesにプッシュできます:
$ kubectl apply -f deploy/secrets.yaml
Percona XtraDBクラスターのデプロイに進む前に、クラスターのdeploy/cr.yaml内のデフォルトのデプロイメント定義を再検討する必要があります。ここで定義されているKubernetesオブジェクトはたくさんありますが、それらのほとんどはコメント化されています。ワークロードについては、次のように変更します。
$ cat deploy/cr.yaml
apiVersion: pxc.percona.com/v1-6-0
kind: PerconaXtraDBCluster
metadata:
name: cluster1
finalizers:
- delete-pxc-pods-in-order
spec:
crVersion: 1.6.0
secretsName: my-cluster-secrets
vaultSecretName: keyring-secret-vault
sslSecretName: my-cluster-ssl
sslInternalSecretName: my-cluster-ssl-internal
allowUnsafeConfigurations: false
updateStrategy: SmartUpdate
upgradeOptions:
versionServiceEndpoint: https://check.percona.com
apply: recommended
schedule: "0 4 * * *"
pxc:
size: 3
image: percona/percona-xtradb-cluster:8.0.20-11.1
configuration: |
[client]
default-character-set=utf8
[mysql]
default-character-set=utf8
[mysqld]
collation-server = utf8_unicode_ci
character-set-server = utf8
default_authentication_plugin = mysql_native_password
resources:
requests:
memory: 1G
affinity:
antiAffinityTopologyKey: "kubernetes.io/hostname"
podDisruptionBudget:
maxUnavailable: 1
volumeSpec:
persistentVolumeClaim:
resources:
requests:
storage: 6Gi
gracePeriod: 600
haproxy:
enabled: true
size: 3
image: percona/percona-xtradb-cluster-operator:1.6.0-haproxy
resources:
requests:
memory: 1G
affinity:
antiAffinityTopologyKey: "kubernetes.io/hostname"
podDisruptionBudget:
maxUnavailable: 1
gracePeriod: 30
backup:
image: percona/percona-xtradb-cluster-operator:1.6.0-pxc8.0-backup
storages:
fs-pvc:
type: filesystem
volume:
persistentVolumeClaim:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 6Gi
schedule:
- name: "daily-backup"
schedule: "0 0 * * *"
keep: 5
storageName: fs-pvc
上記のように、提供されたcr.yamlにいくつかの変更を加えて、アプリケーションで機能するようにしました。まず、CPUに関連するすべての行([*]。resources.requests.cpu:600mなど)をコメントアウト(または削除)して、KubernetesがCPUが制限されているノードでポッドの作成を正しくスケジュールできるようにする必要があります。次に、次の抜粋に示すように、後でデプロイするWordPressアプリケーションとスムーズに連携するために、MySQL8.0に基づくPerconaXtraDBCluster8.0の互換性オプションをいくつか追加する必要があります。
configuration: |
[client]
default-character-set=utf8
[mysql]
default-character-set=utf8
[mysqld]
collation-server = utf8_unicode_ci
character-set-server = utf8
default_authentication_plugin = mysql_native_password
上記は、MySQLサーバーのデフォルトの文字セットをWordPressコンテナのMySQLiPHPドライバーと一致させます。次のセクションは、「enabled:true」に設定されているHAProxyデプロイメントです。 「enabled:false」のProxySQLセクションもあります。通常、すべてのクラスターに対していずれかのリバースプロキシを選択します。最後のセクションはバックアップ構成です。ここでは、毎日午前12時にバックアップをスケジュールし、最後の5つのバックアップを保持します。
これで、3ノードのPerconaXtraDBクラスターのデプロイを開始できます。
$ kubectl apply -f deploy/cr.yaml
作成プロセスには時間がかかります。オペレーターは、Percona XtraDBクラスターポッドをステートフルセットとしてデプロイします。つまり、一度に1つのポッドを作成し、ステートフルセット内の各ポッドには、セット全体で一意の0からN-1までの整数の序数が割り当てられます。オペレーターとポッドの両方が実行ステータスに達すると、プロセスは終了します:
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
cluster1-haproxy-0 2/2 Running 0 71m
cluster1-haproxy-1 2/2 Running 0 70m
cluster1-haproxy-2 2/2 Running 0 70m
cluster1-pxc-0 1/1 Running 0 71m
cluster1-pxc-1 1/1 Running 0 70m
cluster1-pxc-2 1/1 Running 0 69m
percona-xtradb-cluster-operator-79d786dcfb-6clld 1/1 Running 0 121m
この演算子はカスタムリソースであるため、perconaxtradbclusterリソースを操作して、標準のKubernetesリソースと同じようにすることができます。
$ kubectl get perconaxtradbcluster
NAME ENDPOINT STATUS PXC PROXYSQL HAPROXY AGE
cluster1 cluster1-haproxy.pxc ready 3 3 27h
短いリソース名「pxc」を使用して、次のコマンドを試すこともできます。
$ kubectl describe pxc
$ kubectl edit pxc
ワークロードセットを見ると、オペレーターが2つのStatefulSetを作成したことがわかります。
$ kubectl get statefulsets -o wide
NAME READY AGE CONTAINERS IMAGES
cluster1-haproxy 3/3 26h haproxy,pxc-monit percona/percona-xtradb-cluster-operator:1.6.0-haproxy,percona/percona-xtradb-cluster-operator:1.6.0-haproxy
cluster1-pxc 3/3 26h pxc percona/percona-xtradb-cluster:8.0.20-11.2
オペレーターは、それぞれのポッドへの負荷分散接続を行う対応するサービスも作成します。
$ kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
cluster1-haproxy ClusterIP 10.40.9.177 <none> 3306/TCP,3309/TCP,33062/TCP 3h27m
cluster1-haproxy-replicas ClusterIP 10.40.0.236 <none> 3306/TCP 3h27m
cluster1-pxc ClusterIP None <none> 3306/TCP,33062/TCP 3h27m
cluster1-pxc-unready ClusterIP None <none> 3306/TCP,33062/TCP 3h27m
上記の出力は、オペレーターが4つのサービスを作成したことを示しています。
- cluster1-haproxy -負荷分散されたMySQLシングルマスター(3306)、プロキシプロトコル(3309)、およびMySQL Admin(33062)のサービス-MySQL8.0.14以降で導入された新しい管理ポート。これは、Galeraクラスターへのシングルマスター接続を確立するためにアプリケーションが接続する必要のあるサービス名またはクラスターIPアドレスです。
- cluster1-haproxy-replicas -負荷分散されたMySQLマルチマスター(3306)のサービス。これは、アプリケーションがラウンドロビンバランシングアルゴリズムを使用してGaleraクラスターにマルチマスター接続するために接続する必要があるサービス名またはクラスターIPアドレスです。
- cluster1-pxc -HAProxyをバイパスする負荷分散されたPXCポッドのサービス。このサービスに直接接続することで、Kubernetesは、cluster-haproxy-replicaseが提供するものと同様に、ラウンドロビン方式で接続をすべてのPXCポッドにルーティングします。このサービスにはパブリックIPアドレスが割り当てられておらず、クラスター外では利用できません。
- cluster1-pxc-unready -ポッドの状態に関係なく、アプリケーションの起動中にポッドアドレスを検出するには、「unready」サービスが必要です。 Proxysqlポッドとpxcポッドは、データベースが完全に機能するようになる前に、お互いを知っている必要があります。準備ができていないサービスにはパブリックIPアドレスが割り当てられておらず、クラスター外では利用できません。
MySQLクライアントを介して接続するには、次のコマンドを実行するだけです。
$ kubectl run -i --rm --tty percona-client --image=percona:8.0 --restart=Never -- bash -il
これにより、一時的なポッドが作成され、すぐにコンテナ環境に入ります。次に、適切なクレデンシャルを使用して標準のmysqlクライアントコマンドを実行します。
bash-4.2$ mysql -uroot -pmypassword -h cluster1-haproxy -P3306 -e 'SELECT @@hostname'
mysql: [Warning] Using a password on the command line interface can be insecure.
+----------------+
| @@hostname |
+----------------+
| cluster1-pxc-0 |
+----------------+
ポッドの配置を見ると、すべてのPercona XtraDBクラスターポッドは別のKubernetesホストにあります:
$ kubectl get pods -o wide --selector=app.kubernetes.io/component=pxc
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
cluster1-pxc-0 1/1 Running 0 67m 10.36.2.5 gke-my-k8s-cluster-default-pool-b80902cd-gp09 <none> <none>
cluster1-pxc-1 1/1 Running 0 66m 10.36.1.10 gke-my-k8s-cluster-default-pool-b80902cd-rdv8 <none> <none>
cluster1-pxc-2 1/1 Running 0 65m 10.36.0.11 gke-my-k8s-cluster-default-pool-b80902cd-jdc3 <none> <none>
これにより、Kubernetesホストの1つがダウンした場合に備えて、サービスの可用性が確実に向上します。
5つのポッドにスケールアップするには、ポッドのアフィニティ設定を尊重するために、事前に別の2つの新しいKubernetesノードを準備する必要があります(デフォルトはaffinity.antiAffinityTopologyKey.topologyKey ="kubernetes.io/hostname")。次に、次のパッチコマンドを実行して、PerconaXtraDBクラスターを5ノードにスケーリングします。
$ kubectl patch pxc cluster1 \
--type='json' -p='[{"op": "replace", "path": "/spec/pxc/size", "value": 5 }]'
kubectl get podsコマンドを使用して、ポッドの作成を監視します。
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
cluster1-pxc-0 1/1 Running 0 27h 10.36.2.5 gke-my-k8s-cluster-default-pool-b80902cd-gp09 <none> <none>
cluster1-pxc-1 1/1 Running 0 27h 10.36.1.10 gke-my-k8s-cluster-default-pool-b80902cd-rdv8 <none> <none>
cluster1-pxc-2 1/1 Running 0 27h 10.36.0.11 gke-my-k8s-cluster-default-pool-b80902cd-jdc3 <none> <none>
cluster1-pxc-3 1/1 Running 0 30m 10.36.7.2 gke-my-k8s-cluster-pool-1-ab14a45e-h1pf <none> <none>
cluster1-pxc-4 1/1 Running 0 13m 10.36.5.3 gke-my-k8s-cluster-pool-1-ab14a45e-01qn <none> <none>
別の2つの新しいポッド(cluster1-pxc-3およびcluster1-pxc-4)が別の2つの新しいKubernetesノード(gke-my-k8s-cluster-pool-1-ab14a45e-h1pf)に作成されましたおよびgke-my-k8s-cluster-pool-1-ab14a45e-01qn)。スケールダウンするには、上記のパッチコマンドで値を3に戻すだけです。スプリットブレインを防ぐために、PerconaXtraDBクラスターは奇数のノードで実行する必要があることに注意してください。
アプリケーションのデプロイ(WordPress)
この例では、PerconaXtraDBクラスターとHAProxyの上にWordPressアプリケーションをデプロイします。まず、次のようなYAML定義ファイルを準備しましょう:
$ cat wordpress-deployment.yaml
apiVersion: v1
kind: Service
metadata:
name: wordpress
labels:
app: wordpress
spec:
ports:
- port: 80
selector:
app: wordpress
tier: frontend
type: LoadBalancer
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: wp-pv-claim
labels:
app: wordpress
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 2Gi
---
apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
name: wordpress
labels:
app: wordpress
spec:
selector:
matchLabels:
app: wordpress
tier: frontend
strategy:
type: Recreate
template:
metadata:
labels:
app: wordpress
tier: frontend
spec:
containers:
- image: wordpress:4.8-apache
name: wordpress
env:
- name: WORDPRESS_DB_HOST
value: cluster1-haproxy
- name: WORDPRESS_DB_PASSWORD
valueFrom:
secretKeyRef:
name: my-cluster-secrets
key: root
ports:
- containerPort: 80
name: wordpress
volumeMounts:
- name: wordpress-persistent-storage
mountPath: /var/www/html
volumes:
- name: wordpress-persistent-storage
persistentVolumeClaim:
claimName: wp-pv-claim
WORDPRESS_DB_HOSTおよびWORDPRESS_DB_PASSWORD環境変数に注意してください。前者の変数は、個々のデータベースノードではなく、データベースホストとして「cluster1-haproxy」を定義し、後者の場合は、キー「root」の下のmy-cluster-secretsオブジェクトから読み取るようにKubernetesに指示することでルートパスワードを指定しました。これは「mypassword」と同等です(base64値がデコードされた後)。デフォルト値は「root」であるため、WORDPRESS_DB_USER環境変数の定義はスキップします。
これで、アプリケーションを作成できます:
$ kubectl apply -f wordpress-deployment.yaml
$ kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
cluster1-haproxy ClusterIP 10.40.9.177 <none> 3306/TCP,3309/TCP,33062/TCP 4h42m
cluster1-haproxy-replicas ClusterIP 10.40.0.236 <none> 3306/TCP 4h42m
cluster1-pxc ClusterIP None <none> 3306/TCP,33062/TCP 4h42m
cluster1-pxc-unready ClusterIP None <none> 3306/TCP,33062/TCP 4h42m
wordpress LoadBalancer 10.40.13.205 35.200.78.195 80:32087/TCP 4h39m
この時点で、http://35.200.78.195/(外部IPアドレス)でWordPressアプリケーションに接続し、WordPressアプリケーションの構成を開始できます。この時点で、WordPressアプリケーションはHAProxyポッドの1つを介してPercona XtraDBクラスターの1つに接続されています(シングルマスター接続)。