k8ssandraを試す

公開:2020/11/27
更新:2020/11/27
17 min読了の目安(約15400字TECH技術記事

こちらの記事に取り上げられたK8ssandraをローカルのDockerを使って動かしてみます。

K8ssandra = Cassandra on Kubernetes (k8s)

Apache Cassandraはオープンソースで開発されている分散データベースです。
現在の安定版はv3.11.7、次のメジャーバージョンである4.0のリリースに向けて開発が進められています。

分散データベースということは、複数台のノードが協調して動きます。
通常は、手順書に沿って1台1台インストール・設定を行ったり、Ansibleなどでそれらの手順をある程度自動化したりしてデータベースを構築します。また、データベースだけでなく、監視や運用の仕組みを別途組み込む必要があることも多々あります。

それがKubernetes基盤上に展開できれば、データベース単体だけでなく、運用や監視に必要な機能も、Kubernetesの仕組みを利用して容易にセットアップが行うことができるようになります。

なお発音に関しては、こちらを見ると、"Kate" + "Sandra" みたいな感じとのこと。
私は"ケイトサンドラ"と呼んでいます。

OverviewArchitectureのページを確認すると、Apache Cassandra本体の他に

  • Prometheus - メトリクス収集
  • Grafana - 監視用ダッシュボード
  • cassandra-reaper - リペア(データ同期)スケジューラ

がインストールされるようです。バックアップや復元、CassandraへREST APIやGraphQL経由でのアクセスを可能にするStargateも将来は組み込まれるようです。

今回試す環境

筆者のWindowsマシンで、Docker on Windowsを用いて試します。

WSL2は.wslconfigファイルで以下のように設定しています。

[wsl2]      
memory=12GB 
processors=4

必要なツール

複数のワーカーノードを利用したいので、Kubernetes環境はKindで構築します。
手元のKind環境は

❯ kind version
kind v0.9.0 go1.14.4 windows/amd64

です。

Kindクラスターの構築

クラスター用のyamlファイルを用意します。ワーカーノードを3台作成し、後でブラウザからいろいろなサービスのUIにアクセスするため、ホストからのアクセスをマッピングする設定も行います。

kind-cluster.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
  kubeadmConfigPatches:
  - |
    kind: InitConfiguration
    nodeRegistration:
      kubeletExtraArgs:
        node-labels: "ingress-ready=true"
  extraPortMappings:
  - containerPort: 32080
    hostPort: 80
    protocol: TCP
  - containerPort: 32443
    hostPort: 443
    protocol: TCP
- role: worker
- role: worker
- role: worker

上のyamlをkind-cluster.yamlとして作成し、Kindクラスターを作成します。

❯ kind create cluster --config=kind-cluster.yaml
Creating cluster "kind" ...
 • Ensuring node image (kindest/node:v1.19.1) 🖼  ...
 ✓ Ensuring node image (kindest/node:v1.19.1) 🖼
 • Preparing nodes 📦 📦 📦 📦   ...
 ✓ Preparing nodes 📦 📦 📦 📦 
 • Writing configuration 📜  ...
 ✓ Writing configuration 📜
 • Starting control-plane 🕹️  ...
 ✓ Starting control-plane 🕹️
 • Installing CNI 🔌  ...
 ✓ Installing CNI 🔌
 • Installing StorageClass 💾  ...
 ✓ Installing StorageClass 💾
 • Joining worker nodes 🚜  ...
 ✓ Joining worker nodes 🚜
Set kubectl context to "kind-kind"
You can now use your cluster with:

kubectl cluster-info --context kind-kind

Have a question, bug, or feature request? Let us know! https://kind.sigs.k8s.io/#community 🙂

確認してみましょう。

❯ kubectl get nodes
NAME                 STATUS   ROLES    AGE   VERSION
kind-control-plane   Ready    master   64s   v1.19.1
kind-worker          Ready    <none>   33s   v1.19.1
kind-worker2         Ready    <none>   34s   v1.19.1
kind-worker3         Ready    <none>   34s   v1.19.1

K8ssandraのインストール

Getting startedのページに沿って解説しながら進めていきます。

Helmレポジトリの追加

k8ssandraとtraefikのhelmレポジトリを追加し、更新しておきます。
Traefikは、Kubetenetesの外部からKubetenetes内のサービスにアクセスするためのゲートウェイを提供します。
後ほどGrafanaのダッシュボードなどにアクセスするために使います。

helm repo add k8ssandra https://helm.k8ssandra.io/
helm repo add traefik https://helm.traefik.io/traefik
helm repo update

実行してみます。

❯ helm repo add k8ssandra https://helm.k8ssandra.io/
"k8ssandra" has been added to your repositories

❯ helm repo add traefik https://helm.traefik.io/traefik
"traefik" has been added to your repositories

❯ helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "k8ssandra" chart repository
...Successfully got an update from the "traefik" chart repository
...Successfully got an update from the "stable" chart repository
Update Complete. ⎈ Happy Helming!

k8ssandraのインストールとCassandraクラスターの構築

Helmを使って、まずはk8ssandraクラスター構築に必要なオペレーターやカスタムリソース定義(CRD)を提供するk8ssandra-toolsをインストールします。

k8ssandra-toolsは今のところKubernetestクラスター全体で利用する方法しかないため、本記事では専用の名前空間に展開します。

helm install -n k8ssandra-tools --create-namespace k8ssandra-tools k8ssandra/k8ssandra

実行してみましょう。

❯ helm install -n k8ssandra-tools --create-namespace k8ssandra-tools k8ssandra/k8ssandra 
NAME: k8ssandra-tools
LAST DEPLOYED: Tue Nov 24 09:53:32 2020
NAMESPACE: k8ssandra-tools
STATUS: deployed
REVISION: 1
TEST SUITE: None

❯ kubectl -n k8ssandra-tools get deploy
NAME                                  READY   UP-TO-DATE   AVAILABLE   AGE
cass-operator                         1/1     1            1           33s
k8ssandra-tools-kube-prome-operator   1/1     1            1           33s

DataStaxが開発しているApache Cassandraのオペレーターcass-operatorと、
Prometheusをインストールするオペレーターがインストールされました。

次にCassandraクラスターを構築します。こちらもCassandraクラスター用の名前空間にインストールしましょう。

helm install -n cass --create-namespace k8ssandra-cluster-a k8ssandra/k8ssandra-cluster  

実行します。

❯ helm install -n cass --create-namespace k8ssandra-cluster-a k8ssandra/k8ssandra-cluster  
NAME: k8ssandra-cluster-a
LAST DEPLOYED: Tue Nov 24 10:06:54 2020
NAMESPACE: cass
STATUS: deployed
REVISION: 1
TEST SUITE: None

❯ kubectl -n cass get deploy,sts,job
NAME                                                             READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/grafana-deployment                               1/1     1            1           6m15s
deployment.apps/k8ssandra-cluster-a-grafana-operator-k8ssandra   1/1     1            1           7m
deployment.apps/k8ssandra-cluster-a-reaper-k8ssandra             1/1     1            1           3m7s
deployment.apps/k8ssandra-cluster-a-reaper-operator-k8ssandra    1/1     1            1           7m

NAME                                                                   READY   AGE
statefulset.apps/k8ssandra-dc1-default-sts                             1/1     6m49s
statefulset.apps/prometheus-k8ssandra-cluster-a-prometheus-k8ssandra   1/1     6m59s

NAME                                                    COMPLETIONS   DURATION   AGE
job.batch/k8ssandra-cluster-a-reaper-k8ssandra-schema   1/1           3m28s      6m38s

grafana、cassandra-reaperとともにCassandra(k8ssandra-dc1-default-sts)1ノードが起動しました。

Cassandraにアクセスしてみる

クラスター状態の確認

Cassandraクラスターはカスタムリソース(CassandraDatacenter, cassdc)を使って定義されています。

kubectlを使って状態を確認してみましょう。

❯ kubectl -n cass describe cassdc/dc1
Name:         dc1
Namespace:    cass
Labels:       app.kubernetes.io/instance=k8ssandra-cluster-a
              app.kubernetes.io/managed-by=Helm
              app.kubernetes.io/name=k8ssandra-cluster
              app.kubernetes.io/version=3.11.7
              helm.sh/chart=k8ssandra-cluster-0.11.0
Annotations:  meta.helm.sh/release-name: k8ssandra-cluster-a
              meta.helm.sh/release-namespace: cass
              reaper.cassandra-reaper.io/instance: k8ssandra-cluster-a-reaper-k8ssandra
API Version:  cassandra.datastax.com/v1beta1
Kind:         CassandraDatacenter
...

次に直接コンテナにアクセスして、Cassandraの管理ツールであるnodetoolを使ってみます。

❯ kubectl -n cass get pod 
NAME                                                              READY   STATUS      RESTARTS   AGE
grafana-deployment-568564cd48-zwmtl                               1/1     Running     0          6m37s
k8ssandra-cluster-a-grafana-operator-k8ssandra-5bcb746b8d-8lqdd   1/1     Running     0          8m32s
k8ssandra-cluster-a-reaper-k8ssandra-6cf5b87b8f-vhdpk             1/1     Running     0          4m40s
k8ssandra-cluster-a-reaper-k8ssandra-schema-wnlkr                 0/1     Completed   5          8m11s
k8ssandra-cluster-a-reaper-operator-k8ssandra-55dc486998-wjbjl    1/1     Running     0          8m32s
k8ssandra-dc1-default-sts-0                                       2/2     Running     0          8m22s
prometheus-k8ssandra-cluster-a-prometheus-k8ssandra-0             2/2     Running     1          8m32s

k8ssandra-dc1-default-sts-0がCassandraのポッドです。その中のcassandraコンテナにアクセスします。

❯ kubectl -n cass exec -it k8ssandra-dc1-default-sts-0 -c cassandra -- nodetool status
nodetool: Failed to connect to '127.0.0.1:7199' - SecurityException: 'Authentication failed! Credentials required'.
command terminated with exit code 1

ユーザー認証が必要なようですね。nodetoolはJMX経由でアクセスするため、それらしい設定があるか確認してみましょう。

❯ kubectl -n cass get pod k8ssandra-dc1-default-sts-0 -o yaml
... 
  - env:
    - name: LOCAL_JMX
      value: "no"
...
    env:
    - name: JMX_USERNAME
      valueFrom:
        secretKeyRef:
          key: username
          name: k8ssandra-cluster-a-reaper-secret-k8ssandra
    - name: JMX_PASSWORD
      valueFrom:
        secretKeyRef:
          key: password
          name: k8ssandra-cluster-a-reaper-secret-k8ssandra
...

cassandra-reaperを使ってリモートからリペアを実行するためにこのような設定になっているようです。

JMXユーザー名とパスワードはk8ssandra-cluster-a-reaper-secret-k8ssandraのシークレットにあるので取得します。

❯ kubectl -n cass get secret k8ssandra-cluster-a-reaper-secret-k8ssandra -o jsonpath="{.data.username}" | base64 -d
lcohLJc0cU
❯ kubectl -n cass get secret k8ssandra-cluster-a-reaper-secret-k8ssandra -o jsonpath="{.data.password}" | base64 -d
DKHLYz3xjX
❯ kubectl -n cass exec -it k8ssandra-dc1-default-sts-0 -c cassandra -- nodetool -u lcohLJc0cU -pw DKHLYz3xjX status
Datacenter: dc1
===============
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
--  Address     Load       Owns (effective)  Host ID                               Token                                    Rack
UN  10.244.1.6  153.69 KiB  100.0%            f017222c-6e77-4362-a4d4-42a4f3872b0b  5267804669664362995                      default

1台のノードのクラスターが構築されていることが確認できました。

cqlshでのアクセス

CassandraにはコマンドラインでCQL(Cassandra Query Language)が実行できるcqlshがついています。これを使ってデータを取得してみます。

❯ kubectl -n cass exec -it k8ssandra-dc1-default-sts-0 -c cassandra -- cqlsh
Connected to k8ssandra at 127.0.0.1:9042.
[cqlsh 5.0.1 | Cassandra 3.11.7 | CQL spec 3.4.4 | Native protocol v4]
Use HELP for help.
cqlsh> SELECT cluster_name FROM system.local;

 cluster_name
--------------
    k8ssandra

(1 rows)

こちらはユーザー認証はかかってないようですね。このクラスターのクラスター名はk8ssandraのようです。

Grafanaおよびcassandra-reaperへのアクセス

Cassaandraクラスターと共にGrafanaやcassandra-reaperが構築されたので、それらにアクセスしてみましょう。このページを参考にします。

Traefik Ingressコントローラーの設定

外部からKubernetes内部のサービスにアクセスするために、IngressコントローラーとしてTraefikを利用します。k8ssandraと同じくhelmコマンドでインストールしますが、Kind環境で動かせるようインストールのカスタマイズを行います。kindクラスターを構築した際の設定と以下の設定を行うことで、http://localhost/ にアクセスした際にTraefikにリクエストが渡るようにします。

traefik.values.yaml
ports:
  web:
    nodePort: 32080
  websecure:
    nodePort: 32443
service:
  type: NodePort

上のyamlをtraefik.values.yamlとしてファイルに保存し、helmでのインストール時に指定します。

❯ helm install -n cass traefik traefik/traefik -f traefik.values.yaml
NAME: traefik
LAST DEPLOYED: Tue Nov 24 16:14:41 2020
NAMESPACE: cass
STATUS: deployed
REVISION: 1
TEST SUITE: None

grafanaおよびcassandra-reaperへのルートを追加します。以下の設定では、ホスト名がgrafana.localhostの場合はgrafana用のサービスへ、reaper.localhostの場合はcassandra-reaper用のサービスへと振り分けます。

ingress.yaml
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: traefik-k8ssandra-route
spec:
  entryPoints:
    - web
  routes:
    - match: Host(`grafana.localhost`)
      kind: Rule
      services:
      - name: grafana-service
        port: 3000
    - match: Host(`reaper.localhost`)
      kind: Rule
      services:
      - name: k8ssandra-cluster-a-reaper-k8ssandra-reaper-service
        port: 8080

上のyamlをingress.yamlとしてファイルに保存し、設定を適用します。

❯ kubectl -n cass apply -f ingress.yaml 
ingressroute.traefik.containo.us/traefik-k8ssandra-route created

Grafanaへのアクセス

http://grafana.localhost にアクセスするとGrafanaのログイン画面が表示されるはずです。

ユーザー名とパスワードはシークレットに登録されています。

❯ kubectl -n cass get secret grafana-admin-credentials -o jsonpath="{.data.GF_SECURITY_ADMIN_USER}" | base64 -d
admin
❯ kubectl -n cass get secret grafana-admin-credentials -o jsonpath="{.data.GF_SECURITY_ADMIN_PASSWORD}" | base64 -d
secret

左側のメニューから Dashboard > Manageと選択すると、あらかじめ設定されたダッシュボードを表示することができます。

Grafanaダッシュボード

cassandra-reaperへのアクセス

Cassandraのリペアスケジューラーであるcassandra-reaperには以下のURLでアクセスできます。

すでに構築したクラスターが登録されていますね。ここから、Web UIを用いてリペアをスケジュールできます。

cassandra-reaper web UI

スケールアウト

デフォルトでは1台のクラスターが構築されるため、スケールアウトして3台構成のクラスターにしてみましょう。

helm upgrade コマンドを用いて新しいノード数に変更するだけでスケールアウトします。

❯ helm -n cass upgrade k8ssandra-cluster-a k8ssandra/k8ssandra-cluster --set size=3
Release "k8ssandra-cluster-a" has been upgraded. Happy Helming!
NAME: k8ssandra-cluster-a
LAST DEPLOYED: Tue Nov 24 18:35:18 2020
NAMESPACE: cass
STATUS: deployed
REVISION: 2
TEST SUITE: None

❯ kubectl -n cass get pod
NAME                                                              READY   STATUS      RESTARTS   AGE
grafana-deployment-568564cd48-8kdw9                               1/1     Running     0          88m
k8ssandra-cluster-a-grafana-operator-k8ssandra-5bcb746b8d-qz95g   1/1     Running     0          90m
k8ssandra-cluster-a-reaper-k8ssandra-6cf5b87b8f-78dtg             1/1     Running     0          86m
k8ssandra-cluster-a-reaper-k8ssandra-schema-48pfq                 0/1     Completed   5          90m
k8ssandra-cluster-a-reaper-operator-k8ssandra-55dc486998-855sj    1/1     Running     0          90m
k8ssandra-dc1-default-sts-0                                       2/2     Running     0          90m
k8ssandra-dc1-default-sts-1                                       2/2     Running     0          41m
k8ssandra-dc1-default-sts-2                                       2/2     Running     0          41m
prometheus-k8ssandra-cluster-a-prometheus-k8ssandra-0             2/2     Running     1          90m
traefik-77fdb5c487-ghtfd

Cassandraのポッドk8ssandra-dc1-default-sts-1k8ssandra-dc1-default-sts-2が追加されていますね。

Grafana上でも3ノードのステータスが表示されています。

ノードステータス

また、nodetool statusを確認すると

# kubectl -n cass exec -it k8ssandra-dc1-default-sts-0 -c cassandra -- nodetool -u lcohLJc0cU -pw DKHLYz3xjX status
Datacenter: dc1
===============
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
--  Address      Load       Tokens       Owns (effective)  Host ID                               Rack
UN  10.244.1.6   177.08 KiB  1            16.0%             f017222c-6e77-4362-a4d4-42a4f3872b0b  default
UN  10.244.2.9   92.55 KiB  1            38.1%             ca96d104-458d-4a29-ae3d-9ac7a24e7015  default
UN  10.244.3.10  102.5 KiB  1            45.9%             46de0ae5-7745-4291-a542-badeda88f0aa  default

となり3台構成のクラスターに確かにスケールアウトしました。ただ、トークンの数が1で、トークンがランダムに割り振られているため、非常に偏りがありますね。このあたりはCassandraの設定ファイルcassandra.yamlで設定していくのですがそのあたりのカスタマイズがどのようにできるかは今後調べていきたいと思います。

まとめ

まだ登場したばかりなので、細かいCassandraクラスター自身の設定がどのようにできるかは気になりますが、k8cassandraを使うとkubernetes上でCassandraクラスターを運用・監視まで含めて簡単に行えるようです。

今後もバックアップや復元への対応などさらなる周辺技術を組み合わせて進化していくことで、本番環境でも使えるようになってほしいものです。