Linode Kubernetes Engine (LKE) でTiDBを構築する

# はじめに

Linode Kubernetes Engine (LKE) は Akamai の Cloud Computing Services上で動作するコンテナ化されたアプリケーションやワークロードを展開・管理するための、フルマネージドのKubernetes(k8s)コンテナオーケストレーションエンジンです。
今回はLKEを利用して、PingCAPが開発するNewSQLのオープンソースデータベース「TiDB」を構築してみます。

## TiDBとは

PingCAPが開発するNewSQLのオープンソースデータベース「TiDB」は、分散型のデータベースです。レプリケーション遅延やノードをまたいだアクセスの性能劣化が少ないことが特徴です。

https://pingcap.co.jp/tidb-overview/

NewSQLとは、従来のリレーショナルデータベース（RDBMS）のトランザクション性と整合性を保持しつつ、分散型システムのスケーラビリティとパフォーマンスを兼ね備えた新しいデータベースシステムです。

RDBの使い勝手はそのままに、分散アーキテクチャを活用した拡張性を担保しています。

||RDB|NoSQL|NewSQL|
|---|---|---|---|
|CAPの考え方|CA|AP|CP+HA|
|クエリ|SQL|API,SQL(CQL)|SQL|
|トランザクション|◯|✕|◯|
|JOIN|◯|✕|◯|
|Read拡張性|◯<br>リードレプリカ<br>テーブル再設計|◎|◎<br>分散アーキテクチャ<br>テーブル再設計不要|
|Write拡張性|△<br>単一ボトルネック<br>シャーディング必要|◎|◎ <br>分散アーキテクチャ

## Linode Kubernetes Engine (LKE) でTiDBを構築する

TiDBはTiDB Operatorを利用することでKubernetes上のクラスターを管理することができるようになります。

https://docs.pingcap.com/tidb-in-kubernetes/dev/tidb-operator-overview

### 各コンポーネントについて

**Placement Driver (PD) Server**
クラスター全体のメタデータ管理をします。TiKVとTiDBのクラスターのトポロジ構造を保存しています。

**TiDB Server**
MySQLの接続エンドポイントを公開するSQLレイヤーです。
SQLリクエストを受信し、TiKVへデータの読み取りリクエストを送ります。

**TiKV Server**
データの保存を行います。TiKVに保存されたデータは複数のレプリカで自動的に維持されるため、高可用性と自動フェイルオーバーをサポートしています。

**TiFlash Server**
特殊なタイプのストレージとなり、データを列ごとに保存し分散処理の高速化に役立ちます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/49877/98c4cfe9-340e-69a8-1b11-8bef0992588f.png)

### LKEへのTiDBインストール

Linode Kubernetes Engine (LKE)ではGeneral Kubernetesの手順を参考に構築することができます。

https://docs.pingcap.com/tidb-in-kubernetes/dev/get-started

はじめに、Akamai Cloud ManagerからLKEのクラスターを構築します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/49877/c717b1f8-1150-16e0-db06-44c4cf50df72.png)

作成したLKEのKubeconfigをダウンロードして、ローカル端末などでkubectlを利用できるようにします。
設定したkubectlを利用して、TiDB Operator CRDsのインストールをします。

```
kubectl create -f https://raw.githubusercontent.com/pingcap/tidb-operator/master/manifests/crd.yaml
```

TiDB Operatorのインストールをします。

```
helm repo add pingcap https://charts.pingcap.org/

kubectl create namespace tidb-admin

helm install --namespace tidb-admin tidb-operator pingcap/tidb-operator --version v1.5.0
```

Podが正常に起動しているか確認します。

```
kubectl get pods --namespace tidb-admin -l app.kubernetes.io/instance=tidb-operator

NAME                                       READY   STATUS    RESTARTS        AGE
tidb-controller-manager-67d678dc64-w6gkn   1/1     Running   16 (164m ago)   2d22h
tidb-scheduler-85d647c86c-vx2gq            2/2     Running   4 (164m ago)    2d22h
```

TiDB cluster と monitoring services のインストールをします。

```
kubectl create namespace tidb-cluster
```

TiDBを構築するためのYAMLを記載します。
今回はいくつかのパラメータを修正しています。（コメントにて記載）

```yaml:tidb-cluster.yaml
# IT IS NOT SUITABLE FOR PRODUCTION USE.
# This YAML describes a basic TiDB cluster with minimum resource requirements,
# which should be able to run in any Kubernetes cluster with storage support.
apiVersion: pingcap.com/v1alpha1
kind: TidbCluster
metadata:
  name: basic
spec:
  version: v6.5.0
  timezone: UTC
  pvReclaimPolicy: Retain
  enableDynamicConfiguration: true
  configUpdateStrategy: RollingUpdate
  discovery: {}
  helper:
    image: alpine:3.16.0
  pd:
    baseImage: pingcap/pd
    maxFailoverCount: 0
    # レプリカ数を修正
    replicas: 3
    # if storageClassName is not set, the default Storage Class of the Kubernetes cluster will be used
    # storageClassName: local-storage
    requests:
      # 容量を修正
      storage: "10Gi"
    config: {}
  tikv:
    baseImage: pingcap/tikv
    maxFailoverCount: 0
    # If only 1 TiKV is deployed, the TiKV region leader
    # cannot be transferred during upgrade, so we have
    # to configure a short timeout
    evictLeaderTimeout: 1m
    # レプリカ数を修正
    replicas: 3
    # if storageClassName is not set, the default Storage Class of the Kubernetes cluster will be used
    # storageClassName: local-storage
    requests:
      # 容量を修正
      storage: "100Gi"
    config:
      storage:
        # In basic examples, we set this to avoid using too much storage.
        reserve-space: "0MB"
      rocksdb:
        # In basic examples, we set this to avoid the following error in some Kubernetes clusters:
        # "the maximum number of open file descriptors is too small, got 1024, expect greater or equal to 82920"
        max-open-files: 256
      raftdb:
        max-open-files: 256
  tidb:
    baseImage: pingcap/tidb
    maxFailoverCount: 0
    # レプリカ数を修正
    replicas: 3
    service:
      # LB経由のアクセスに修正
      type: LoadBalancer
    config: {}
```

作成したYAMLをApplyしてTiDBを構築します。

```
kubectl -n tidb-cluster apply -f tidb-cluster.yaml

kubectl -n tidb-cluster apply -f https://raw.githubusercontent.com/pingcap/tidb-operator/master/examples/basic/tidb-dashboard.yaml

kubectl -n tidb-cluster apply -f https://raw.githubusercontent.com/pingcap/tidb-operator/master/examples/basic/tidb-monitor.yaml
```

Podが正常に起動しているか確認をします。

```
kubectl get po -n tidb-cluster

NAME                               READY   STATUS    RESTARTS        AGE
basic-discovery-798df4d8b4-8pp22   1/1     Running   0               2d22h
basic-monitor-0                    4/4     Running   0               2d22h
basic-pd-0                         1/1     Running   1 (2d22h ago)   2d22h
basic-pd-1                         1/1     Running   0               2d22h
basic-pd-2                         1/1     Running   0               2d22h
basic-tidb-0                       2/2     Running   0               2d22h
basic-tidb-1                       2/2     Running   0               2d22h
basic-tidb-2                       2/2     Running   0               2d22h
basic-tidb-dashboard-0             1/1     Running   0               2d22h
basic-tikv-0                       1/1     Running   0               2d22h
basic-tikv-1                       1/1     Running   0               2d22h
basic-tikv-2                       1/1     Running   0               2d22h
```

YAMLに記載しているとおりに、外部ディスクが付与されているか確認をします。

```
 kubectl get pvc -n tidb-cluster
NAME                                         STATUS   VOLUME                 CAPACITY   ACCESS MODES   STORAGECLASS                  AGE
pd-basic-pd-0                                Bound    pvc-c15a1f5405a54010   10Gi       RWO            linode-block-storage-retain   2d22h
pd-basic-pd-1                                Bound    pvc-3e941d50544d4276   10Gi       RWO            linode-block-storage-retain   2d22h
pd-basic-pd-2                                Bound    pvc-d054d6ead6ce4cc4   10Gi       RWO            linode-block-storage-retain   2d22h
tidb-dashboard-data-basic-tidb-dashboard-0   Bound    pvc-9b377a7ea3d84dde   10Gi       RWO            linode-block-storage-retain   2d22h
tikv-basic-tikv-0                            Bound    pvc-9a8a17d6224e48fb   100Gi      RWO            linode-block-storage-retain   2d22h
tikv-basic-tikv-1                            Bound    pvc-f402a300368a4db2   100Gi      RWO            linode-block-storage-retain   2d22h
tikv-basic-tikv-2                            Bound    pvc-a520aecfb91d42fe   100Gi      RWO            linode-block-storage-retain   2d22h
```

以上で構築は完了です。

## SQLの接続テスト

ロードバランサー経由でアクセスするためにExternal-IPを確認します。

```
kubectl get services -n tidb-cluster
NAME                           TYPE           CLUSTER-IP       EXTERNAL-IP      PORT(S)                          AGE
basic-discovery                ClusterIP      10.128.117.53    <none>           10261/TCP,10262/TCP              19h
basic-grafana                  ClusterIP      10.128.241.25    <none>           3000/TCP                         19h
basic-monitor-reloader         ClusterIP      10.128.195.76    <none>           9089/TCP                         19h
basic-pd                       ClusterIP      10.128.22.218    <none>           2379/TCP                         19h
basic-pd-peer                  ClusterIP      None             <none>           2380/TCP,2379/TCP                19h
basic-prometheus               ClusterIP      10.128.183.161   <none>           9090/TCP                         19h
basic-tidb                     LoadBalancer   10.128.68.183    xxx.xxx.xxx.xxx   4000:32266/TCP,10080:30413/TCP   19h
basic-tidb-dashboard-exposed   ClusterIP      10.128.145.89    <none>           12333/TCP                        19h
basic-tidb-peer                ClusterIP      None             <none>           10080/TCP                        19h
basic-tikv-peer                ClusterIP      None             <none>           20160/TCP                        19h
```

外部のクライアントからmysqlコマンドを利用してTiDBにアクセスできることを確認します。

:::note alert 
本番利用時にはMySQLの接続に認証が必要となるように設定してください。
:::

```
mysql -h <EXTERNAL-IP> -P 4000 -u root
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 14551
Server version: 5.7.25-TiDB-v6.5.0 TiDB Server (Apache License 2.0) Community Edition, MySQL 5.7 compatible

Copyright (c) 2000, 2023, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> select tidb_version()\G
*************************** 1. row ***************************
tidb_version(): Release Version: v6.5.0
Edition: Community
Git Commit Hash: 706c3fa3c526cdba5b3e9f066b1a568fb96c56e3
Git Branch: heads/refs/tags/v6.5.0
UTC Build Time: 2022-12-27 03:50:44
GoVersion: go1.19.3
Race Enabled: false
TiKV Min Version: 6.2.0-alpha
Check Table Before Drop: false
Store: tikv
1 row in set (0.01 sec)
```


試しにデータベースを作成し、値を入れ、確認をしてみます。


```
mysql> create database linode;
Query OK, 0 rows affected (0.55 sec)

mysql> show Databases;
+--------------------+
| Database           |
+--------------------+
| INFORMATION_SCHEMA |
| METRICS_SCHEMA     |
| PERFORMANCE_SCHEMA |
| linode             |
| mysql              |
| sbtest             |
| test               |
+--------------------+
8 rows in set (0.00 sec)

mysql> use linode;
Database changed
mysql> create table linode(id int unsigned not null auto_increment primary key, v varchar(32));
Query OK, 0 rows affected (0.56 sec)

mysql> INSERT INTO linode VALUES(1,'test1');
Query OK, 1 row affected (0.03 sec)

mysql> select * from linode;
+----+-------+
| id | v     |
+----+-------+
|  1 | test1 |
+----+-------+
1 row in set (0.01 sec)

```

正常にSQLが動作していることを確認できました。


# まとめ

Linode Kubernetes Engine (LKE) を利用することで分散アーキテクチャを採用するTiDBを簡単に構築することができました。
Akamai の Cloud Computing Services のインスタンスには高速なNVMeのストレージが搭載されているため、高い性能を必要とするユースケースにも利用することができます。


# 関連記事

アカマイ・テクノロジーズ合同会社はQiitaでAkamai Cloud Computing Services関連など開発者向けの記事を掲載しております。

https://qiita.com/xenbase/items/52e2956a64cedc772bd9