AlibabaCloudでKubernetesを使用してCassandraをセットアップ

この記事では、**Alibaba Cloud**上の**Kubernetes**で**Cassandra**をセットアップする方法を説明します。

[Alibaba Cloud Community Blog](https://www.alibabacloud.com/blog?spm=a2c65.11461447.0.0.2d321fc0YfAloD)の著者であるAlexによるものです。

Kubernetesシリーズでは、コンテナ化、アプリケーションのライフサイクル管理、マルチコンテナイメージのデプロイ、マイクロサービスを取り上げ、いくつかの関連するプラクティスについて説明してきましたが、このチュートリアルでは、ステートフルサービスに関わるさらなるコンセプトを探ってみましょう。

データベース・クラスターのようなステートフルなワークロードでは、Replica Setを使用しないため、別のアプローチが必要になります。[StatefulSet](https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/?spm=a2c65.11461447.0.0.2d321fc0YfAloD)を使用すると、データベースなどの従来のワークロードを展開、管理、およびスケーリングすることができます。StatefulSetを使用することで、以下のことが保証され、永続性とステートフルの両方を備えた分散システムがパワーアップします。

- 一意の識別子によるポッドのインデックス化
- ポッドのシステム的な作成
- 持続的なネットワークアイデンティティ

ステートフルセットは、サービスを効果的に実行するために、ポッドの順序と一意性を保証します。通常、利用可能な知識の状態に依存するアプリケーションがスムーズに実行されるように、ポッドの開始時およびその結果としての再起動時に状態が維持されます。

実例としては、アプリケーションやクライアントがそのようなデータにアクセスするデータベースやキーバリューストアなど、サーバー内の永続的なディスクストレージにデータを保存することが挙げられます。このチュートリアルでは、Cassandraデータベース・アプリケーションを展開して、このコンセプトを探ります。

このチュートリアルの要件は以下の通りです。

- Alibaba Cloud上のKubernetesクラスタ
- [Docker Hub](https://hub.docker.com/?spm=a2c65.11461447.0.0.2d321fc0YfAloD)アカウント
- リポジトリからのCassandraデータベースイメージ

#チュートリアルの目的
このチュートリアルは、以下の点を明確に示すことで、Kubernetesの概念を理解するのに役立ちます。

- DockerイメージからCassandraサービスを作成する方法
- サービスで実行するポッドを作成する方法
- 検証、変更、削除を含むステートフルセットの原則を適用する方法

#はじめに
これまでの連載では、ポッド、サービス、ReplicaSetsの基本を説明するとともに、3ノードのクラスターにおけるKubeadmとKubectlの設定と展開について詳しく説明しました。

前回のチュートリアルでは、3台のサーバーを使ってKubernetesクラスターを構成しましたが、今回の記事では、Cassandra SeedProviderを採用し、StatefulSetsを使ってクラスター内に配置されたCassandraノードを検出します。

以下のコマンドを実行します。

```
sudo nano /etc
```

以下のリンクで提供されているサンプルファイルを使用して、デプロイメントを可能にします。

- [cassandra-service.yaml](https://kubernetes.io/examples/application/cassandra/cassandra-service.yaml?spm=a2c65.11461447.0.0.2d321fc0YfAloD&file=cassandra-service.yaml)
- [cassandra-statefulset.yaml](https://kubernetes.io/examples/application/cassandra/cassandra-statefulset.yaml?spm=a2c65.11461447.0.0.2d321fc0YfAloD&file=cassandra-statefulset.yaml)
次に、上記のダウンロードしたファイルを格納するディレクトリを作成します。


```
cd ~
mkdir application
cd application
mkdir cassandra
cd cassandra
wget https://kubernetes.io/examples/application/cassandra/cassandra-service.yaml
wget https://kubernetes.io/examples/application/cassandra/cassandra-statefulset.yaml
```

#Cassandraのヘッドレスサービス
Kubernetesは、通常のサービスとヘッドレスサービスの両方をサポートしています。この2種類のサービスの主な違いは、通常のサービスはサービスIP上でポッドをロードし、舞台裏でDNSエントリを管理します。一方、ヘッドレスサービスはサービスIPを持たないため、通常のサービスと比較してロードバランシングを行いません。ヘッドレス・サービスではポッドを指すレコードを使用しますが、これはCassandraがロードバランシングを必要としないため、ノードがクライアントに直接接続されることでうまく機能します。クライアントは、`cassandra.data.svc.cluster.local`に接続します。選択したイメージは、次のDockerイメージの[リンク](https://console.cloud.google.com/gcr/images/google-samples/GLOBAL/cassandra@sha256:7a3d20afa0a46ed073a5c587b4f37e21fa860e83c60b9c42fec1e1e739d64007/details?spm=a2c65.11461447.0.0.2d321fc0YfAloD&tab=info)にあります。

Cassandraヘッドレスサービスは、Cassandraインスタンスをホストするポッドを一覧表示します。最初のステップは、DNSを使用してクラスタ内のCassandraポッドとクライアントをリンクするサービスを作成することです。次のコマンドを実行して、ファイルのダウンロードが正常に行われたことを確認します。


```
sudo nano application/cassandra/cassandra-service.yaml
```

次のスニペットは、上記コマンドの出力を示しています。



```
application/cassandra/cassandra-service.yaml 
apiVersion: v1
kind: Service
metadata:
  labels:
    app: cassandra
  name: cassandra
  namespace: data
spec:
  clusterIP: None
  ports:
  - port: 9042
  selector:
    app: cassandra
```

ファイルのダウンロードが完了したら、以下のコマンドを実行して、ファイルからCassandraサービスを作成します。

```
kubectl apply -f /home/flasky/application/cassandra/cassandra-service.yaml
```


クラスタが正しくインストールされていない場合は、以下のエラーが発生します。

```
error: unable to recognize "https://k8s.io/examples/application/cassandra/cassandra-service.yaml": Get http://localhost:8080/api?timeout=32s: dial tcp [::1]:8080: connect: connection refused
```

このエラーを修正するには、以下のcalicoネットワークコマンドを実行します。
```
sudo kubeadm init --pod-network-cidr=192.168.0.0/16
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
```

再度、以下のコマンドを実行します。

```
kubectl apply -f /home/flasky/application/cassandra/cassandra-service.yaml
```

テストして動作を確認してみましょう。



```
kubectl get svc cassandra
```

次のスニペットは、上記のコマンドの出力を示しています。

```
name type cluster-ip external-ip port(s) age
cassandra ClusterIP None <none> 9042/TCP 57s
```

#Cassandra Ringの作成
それでは、3つのポッドで構成されるCassandra Ringを作成してみましょう。まず、以下のコマンドを実行して、2番目にダウンロードしたファイルを見てみましょう。

```
sudo nano application/cassandra/cassandra-statefulset.yaml
```

このファイルの中で、以下のようにイメージ・リンクをDockerイメージ・リンクに置き換えます。

```
application/cassandra/cassandra-statefulset.yaml  

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: cassandra
  labels:
    app: cassandra
spec:
  serviceName: cassandra
  replicas: 3
  selector:
    matchLabels:
      app: cassandra
  template:
    metadata:
      labels:
        app: cassandra
    spec:
      terminationGracePeriodSeconds: 1800
      containers:
      - name: cassandra
        image: gcr.io/google-samples/cassandra@sha256:7a3d20afa0a46ed073a5c587b4f37e21fa860e83c60b9c42fec1e1e739d64007
        imagePullPolicy: Always
        ports:
        - containerPort: 7000
          name: intra-node
        - containerPort: 7001
          name: tls-intra-node
        - containerPort: 7199
          name: jmx
        - containerPort: 9042
          name: cql
        resources:
          limits:
            cpu: "500m"
            memory: 1Gi
          requests:
            cpu: "500m"
            memory: 1Gi
        securityContext:
          capabilities:
            add:
              - IPC_LOCK
        lifecycle:
          preStop:
            exec:
              command: 
              - /bin/sh
              - -c
              - nodetool drain
        env:
          - name: MAX_HEAP_SIZE
            value: 512M
          - name: HEAP_NEWSIZE
            value: 100M
          - name: CASSANDRA_SEEDS
            value: "cassandra-0.cassandra.default.svc.cluster.local"
          - name: CASSANDRA_CLUSTER_NAME
            value: "K8Demo"
          - name: CASSANDRA_DC
            value: "DC1-K8Demo"
          - name: CASSANDRA_RACK
            value: "Rack1-K8Demo"
          - name: POD_IP
            valueFrom:
              fieldRef:
                fieldPath: status.podIP
        readinessProbe:
          exec:
            command:
            - /bin/bash
            - -c
            - /ready-probe.sh
          initialDelaySeconds: 15
          timeoutSeconds: 5
        volumeMounts:
        - name: cassandra-data
          mountPath: /cassandra_data
  volumeClaimTemplates:
  - metadata:
      name: cassandra-data
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: fast
      resources:
        requests:
          storage: 1Gi
---
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: fast
provisioner: k8s.io/minikube-hostpath
parameters:
  type: pd-ssd
```

次に、以下のコマンドを実行して、ファイルからStatefulSetを作成します。

```
kubectl apply -f /home/flasky/application/cassandra/cassandra-statefulset.yaml
```

注：以下のコマンドを実行して、ダウンロードしたファイルの場所を確認してください。

```
pwd
```

エラーが発生しないことが理想ですが、万が一エラーが発生した場合は、Cassandraヘッドレス・サービスの作成に関連する前のセクションとその解決方法を確認してください。

以下に示すコマンドを使用して、デプロイを検証します。

```
kubectl get statefulset cassandra
```

次のスニペットは、上記のコマンドの出力を示しています。

```
NAME        DESIRED   CURRENT   AGE
cassandra   3         0         57s
```

ステートフルセットの作成時に指定した3つのレプリカが稼働していることを確認します。次のコマンドを実行して、同じことを確認します。



```
kubectl get pods -l="app=cassandra”
```

次のスニペットは、上記のコマンドの出力を示しています。

```
NAME          READY     STATUS    RESTARTS   AGE
cassandra-0   1/1       Running   0          6m
cassandra-1   1/1       Running   0          3m
cassandra-2   1/1       Running   0          45s
```

10分待って、1回目で3つのポッドが反映されない場合に備えて、コマンドを再度実行します。以下のコマンドを実行して、アプリケーションの状態を確認します。

```
kubectl exec -it cassandra-0 -- nodetool status
```

次のスニペットは、上記のコマンドの出力を示しています。



```
Datacenter: DC1
======================
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
--  Address         Load           Tokens    Owns        Host ID   Rack
192.168.0.4        98.77 KiB    32        74.0%        id        Rack1
192.168.0.4        91.02 KiB    32        58.8%        id        Rack1
192.168.0.4        97.56 KiB    32        67.1%        id        Rack1
```

#Kubectlによるスケーリングのテスト
それでは、デプロイされたStatefulSetのスケーラビリティをテストしてみましょう。以下のコマンドを実行して、StatefulSetを探します。

```
kubectl get statefulsets <stateful-set-name>
```

前述の通り、今回の記事ではStatefulSetには3つのレプリカが存在します。しかし、スケーリングでは以下のコマンドで同じように変更することができます。

```
kubectl scale statefulsets <stateful-set-name> --replicas=<10> 
```

#StatefulSetsの削除
Kubernetesでは、kubectl deleteコマンドを使ってStatefulSetsを削除することができます。このコマンドには、以下のようにステートフルセットのファイルまたは名前を指定する引数が必要です。

```
kubectl delete -f <Cassandra-statefulset.yaml>
kubectl delete statefulsets <cassandra>
```

`kubectl delete`コマンドでヘッドレス・サービスを削除します。

```
kubectl delete service <cassandra-service.yaml>
```

StatefulSetsの削除後は、レプリカ・セットがゼロに設定されるため、ポッドが削除されます。ただし、データの完全な損失を避けるために、関連する永続的なボリュームを排除しないような方法でStatefulSetを削除することが重要です。

とはいえ、StatefulSetを完全に削除するには、以下のコマンドを実行します。

```
grace=$(kubectl get pods <stateful-set-pod> --template '{{.spec.terminationGracePeriodSeconds}}')
kubectl delete statefulset -l app=cassandra
sleep $grace
kubectl delete pvc -l app=Cassandra
```

引数の「app」を特定のアプリに置き換えることを確認します。この記事では、Cassandraです。



#Cascade削除
KubernetesのCascade削除の概念は、長期間にわたって望ましくない状態にあるポッドを処理することができます。これにより、サーバーで手動でポッドを削除する必要がなくなります。Cascadeフラグまたは引数は、ポッドではなくステートフルセットのみを削除します。以下のようにdeleteコマンドに含めます。

```
kubectl delete -f <cassandra-statefulset.yaml> --cascade=false
```

前述のコマンドでStatefulSetが削除されても、3つまたは4つのレプリカはそのままで、cassandraというラベルが残っています。以下のコマンドを実行して、それらも削除します。

```
kubectl delete pods -l app=myapp
```

#StatefulSetファイルへの変更
`kubectl edit`コマンドを使うと、StatefulSetファイルに直接変更を加えることができ、変更内容を再適用する必要がありません。



```
kubectl edit statefulset cassandra
```

上記のコマンドを実行すると、`StatefulSet`ファイルがエディタで開かれます。ここで、例えば、レプリカの数を10に変更するための以下のコードを考えてみます。

```
apiVersion: apps/v1 
kind: StatefulSet
metadata:
  creationTimestamp: 2019-03-29T15:33:17Z
  generation: 1
  labels:
  app: cassandra
  name: cassandra
  namespace: default
  resourceVersion: "323"
  selfLink: /apis/apps/v1/namespaces/default/statefulsets/cassandra
  uid: 7a209352-0976-15t6-e907-437j940u864
spec:
  replicas: 10
```

変更内容を保存し、エディタを終了します。以下のコマンドを実行して、変更内容を検証します。

```
kubectl get statefulset cassandra
```

次のスニペットは、前のコマンドの出力を反映しています。

```
NAME        DESIRED   CURRENT   AGE
cassandra   4         4         3m
```

明らかに、変更が有効になっています。



#結論
この記事は、Kubernetes StatefulSetを使用して高可用性のCassandraリングを展開する方法を理解するのに役立ちます。サービスをスケールアップおよびスケールダウンし、KubernetesアプリケーションからStatefulSetsにアクセスする方法を示しています。さらに、Kubernetes上で動作する高可用性アプリケーションをAlibaba Cloudで展開する方法についても説明しています。

Alibaba Cloudのアカウントをお持ちではないですか？アカウントにサインアップすると、最大1200ドル相当の[40以上の製品を無料でお試し](https://account.alibabacloud.com/register/intl_register.htm?spm=a2c65.11461447.0.0.2d321fc0YfAloD)いただけます。[Get Started with Alibaba Cloud](https://account.alibabacloud.com/register/intl_register.htm?spm=a2c65.11461447.0.0.2d321fc0YfAloD)で詳細をご覧ください。

*本ブログは英語版からの翻訳です。オリジナルは[こちら](https://www.alibabacloud.com/blog/kubernetes-stateful-services-on-alibaba-cloud_595774)からご確認いただけます。一部機械翻訳を使用しております。翻訳の間違いがありましたら、ご指摘いただけると幸いです。*

*アリババクラウドは日本に２つのデータセンターを有し、世界で60を超えるアベラビリティーゾーンを有するアジア太平洋地域No.1(2019ガートナー)のクラウドインフラ事業者です。
アリババクラウドの詳細は、こちらからご覧ください。
[アリババクラウドジャパン公式ページ](https://www.alibabacloud.com/ja)*