29
20

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

KubernetesでMySQLのクラスタツールVitessを動かす

Last updated at Posted at 2018-04-03

目的

DockerやKubernetes(k8s)のおかげで様々なソフトウェアを気軽に試す、あるいは開発で利用できるようになりましたが、本番利用を考えると多くの考慮点を解決しなければいけません。その1つがNFRs(Non-Functional Requirements: 非機能要件)です。例えば可用性の観点では、スケールアウトしにくいRDBはk8sとは相性が悪いです。

有名なMySQLはレプリケーションに対応していますが、マスタが死んだときのスレーブの自動昇格をどうやって実現するかの考慮が必要ですし、昇格までの時間はサービス停止になります。また、Oracle公式のMySQL Clusterはk8sへの対応が明確に表明されてないと思っています。

そこで、今回はそこをよしなにしてくれるVitessをk8sで動かしてみます。

VitessはYouTubeが開発したMySQLのクラスタリングツールです。最近CNCFにプロジェクトがホストされたので、それなりに由緒正しいものになりました。

https://vitess.io/

検証は以下の環境で行いました。

  • IBM Cloud Private 2.1.0.2 (Kubernetes 1.9.1)

手順

Helm版について

Chartは以下サイトで公開されていますが、残念ながらまだalphaクオリティとのことです。なので今回は公式サイトの手動の手順に従って検証します。

https://github.com/vitessio/vitess/tree/master/helm/vitess

etcd-operatorのインストール

先にetcd-operatorをデプロイしておきます。今回はnamespaceをdefaultからteruに変えます。ServiceAccountはdefaultではなくetcd-operatorという名称で新規作成し、ClusterRoleを割り当てます。RoleではなくClusterRoleにする理由は、最初のetcd-operatorはCRD(Custom Resource Definition)というものを自動作成しますが、それにはRoleではなくClusterRoleが必要になるため、のようです。このように必要最低限の権限を付与するのがk8sの本番運用では考慮が必要になります(これが大変です)。

ServiceAccountを作成します。

$ kubectl create sa etcd-operator -n teru

ClusterRoleとClusterRoleBindingを作成します。

$ git clone https://github.com/coreos/etcd-operator.git
$ cd etcd-operator
$ export SA_NAME=etcd-operator
$ export ROLE_NAME=etcd-operator
$ export ROLE_BINDING_NAME=etcd-operator
$ export NAMESPACE=teru

$ sed -e "s/<ROLE_NAME>/${ROLE_NAME}/g" example/rbac/cluster-role-template.yaml | kubectl create -f - -n ${NAMESPACE}
$ sed -e "s/<ROLE_NAME>/${ROLE_NAME}/g" -e "s/<ROLE_BINDING_NAME>/${ROLE_BINDING_NAME}/g" -e "s/<NAMESPACE>/${NAMESPACE}/g" example/rbac/cluster-role-binding-template.yaml -e "s/  name: default/  name: ${SA_NAME}/" | kubectl create -f - -n ${NAMESPACE}

Deploymentを作成します。

$ sed -e "s/^    spec:/    spec:\n      serviceAccountName: ${SA_NAME}/" example/deployment.yaml | kubectl create -f - -n ${NAMESPACE}

ログにエラーが出てないか確認します。

$ kubectl get pod -n teru | grep etcd
etcd-operator-65f6cd5964-l98p6       1/1       Running   0          6m

$ kubectl logs etcd-operator-65f6cd5964-l98p6 -n teru
time="2018-03-28T17:40:25Z" level=info msg="etcd-operator Version: 0.9.1"
time="2018-03-28T17:40:25Z" level=info msg="Git SHA: 16f0e1b3"
time="2018-03-28T17:40:25Z" level=info msg="Go Version: go1.9.4"
time="2018-03-28T17:40:25Z" level=info msg="Go OS/Arch: linux/amd64"
time="2018-03-28T17:40:25Z" level=info msg="Event(v1.ObjectReference{Kind:\"Endpoints\", Namespace:\"teru\", Name:\"etcd-operator\", UID:\"1938312d-32af-11e8-a731-000c293da360\", APIVersion:\"v1\", ResourceVersion:\"603114\", FieldPath:\"\"}): type: 'Normal' reason: 'LeaderElection' etcd-operator-65f6cd5964-l98p6 became leader"

Goのインストール

Vitessの各種ツール類を作成するためにGoをインストールします。

$ cd
$ wget https://dl.google.com/go/go1.10.linux-amd64.tar.gz
$ tar zxvf go1.10.linux-amd64.tar.gz 
$ sudo cp -r go /usr/local/

環境変数に次のものを追加します。

~/.bash_profile
export GOPATH=${HOME}/go
export PATH=${PATH}:/usr/local/go/bin:${GOPATH}/bin

vtctlclientのビルドとインストール

以下のコマンドでvtctlclientのビルドとインストールをします。成功すれば${GOPATH}/bin/vtctlclientが出来ます。

$ go get vitess.io/vitess/go/cmd/vtctlclient
$ ls ${GOPATH}/bin/vtctlclient 
/home/teru/go/bin/vtctlclient

バックアップの設定

configure.shを実行します。ここでは主にバックアップをどこに保管するかを指定します。GCS(Google Cloud Storage)かNFSが選べます。今回はNFSにしますが、NFSはPod内にマウントされている必要があります。ここでは/mntにしておきます。

$ cd ${GOPATH}/src/vitess.io/vitess/examples/kubernetes
$ ./configure.sh 
Vitess Docker image (leave empty for default) []: 
Backup Storage (file, gcs) [gcs]: file
Root directory for backups (usually an NFS mount): /mnt

NOTE: You must add your NFS mount to the vtctld-controller-template
      and vttablet-pod-template as described in the Kubernetes docs:
      http://kubernetes.io/v1.0/docs/user-guide/volumes.html#nfs

NOTEの通り、2つのファイルを修正し、NFS領域をマウントする設定をテンプレートファイルに追記します。

vtctld-controller-template.yaml
(略)
          volumeMounts
            - name: backup             # 追加
              mountPath: /mnt          # 追加
(略)
       volumes:
        - name: backup                 # 追加
          persistentVolumeClaim:       # 追加
            claimName: vitess-backup   # 追加
vttablet-pod-template.yaml
(略)
          volumeMounts
            - name: backup             # 追加
              mountPath: /mnt          # 追加
(略)
          volumeMounts
            - name: backup             # 追加
              mountPath: /mnt          # 追加
(略)
          persistentVolumeClaim:       # 追加
            claimName: vitess-backup   # 追加

PersistentVolumeClaimを作っておきます。私は以前の記事でNFSの動的プロビジョニングのためのStorageClassを作っておいたので、それを使います。

vitess-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: vitess-backup
  annotations:
    volume.kubernetes.io/storage-class: "nfs"
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 8Gi
$ kubectl create -f vitess-pvc.yaml

etcdの起動

環境変数VITESS_NAMEにnamespaceを、CELLSにセル名をセットし、etcdを実行します。

$ export VITESS_NAME=teru
$ export CELLS=vitess

$ ./etcd-up.sh 
Creating etcd service for 'global' cell...
etcdcluster "etcd-global" created
Creating etcd service for 'vittes' cell...
etcdcluster "etcd-vittes" created

Podの状態を確認します。しばらく待つとRunningになります。

$ kubectl get pods -n teru | grep etcd
etcd-global-2z5mpjjqmt               1/1       Running   0          11s
etcd-global-4kzbnlkqwf               1/1       Running   0          27s
etcd-global-r66b9nsqrq               1/1       Running   0          36s
etcd-operator-65f6cd5964-ff24g       1/1       Running   0          1h
etcd-vitess-5wxv9g7tv8               1/1       Running   0          35s
etcd-vitess-ltfflh2gxq               1/1       Running   0          27s
etcd-vitess-nbxfjqsjxd               1/1       Running   0          11s

vtlctldの起動

$ ./vtctld-up.sh 
Creating vtctld ClusterIP service...
service "vtctld" created
Creating vtctld replicationcontroller...
replicationcontroller "vtctld" created
persistentvolumeclaim "vitess-backup" created

To access vtctld web UI, start kubectl proxy in another terminal:
  kubectl proxy --port=8001
Then visit http://localhost:8001/api/v1/proxy/namespaces/teru/services/vtctld:web/

言われたとおりにkubectl proxy --port=8001してURLにアクセスしてみましょう。まだ何も定義がありませんが、Vitessのコントロールパネルにアクセスできます。

image.png

トポロジーの設定

トポロジーを設定します。

./kvtctl.sh AddCellInfo -server_address http://etcd-${CELLS}-client:2379 ${CELLS}

vttabletの起動

vttabletを起動します。vttabletとは、mysqldと同じPodで動くものだそうです。環境変数KEYSPACEに任意の値をセットしておきます。また、起動するPod数を調整します。以下の例では、全体のPod数を3、そのうち1つをReadOnlyにしています。デフォルトでは5個のPodが起動しそのうち2つがReadOnlyなのですが、私の検証機ではスペック不足で全て起動できませんでしたので、数を減らしました。

$ export KEYSPACE=teru_keyspace
$ export TABLETS_PER_SHARD=3
$ export RDONLY_COUNT=1
$ ./vttablet-up.sh
Creating teru_keyspace.shard-0 pods in cell vitess...
Creating pod for tablet vitess-0000000100...
pod "vttablet-100" created
Creating pod for tablet vitess-0000000101...
pod "vttablet-101" created
Creating pod for tablet vitess-0000000102...
pod "vttablet-102" created

先ほどのコントロールパネルを見ると、teru_keyspaceで1つのシャードができています。

image.png

Podの状態を表示します。全てRunningになっています。

$ kubectl get pods -n teru | grep vtt
vttablet-100                         2/2       Running   1          59s
vttablet-101                         2/2       Running   1          59s
vttablet-102                         2/2       Running   1          59s

Tabletの状態を表示します。

$ ./kvtctl.sh ListAllTablets ${CELLS}
Starting port forwarding to vtctld...
vitess-0000000100 teru_keyspace 0 replica 10.1.45.220:15002 10.1.45.220:3306 []
vitess-0000000101 teru_keyspace 0 replica 10.1.225.43:15002 10.1.225.43:3306 []
vitess-0000000102 teru_keyspace 0 rdonly 10.1.45.221:15002 10.1.45.221:3306 []

Replicaが2つ、ReadOnlyが1つできています。Masterはまだなくてよいです。

データベースの初期化

データベースを初期化します。

$ ./kvtctl.sh InitShardMaster -force ${KEYSPACE}/0 ${CELLS}-0000000100
Starting port forwarding to vtctld...
W0404 03:09:31.694664   23743 main.go:58] W0403 18:09:31.688983 reparent.go:181] master-elect tablet vitess-0000000100 is not the shard master, proceeding anyway as -force was used
W0404 03:09:31.696059   23743 main.go:58] W0403 18:09:31.689397 reparent.go:187] master-elect tablet vitess-0000000100 is not a master in the shard, proceeding anyway as -force was used

今回は初回なのでまだマスターが存在しない状態です。そのため、InitShardMaster -forceで一番目のTabletであるvitess-0000000100を強制的にマスターにしています。改めてTabletの状態を見ると、masterが出現しました。

$ ./kvtctl.sh ListAllTablets ${CELLS}
Starting port forwarding to vtctld...
vitess-0000000100 teru_keyspace 0 master 10.1.45.220:15002 10.1.45.220:3306 []
vitess-0000000101 teru_keyspace 0 replica 10.1.225.43:15002 10.1.225.43:3306 []
vitess-0000000102 teru_keyspace 0 rdonly 10.1.45.221:15002 10.1.45.221:3306 []

テーブルの作成

それではテーブルを作成します。ソースツリー付属のテストテーブルを使います。

$ cat create_test_table.sql
CREATE TABLE messages (
  page BIGINT(20) UNSIGNED,
  time_created_ns BIGINT(20) UNSIGNED,
  message VARCHAR(10000),
  PRIMARY KEY (page, time_created_ns)
) ENGINE=InnoDB

$ ./kvtctl.sh ApplySchema -sql "$(cat create_test_table.sql)" ${KEYSPACE}
Starting port forwarding to vtctld...

次のコマンドで各tabletにテーブル定義がレプリケーションされていることがわかります。

$ ./kvtctl.sh GetSchema ${CELLS}-0000000100
$ ./kvtctl.sh GetSchema ${CELLS}-0000000101
$ ./kvtctl.sh GetSchema ${CELLS}-0000000102

(例)
Starting port forwarding to vtctld...
{
  "database_schema": "CREATE DATABASE /*!32312 IF NOT EXISTS*/ {{.DatabaseName}} /*!40100 DEFAULT CHARACTER SET utf8 */",
  "table_definitions": [
    {
      "name": "messages",
      "schema": "CREATE TABLE `messages` (\n  `page` bigint(20) unsigned NOT NULL,\n  `time_created_ns` bigint(20) unsigned NOT NULL,\n  `message` varchar(10000) DEFAULT NULL,\n  PRIMARY KEY (`page`,`time_created_ns`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8",
      "columns": [
        "page",
        "time_created_ns",
        "message"
      ],
      "primary_key_columns": [
        "page",
        "time_created_ns"
      ],
      "type": "BASE TABLE",
      "data_length": "16384",
      "row_count": "0"
    }
  ],
  "version": "5b2e5dbcb5766b6c69fe55c81b6ea805"
}

データのバックアップ

ここで最初のバックアップをとります。バックアップはReadOnlyノードの1つを指定して取得します。なぜReadOnlyノードを指定するかというと、バックアップの間はレプリケーションが一時的に停止するので、静止点が取れるのだそうです。

$ ./kvtctl.sh Backup ${CELLS}-0000000102
Starting port forwarding to vtctld...

正しくとれたか確認してみます。

$ ./kvtctl.sh ListBackups ${KEYSPACE}/0
Starting port forwarding to vtctld...
2018-04-03.181103.vitess-0000000102

このバックアップがあると、今後ノードを足したときに自動的にこれを使ってリストアし、マスタからの差分をレプリケーションしてくれるのだそうです。便利ですね。

Routing Schemaの初期化

説明を読んでもよくわかりませんでしたが、何かの初期化のようです。

$ ./kvtctl.sh RebuildVSchemaGraph
Starting port forwarding to vtctld...

vtgateの起動

構成作業の最後ですが、クライアントから生きてるMySQLにルーティングするためのvtgateを起動します。デフォルトではレプリカが3つ起動しますが私の検証環境はリソース不足なので1個にします。

$ export VTGATE_REPLICAS=1
$ ./vtgate-up.sh
Creating vtgate service in cell vitess...
service "vtgate-vitess" created
Creating vtgate replicationcontroller in cell vitess...
replicationcontroller "vtgate-vitess" created

$ kubectl get pods -n teru | grep vt
vtctld-rcdtg                         1/1       Running   0          2h
vtgate-vitess-4cb6w                  1/1       Running   0          1m
vttablet-100                         2/2       Running   1          39m
vttablet-101                         2/2       Running   1          39m
vttablet-102                         2/2       Running   1          39m

以上でセットアップは完了です。今後、実際に動かしていろいろ検証したいと思います。

29
20
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
29
20

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?