VMware GemFire for Kubernetesをインストールして、Aria Operations for Applicationsで状態確認する


[VMware GemFire for Kubernetes](https://docs.vmware.com/en/VMware-GemFire-for-Kubernetes/index.html)はVMware GemFireのKubernetes版で、'23/9/7にリリースされたv2.3ではGemFireの10.0をサポートし、機能的にはオンプレ版のGemFireに近いものを持っているものと思われる。
また、独自のCRDやHPAに対応していたり、Kubernetesとしての強みも持っているっぽい。
ここではこれをインストールし、データを格納した後に[Aria Operations for Applications(旧Tanzu Observability)](https://docs.wavefront.com/index.html)からメトリクスを取得するところまでやってみる。


## インストール
### インストール要件
[こちら](https://docs.vmware.com/en/VMware-GemFire-for-Kubernetes/2.3/gf-k8s/supported-configurations.html#K8s-supported-versions-table)によると、サポートされているk8sディストリビューションは以下となる。
- AKS/EKS/GKE
- OpenShift 4.11
- TKG

ここではTKGで進める。TKGの場合、k8sのバージョンは1.23以上である必要がある。
また、その他以下が必要となっている。
- cert-manager 1.6.0以上
- kubectl
- Helm3.9以上
- [Carvel](https://carvel.dev/)(ytt, kbld, kapp, imgpkg)
- [VMware Tanzu Network](https://network.tanzu.vmware.com/)へのアクセス  

ここでは上記の要件を満たしていることを前提として先に進む。

### インストール
インストールに使う環境変数を宣言しておく。
```sh
# VMware Tanzu Networkへのログイン情報
export TANZUNET_USERNAME=xxx@xxx
export TANZUNET_PASSWORD=xxxxxx
# Operatorのインストール先Namespace
export GEMFIRE_NS=gemfire
```

Namespaceを作成する。
```sh
kubectl create ns $GEMFIRE_NS
```
Tanzu NetworkからイメージをPullするためのSecretを作成する。なお、この名前はGemFireのOperatorのDeploymentの中でハードコードされているため、`image-pull-secret`から変更すると動かなくなる。
```sh
kubectl create secret docker-registry image-pull-secret --namespace=$GEMFIRE_NS --docker-server=registry.tanzu.vmware.com --docker-username=$TANZUNET_USERNAME --docker-password=$TANZUNET_PASSWORD
```
k8sが1.25より前の場合は必要に応じてPSPを設定する。vSphere with TanzuのTKCなどは必要になると思われる。
```sh
kubectl create rolebinding psp-gemfire --namespace=$GEMFIRE_NS \
--clusterrole=psp:vmware-system-privileged --serviceaccount=${GEMFIRE_NS}:default
```

Operatorのインストール方法はHelmかCarvelが[選べるようになっている](https://docs.vmware.com/en/VMware-GemFire-for-Kubernetes/2.3/gf-k8s/install.html#install-the-operator-2)。
ここではHelmでインストールする。
HelmでTanzu Networkのイメージがpull出来るようログインする。
```sh
echo "$TANZUNET_PASSWORD" | helm registry login -u $TANZUNET_USERNAME registry.tanzu.vmware.com --password-stdin
```
CRDとOperatorをインストールする。
```sh
helm install gemfire-crd oci://registry.tanzu.vmware.com/tanzu-gemfire-for-kubernetes/gemfire-crd --version 2.3.0 --namespace $GEMFIRE_NS --set operatorReleaseName=gemfire-operator
helm install gemfire-operator oci://registry.tanzu.vmware.com/tanzu-gemfire-for-kubernetes/gemfire-operator --version 2.3.0 --namespace $GEMFIRE_NS
```
インストール後は以下のような感じ。
```sh
$ kubectl get all -n $GEMFIRE_NS
NAME                                                    READY   STATUS    RESTARTS   AGE
pod/gemfire-operator-controller-manager-fc564d6-jthsm   1/1     Running   0          4m48s

NAME                                       TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
service/gemfire-operator-webhook-service   ClusterIP   10.105.89.92   <none>        443/TCP   4m48s

NAME                                                  READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/gemfire-operator-controller-manager   1/1     1            1           4m49s

NAME                                                          DESIRED   CURRENT   READY   AGE
replicaset.apps/gemfire-operator-controller-manager-fc564d6   1         1         1       4m49s
```

### おまけ：Helmの中身
余談だが、Helmだがvaluesとして編集できる項目はほとんどない。CRDに関してはゼロで、Operatorについてはイメージのパスとcert-managerのNamespaceのみである。
```sh
$ helm show values oci://registry.tanzu.vmware.com/tanzu-gemfire-for-kubernetes/gemfire-operator
controllerImage: registry.tanzu.vmware.com/tanzu-gemfire-for-kubernetes/gemfire-controller:2.3.0
certManagerNamespace: cert-manager
```
デプロイするリソースは以下となっていた。
```sh
$ helm get manifest gemfire-crd -n gemfire |grep ^kind | sort | uniq
kind: CustomResourceDefinition
```
```sh
$ helm get manifest gemfire-operator -n gemfire |grep ^kind | sort | uniq
kind: Certificate
kind: ClusterIssuer
kind: ClusterRole
kind: ClusterRoleBinding
kind: Deployment
kind: Issuer
kind: MutatingWebhookConfiguration
kind: Role
kind: RoleBinding
kind: Service
kind: ValidatingWebhookConfiguration
```
## GemFireクラスタの作成
インストールの時と同じように環境変数を設定する。
```sh
# VMware Tanzu Networkへのログイン情報
export TANZUNET_USERNAME=xxx@xxx
export TANZUNET_PASSWORD=xxxxxx
# GemFireの展開先Namespace
export GEMFIRE_DEV_NS=gemfire-dev
```
Namespaceを作成する。Operatorと同じでも動くが、誤操作を避けたり権限分離を考えると分けた方がいい。
```sh
kubectl create ns $GEMFIRE_DEV_NS
```
イメージのPull用Secretを配布する。面倒なので普通に作成するが、実運用を考えると[secretgen-controller](https://github.com/carvel-dev/secretgen-controller)のCRDである`SecretImport`/`SecretExport`で配布した方がいい。
```sh
kubectl create secret docker-registry image-pull-secret --namespace=$GEMFIRE_DEV_NS --docker-server=registry.tanzu.vmware.com --docker-username=$TANZUNET_USERNAME --docker-password=$TANZUNET_PASSWORD
```
ちなみにOperatorのPull用Secret名はハードコーディングされていたが、GemFireのクラスタで使うPull用Secretは別名に変更できる。

GemFireのクラスタを定義するCRDのManifestを作成してapplyする。
```yaml
cat << EOF > ./gemfire-cluster.yaml
apiVersion: gemfire.vmware.com/v1
kind: GemFireCluster
metadata:
  name: gemfire1
spec:
  image: registry.tanzu.vmware.com/pivotal-gemfire/vmware-gemfire:10.0.0
EOF
kubectl apply -f ./gemfire-cluster.yaml -n $GEMFIRE_DEV_NS
```
なお、CRDの詳細な説明は公式サイトの[こちら](https://docs.vmware.com/en/VMware-GemFire-for-Kubernetes/2.3/gf-k8s/crd.html)に記載がある。
しばらくするとLocatorとServerが起動する。
```sh
$ kubectl get all -n $GEMFIRE_DEV_NS
NAME                     READY   STATUS    RESTARTS   AGE
pod/gemfire1-locator-0   1/1     Running   0          4m45s
pod/gemfire1-server-0    1/1     Running   0          3m42s
pod/gemfire1-server-1    1/1     Running   0          3m42s

NAME                         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                       AGE
service/gemfire1-locator     ClusterIP   None         <none>        10334/TCP,7070/TCP,4321/TCP   4m47s
service/gemfire1-locator-0   ClusterIP   None         <none>        10334/TCP,7070/TCP,4321/TCP   4m47s
service/gemfire1-server      ClusterIP   None         <none>        40404/TCP,7070/TCP,4321/TCP   3m44s
service/gemfire1-server-0    ClusterIP   None         <none>        40404/TCP,7070/TCP,4321/TCP   3m44s
service/gemfire1-server-1    ClusterIP   None         <none>        40404/TCP,7070/TCP,4321/TCP   3m44s

NAME                                READY   AGE
statefulset.apps/gemfire1-locator   1/1     4m46s
statefulset.apps/gemfire1-server    2/2     3m43s
```
`kind: GemFireCluster`オブジェクトは以下のようになった。
```sh
$ kubectl get gemfireclusters -n $GEMFIRE_DEV_NS
NAME       LOCATORS   SERVERS   CLUSTER IMAGE                                                     OPERATOR VERSION
gemfire1   1/1        2/2       registry.tanzu.vmware.com/pivotal-gemfire/vmware-gemfire:10.0.0   2.3.0-build.26
```
なお、しっかりOperatorでリソースを管理しているようで，StatefulSetを削除してもすぐに元に戻る。
```sh
$ kubectl delete sts gemfire1-server -n $GEMFIRE_DEV_NS
statefulset.apps "gemfire1-server" deleted
$ kubectl get sts -n $GEMFIRE_DEV_NS
NAME               READY   AGE
gemfire1-locator   1/1     10m
gemfire1-server    0/2     2s
```
これは`kind: GemFireCluster`オブジェクトのannotationの`pause-reconciliation`で制御されていて、以下のように設定すると元に戻らなくなる。
```sh
kubectl annotate gemfirecluster gemfire1 gemfire.vmware.com/pause-reconciliation=true --overwrite -n $GEMFIRE_DEV_NS
```
```sh
$ k delete sts gemfire1-server -n $GEMFIRE_DEV_NS 
statefulset.apps "gemfire1-server" deleted
$ k get sts -n $GEMFIRE_DEV_NS
NAME               READY   AGE
gemfire1-locator   1/1     13m
```
戻すと復活する。
```sh
$ kubectl annotate gemfirecluster gemfire1 gemfire.vmware.com/pause-reconciliation=false --overwrite -n $GEMFIRE_DEV_NS
gemfirecluster.gemfire.vmware.com/gemfire1 annotated
$ kubectl get sts
NAME               READY   AGE
gemfire1-locator   1/1     15m
gemfire1-server    0/2     2s
```
## GemFireクラスタへの接続

ここではLocator PodからLocatorに接続する。Locator Pod外から繋ぐことも出来るが、TLSの証明書の都合でLocator Podから繋いだ方が楽が出来るため、まずはLocator Podから繋ぐ。
GemFireクラスタに接続する前に、Trust StoreとKey Storeのパスワードを取得する。(値は共通)
```sh
kubectl get secret gemfire1-cert -o=jsonpath='{.data.password}' -n $GEMFIRE_DEV_NS | base64 --decode
```

gfshを起動する。
```sh
kubectl exec -it gemfire1-locator-0 -n $GEMFIRE_DEV_NS -- gfsh
```
Locatorに接続する。引数のうち、password部分は先程取得したTrust Store/Key Storeのパスワードに置き換えて実行すること。
```sh
connect --locator=gemfire1-locator-0[10334] --trust-store=/certs/truststore.p12 --trust-store-password="2_7jdK...9fyc=" --key-store=/certs/keystore.p12 --key-store-password="2_7jdK...9fyc="
```
実行すると、key-store-type等聞かれるが、全てdefaultのままでOK。
正常に接続後、状態を確認する。
```sh
gfsh>list members
Member Count : 3

       Name        | Id
------------------ | ----------------------------------------------------------------------------
gemfire1-locator-0 | gemfire1-locator-0(gemfire1-locator-0:1:locator)<ec><v0>:42595 [Coordinator]
gemfire1-server-1  | gemfire1-server-1(gemfire1-server-1:1)<v7>:51704
gemfire1-server-0  | gemfire1-server-0(gemfire1-server-0:1)<v8>:59708
```
```sh
gfsh>list region
No Regions Found

```
リージョンがないため、作成する。
```sh
create region --name=regionA --type=REPLICATE_PERSISTENT
```

データを入れてみる。
```
put --region=regionA --key="1" --value="one"
put --region=regionA --key="2" --value="two"
```
入れたデータを取得する。
```sh
gfsh>query --query="select * from /regionA"
Result : true
Limit  : 100
Rows   : 2

Result
------
two
one
```
問題なく利用できるようだ。

## Aria Operations for Applicationsのデプロイ
Aria Operations for Applications(以下AOA)との統合は[こちら](https://docs.wavefront.com/gemfire.html)に手順が記載されている。
Kubernetes版との連携ではWavefront ProxyとKubernetes Metrics Collectorが入っていれば勝手に取ってくれる模様。
なので[この辺](https://docs.wavefront.com/vsphere_tanzu.html#add-a-kubernetes-integration)を参考にWavefront Proxyをデプロイする。
AOAのKubernetesのIntegrationの画面から値を入力していく。Token等は最初から値が設定されているのでクラスタ名程度で済むはずだ。
![1695898406593.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/eeae047e-5729-1e5a-ddec-5a70c15316e4.png)
デプロイ用のコマンドが表示されるので、コピーしてクラスタで実行し、FINISHボタンを押す。
![1695898511557.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/e6b9c94e-0df2-1181-814f-0053ed3b5ef1.png)

待ち画面となるので、コンポーネントが展開されるのを待つ。
![1695898582972.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/529e4782-db7d-fbfb-8f16-eadee068ba28.png)

5分くらいすると完了し、Kubernetesダッシュボードにメトリクスが少しずつ表示される。
![1695898988564.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/a01cdde4-e5f8-2618-abbb-04ccd614980d.png)

続いてGemFireのダッシュボードを作成する。
画面上部の`Integrations`を選択後、GemFireを検索してクリックし、`Dashboards`から`INSTALL DASHBOARDS`をクリックする。
![1695969715646.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/840107c2-9340-9f40-510e-811eeadae498.png)

インストール後、Dashboardが3種類表示されるので、一番右の`VMware GemFire for Kubernetes`をクリックする。
![1695969904379.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/5369b9c3-42d9-8897-cf2c-7eb0e7ed3bbf.png)

GemFireのダッシュボードが表示され、以下のような形で先程作成したリージョンなどの情報も取得できていることが分かる。
![1695984154990.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/8abd7ac4-d260-02b6-054a-0c28b38d51c4.png)

## 所感

Kubernetes版は最初からTLSが有効になっていたり、使い勝手がややオンプレ版と異なる点は注意が必要そう。
また、Serviceのtypeが指定できなかったり、痒いところに届かないところも多い。
ただ、使えない訳ではないので、CRDで完結すると考えずに自分でリソースを作成するなどして補って使えればと思う。
あと、Aria Operations for Applicationsの連携は非常に簡単で、かつ提供されるダッシュボードでリージョンやLocator, Serverの数が分かるなど使い勝手が良いものであった。
GemFireを使う際はAria Operations for Applicationsの利用も検討すると良さそうだ。