👀

ラズパイ4でK8ssandra動かしてみた

2021/11/03に公開

はじめに

以前構築したラズパイK8sクラスタが自宅の片隅で文鎮と化していたので、K8ssandra を試してみることにしました。
仕事で DSE を利用していることもあり、前から気になっていたんですよね。

K8ssandraとは

こちらに記載ありました。
https://k8ssandra.io/about/
CassandraがKubernetes上で実行できるぐらいに思っておけばよいですかね。

個人的にはずっとなんて呼ぶんだろうと気になっていましたが、それもしっかり記載されていました。

Any way you want! Many of the team members pronounce it as “Kate” + “Sandra”.

なんでもいいよが一番困る気がしますが、とりあえず「ケイトサンドラ」と呼ぶことにしました。

動作環境

Kubernetes(Rasberry Pi4): v1.19.2
Helm: v3.3.0
K8ssandra:v1.3.0
Cassandra:3.11.10

K8s と Helm は既に導入済みのものを利用しており、バージョンなどは特に気にしていません。

エミュレータの導入

いきなり helm install でデプロイしたいところですが、今回ラズパイ4で構築した K8s クラスタを使っているの少し下準備が必要です。

K8ssandra で使われているイメージが、ARM 対応してるものとそうでないものがあるので、そのままでは動かすことができません。
今回は Qemu というオープンソースのプロセッサエミュレータを使うことにします。

debパッケージはこちらからダウンロードしました。
http://ftp.jp.debian.org/debian/pool/main/q/qemu/

$ wget http://ftp.jp.debian.org/debian/pool/main/q/qemu/qemu-user-static_6.1+dfsg-6_arm64.deb
$ sudo dpkg -i qemu-user-static_6.1+dfsg-6_arm64.deb
$ sudo apt install qemu-user-static
$ sudo apt install binfmt-support
$ apt list --installed | grep -e qemu-user-static -e binfmt-support
binfmt-support/focal,now 2.2.0-2 arm64 [installed]
qemu-user-static/now 1:6.1+dfsg-6 arm64 [installed,local]
$ reboot -h now

再起動後にバージョンを確認して、指定したバージョンが入っていれば OK です。
ついでに、x86 の ubuntu イメージを実行して確認してみます。

$ qemu-x86_64-static --version
qemu-x86_64 version 6.1.0 (Debian 1:6.1+dfsg-6)
Copyright (c) 2003-2021 Fabrice Bellard and the QEMU Project developers
$ docker run --rm -it bitnami/ubuntu-base-buildpack:latest /bin/bash -c 'uname -m'
x86_64

上記の操作を Master, Worker 含め全てのノードで実施しました。

K8ssandraデプロイ

dc1 というデータセンターに、バージョン 4.0.1 の Cassandra ノードを1つ持つ K8ssandra クラスタを作成します。

基本的にはこちらを参考にしています。
https://k8ssandra.io/get-started/

あとは以下の記事も参考にさせていただきました。
https://zenn.dev/t_ume/articles/e62b1e837e5cd2
似たような部分も多いです。もしかしたらこちらの記事の方が参考になるかもしれません。


Helm のリポジトリを登録します。
K8ssandra 1.0からは、Stable と Next の2つが公開されています。特に理由はないですが、今回はNextを使ってみます。

詳しくはこちらをご確認ください。
https://k8ssandra.io/blog/announcements/release/k8ssandra-1-0-stable-release-and-whats-next/

$ helm repo add k8ssandra https://helm.k8ssandra.io/next
$ helm repo list
NAME                           	URL
kong                           	https://charts.konghq.com
jenkins                        	https://charts.jenkins.io
nfs-subdir-external-provisioner	https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/
k8ssandra                      	https://helm.k8ssandra.io/next
grafana                        	https://grafana.github.io/helm-charts
metallb                        	https://metallb.github.io/metallb

一部設定を変更したいので、Helm の Charts もダウンロードしておきます。

$ helm pull k8ssandra/k8ssandra --untar

values.yaml の以下を書き換えて利用します。

$ cd k8ssandra
$ diff -u values.org.yaml  values.yaml
--- values.org.yaml	2021-11-03 18:36:15.000000000 +0900
+++ values.yaml	2021-11-03 17:04:36.000000000 +0900
@@ -123,7 +123,7 @@
     # underlying cassandra pods. Depending on your Kubernetes distribution this
     # may be named "standard", "hostpath", or "localpath". Run `kubectl get
     # storageclass` to identify what is available in your environment.
-    storageClass: standard
+    storageClass: nfs
     # -- Size of the provisioned persistent volume per node. It is recommended
     # to keep the total amount of data per node to approximately 1 TB. With room
     # for compactions this value should max out at ~2 TB. This recommendation is
@@ -177,9 +177,9 @@
   # Options are commented out for reference. Note that k8ssandra does not
   # automatically apply default values for heap size. It instead defers to
   # Cassandra's out of box defaults.
-  heap: {}
-  #size:
-  #newGenSize:
+  heap:
+    size: 1G
+    newGenSize: 1G

   # -- Optional cluster-level garbage collection configuration. It can be overridden at
   # the datacenter level.
@@ -229,7 +229,13 @@
   # -- Resource requests for each Cassandra pod. See
   # https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
   # for background on managing resources.
-  resources: {}
+  resources:
+    requests:
+      cpu: 1000m
+      memory: 2Gi
+    limits:
+      cpu: 1000m
+      memory: 2Gi
   # Tolerations to apply to the Cassandra pods. See
   # https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ for background.
   tolerations: []

storageClass は任意のものを指定してください。今回は nfs-subdir-external-provisioner を使っています。

helm install をしてみます。

$ kubectl create ns cassandra
namespace/cassandra created
$ helm install -n cassandra -f values.yaml k8ssandra k8ssandra/k8ssandra

なかなか k8ssandra-dc1-default-sts-0 が立ち上がらないので調べてみるとinit containerが失敗していたようで、原因は放置していた Pod たちでした。
クラスタ全体で見たら CPU/MEM 供に 40% 程度だったのでスルーしていたのですが、Node 単位で確認すると、ワーカーノードの1つが 90% 近くになっていました。

もろもろ整理して再度実行してみました。

$ helm upgrade -n cassandra -f values.yaml k8ssandra k8ssandra/k8ssandra

30分ぐらい待っても Stargate が起動しないので log 見てみたところ、 Service の名前解決ができていないようです。

$ kubectl -n cassandra logs k8ssandra-dc1-stargate-7847f6bfb9-prprt -c wait-for-cassandra

Server:        10.96.0.10             
Address:    10.96.0.10:53
** server can't find k8ssandra-seed-service.cassandra.svc.cluster.local: NXDOMAIN 
** server can't find k8ssandra-seed-service.cassandra.svc.cluster.local: NXDOMAIN 
kubectl -n cassandra run -it --rm=true busybox --image=yauritux/busybox-curl --restart=Never
/home # nslookup k8ssandra-seed-service
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local
nslookup: can't resolve 'k8ssandra-seed-service'

いろいろ調べてみたけど解決できず、途方に暮れていたら勝手に起動していました。
ラズパイで動かしていたので、起動に時間がかかった感じですかね。エミュレータ使っているのも影響ある気がします。
そこら辺はまた今後調べてみようと思います。
ちなみに起動したのは実行してから45分ほど経ってからでした。

$ kubectl -n cassandra logs k8ssandra-dc1-stargate-7847f6bfb9-prprt -c wait-for-cassandra -f

Server:   10.96.0.10
Address:  10.96.0.10:53

** server can't find k8ssandra-seed-service.cassandra.svc.cluster.local: NXDOMAIN

** server can't find k8ssandra-seed-service.cassandra.svc.cluster.local: NXDOMAIN

Server:   10.96.0.10
Address:  10.96.0.10:53

** server can't find k8ssandra-seed-service.cassandra.svc.cluster.local: NXDOMAIN

** server can't find k8ssandra-seed-service.cassandra.svc.cluster.local: NXDOMAIN
Server:   10.96.0.10
Address:  10.96.0.10:53

Name: k8ssandra-seed-service.cassandra.svc.cluster.local
Address: 10.244.1.189

Cassandra is ready. Starting Stargate...

デプロイ後は以下のようになっていました。

$ kubectl -n cassandra get po, svc
NAME                                                      READY   STATUS    RESTARTS   AGE
pod/k8ssandra-cass-operator-6ffc65b9f6-q6vc9              1/1     Running   0          110m
pod/k8ssandra-dc1-default-sts-0                           2/2     Running   0          109m
pod/k8ssandra-dc1-stargate-7847f6bfb9-prprt               1/1     Running   0          110m
pod/k8ssandra-grafana-74db456fdb-q89dz                    2/2     Running   0          110m
pod/k8ssandra-kube-prometheus-operator-8487f5df79-4v86v   1/1     Running   0          110m
pod/k8ssandra-reaper-operator-766696f6d4-xq884            1/1     Running   0          110m
pod/prometheus-k8ssandra-kube-prometheus-prometheus-0     2/2     Running   1          110m

NAME                                           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                                                 AGE
service/cass-operator-metrics                  ClusterIP   10.99.180.101   <none>        8383/TCP,8686/TCP                                       109m
service/k8ssandra-dc1-all-pods-service         ClusterIP   None            <none>        9042/TCP,8080/TCP,9103/TCP                              109m
service/k8ssandra-dc1-service                  ClusterIP   None            <none>        9042/TCP,9142/TCP,8080/TCP,9103/TCP,9160/TCP            109m
service/k8ssandra-dc1-stargate-service         ClusterIP   10.108.191.46   <none>        8080/TCP,8081/TCP,8082/TCP,8084/TCP,8085/TCP,9042/TCP   110m
service/k8ssandra-grafana                      ClusterIP   10.99.62.237    <none>        80/TCP                                                  110m
service/k8ssandra-kube-prometheus-operator     ClusterIP   10.109.162.74   <none>        443/TCP                                                 110m
service/k8ssandra-kube-prometheus-prometheus   ClusterIP   10.96.223.229   <none>        9090/TCP                                                110m
service/k8ssandra-seed-service                 ClusterIP   None            <none>        <none>                                                  109m
service/prometheus-operated                    ClusterIP   None            <none>        9090/TCP                                                110m

K8ssandra の資格情報を取得

Cassandra ユーティリティにアクセスし、Stargate アクセストークンを生成するなどの操作を行うには、K8ssandra のスーパーユーザー名とパスワードが必要です。
Secret から情報を取得し、デコードします。

$ kubectl -n cassandra get secret k8ssandra-superuser -o jsonpath='{.data.username}{"\n"}{.data.password}' | xargs -I{} sh -c "echo {} | base64 -d; echo"
k8ssandra-superuser
18yKg1APBIiR1AHzXB0D

Cassandra へのアクセス

公式のクイックスタートドキュメントには、K8ssandra 開発者向けと K8ssandra 管理者向けの2種類がありましたが、今回は K8ssandra 開発者向けを試してみます。

外部からCassanndraクラスタにアクセスするために、まずは k8ssandra-dc1-stargate-service に対してポートフォワーディングをおこないます。

kubectl -n cassandra port-forward svc/k8ssandra-dc1-stargate-service 8080 8081 8082 9042 &
$
Forwarding from 127.0.0.1:8080 -> 8080                                         
Forwarding from [::1]:8080 -> 8080
Forwarding from 127.0.0.1:8081 -> 8081
Forwarding from [::1]:8081 -> 8081
Forwarding from 127.0.0.1:8082 -> 8082
Forwarding from [::1]:8082 -> 8082
Forwarding from 127.0.0.1:9042 -> 9042
Forwarding from [::1]:9042 -> 9042

StargateAPIを使用してCassandraにアクセス

Stargate は、Cassandra に保存されているデータにCRUDアクセスするための Document、REST 、GraphQL APIなどを提供してくれるようです。
詳しくはこちらにあります。
https://stargate.io/docs/stargate/1.0/quickstart/quickstart.html

トークンを取得します。

$ curl -L -X POST 'http://localhost:8081/v1/auth' -H 'Content-Type: application/json' --data-raw '{"username": "k8ssandra-superuser", "password": "18yKg1APBIiR1AHzXB0D"}'
Handling connection for 8081
{"authToken":"0aa12133-93f9-477f-bbc8-dcca177c6c6b"}⏎

次に Keyspace の取得を試してみます。
以下を参考にしてます。
https://stargate.io/docs/stargate/1.0/quickstart/quick_start-rest.html

$ set AUTH_TOKEN 0aa12133-93f9-477f-bbc8-dcca177c6c6b
$ curl -sL -X GET 'http://localhost:8082/v2/schemas/keyspaces' -H "X-Cassandra-Token: $AUTH_TOKEN" -H "Content-Type: application/json" -H "Accept: application/json" | jq              
Handling connection for 8082
{
  "data": [
    {
      "name": "system_schema"
    },
    {
      "name": "system"
    },
    {
      "name": "system_distributed",
      "datacenters": [
        {
          "name": "dc1",
          "replicas": 1
        }
      ]
    },
    {
      "name": "system_traces",
      "datacenters": [
        {
          "name": "dc1",
          "replicas": 1
        }
      ]
    },
    {
      "name": "system_auth",
      "datacenters": [
        {
          "name": "dc1",
          "replicas": 1
        }
      ]
    },
    {
      "name": "stargate_system"
    },
    {
      "name": "data_endpoint_auth"
    }
  ]
}

きちんと Keyspace が取ってこれてますね。
次は Keyspace を作成してみます。

$ curl -sL -X POST 'localhost:8082/v2/schemas/keyspaces' -H "X-Cassandra-Token: $AUTH_TOKEN" -H 'Content-Type: application/json' -d '{"name": "my_k8ssandra_keyspace"}'                                                       
Handling connection for 8082
{"name":"my_k8ssandra_keyspace"}⏎
$ curl -sL -X GET 'localhost:8082/v2/schemas/keyspaces' -H "X-Cassandra-Token: $AUTH_TOKEN" -H "Content-Type: application/json" -H "Accept: application/json" | jq 
Handling connection for 8082
{
  "data": [
    {
      "name": "system_schema"
    },
    {
      "name": "system"
    },
    {
      "name": "system_distributed",
      "datacenters": [
        {
          "name": "dc1",
          "replicas": 1
        }
      ]
    },
    {
      "name": "system_traces",
      "datacenters": [
        {
          "name": "dc1",
          "replicas": 1
        }
      ]
    },
    {
      "name": "system_auth",
      "datacenters": [
        {
          "name": "dc1",
          "replicas": 1
        }
      ]
    },
    {
      "name": "stargate_system"
    },
    {
      "name": "data_endpoint_auth"
    },
    {
      "name": "my_k8ssandra_keyspace"
    }
  ]
}

my_k8ssandra_keyspace が追加されていることが確認できました。

CQLSHを使用してCassandraにアクセスする

次はCQL使ってみます。
自分のMacにCQLクライアントは入ってなかったので、コンテナに入って試してみます。

kubectl -n cassandra exec -it k8ssandra-dc1-default-sts-0 -- /bin/bash 
Defaulting container name to cassandra.
Use 'kubectl describe pod/k8ssandra-dc1-default-sts-0 -n cassandra' to see all of the containers in this pod.
cassandra@k8ssandra-dc1-default-sts-0:/$ which cqlsh
/opt/cassandra/bin/cqlsh
cassandra@k8ssandra-dc1-default-sts-0:/$
cassandra@k8ssandra-dc1-default-sts-0:/$ cqlsh -u k8ssandra-superuser -p 18yKg1APBIiR1AHzXB0D
Connected to k8ssandra at 127.0.0.1:9042
[cqlsh 6.0.0 | Cassandra 4.0.1 | CQL spec 3.4.5 | Native protocol v5]
Use HELP for help.
k8ssandra-superuser@cqlsh>

先ほど作成した Keyspace があるか確認してみます。

k8ssandra-superuser@cqlsh> desc keyspaces

data_endpoint_auth     system_auth         system_traces
my_k8ssandra_keyspace  system_distributed  system_views
system                 system_schema       system_virtual_schema

ありましたね。別の Keyspace も作成して、何かデータを入れて確認してみます。

k8ssandra-superuser@cqlsh> CREATE KEYSPACE my_k8ssandra_cql_keyspac  WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1};
k8ssandra-superuser@cqlsh> desc keyspaces

data_endpoint_auth        system_auth         system_views
my_k8ssandra_cql_keyspac  system_distributed  system_virtual_schema
my_k8ssandra_keyspace     system_schema
system                    system_traces

k8ssandra-superuser@cqlsh> USE my_k8ssandra_cql_keyspac;
k8ssandra-superuser@cqlsh:my_k8ssandra_cql_keyspac> CREATE TABLE users (email text primary key, name text, state text);
k8ssandra-superuser@cqlsh:my_k8ssandra_cql_keyspac> INSERT INTO users (email, name, state) values ('alice@example.com', 'Alice Smith', 'TX');
k8ssandra-superuser@cqlsh:my_k8ssandra_cql_keyspac> INSERT INTO users (email, name, state) values ('bob@example.com', 'Bob Jones', 'VA');
k8ssandra-superuser@cqlsh:my_k8ssandra_cql_keyspac> INSERT INTO users (email, name, state) values ('carol@example.com', 'Carol Jackson', 'CA');
k8ssandra-superuser@cqlsh:my_k8ssandra_cql_keyspac> INSERT INTO users (email, name, state) values ('david@example.com', 'David Yang', 'NV');

SELECTを使用して返される結果をみてみます。

k8ssandra-superuser@cqlsh:my_k8ssandra_cql_keyspac> SELECT * FROM my_k8ssandra_cql_keyspac.users;

 email             | name          | state
-------------------+---------------+-------
 alice@example.com |   Alice Smith |    TX
   bob@example.com |     Bob Jones |    VA
 david@example.com |    David Yang |    NV
 carol@example.com | Carol Jackson |    CA

(4 rows)

INSERTしたデータがありますね。
基本的なCQLを操作できることを確認できました。

最後にポートフォワーディングは終了させておきます。

$ jobs -l | grep kubectl   
37063	running	kubectl -n cassandra port-forward svc/k8ssandra-dc1-stargate-service 8080 8081 8082 9042 &
$ kill 37063  
kubectl -n cassandra port-forwa…' terminated by signal SIGTERM (Polite quit request)

まとめ

ラズパイK8sクラスタ上でK8ssandraを導入し、Cassanndraを試してみることができました。
Helm使って簡単に構築できるのはいいですね。
Stargateは簡単にしか触れてないので、時間があれば細かく見てみたいと思います。

今回はエミュレータを使って無理やり動作させましたが、今後はARMにも対応していくのかなと思っています。(k8ssandra/cass-management-apiとかはARMイメージ対応しているようでした)
管理用のツールも一緒に導入されるので、次はそっちも触ってみようと思います

参考

https://k8ssandra.io/
https://stargate.io/docs/stargate/1.0/quickstart/quickstart.html
https://zenn.dev/t_ume/articles/e62b1e837e5cd2#アクセス確認(開発者版)
https://zenn.dev/yukim/articles/e12ebb70040068

Discussion