オフライン環境でGemFire for Kubernetesを動かす

[GemFire for Kubernetesのインストール手順](https://docs.vmware.com/en/VMware-GemFire-for-Kubernetes/2.3/gf-k8s/install.html)にはオフライン環境でのインストール手順は書かれておらず、[Requirement](https://docs.vmware.com/en/VMware-GemFire-for-Kubernetes/2.3/gf-k8s/supported-configurations.html#prerequisites-0)でもTanzu Networkとの接続が必須のように書かれている。
ただし、噂で聞いたところどうもオフラインでも利用は特段問題ないとのことだったので、ここではオフライン環境でのインストール手順をまとめる。
なお、非公式な手順となるので、商用利用する場合とかは別途サポートに問い合わせた方がよい。

ここでは以下の手順でイメージを持ち込んで、GemFire Clusterを立ち上げる。
1. インターネット接続環境でイメージHelm Chartをダウンロードし、オフライン環境に持ち込む
2. オフライン環境で取り込んだイメージ・Chartをイメージレジストリにpushする
3. GemFire Operatorをインストールする
4. GemFire Clusterを起動する

また、以下は今回の検証の前提となる。
- cert-managerはインストール済み
- KubernetesはTKGを利用

※'23/11/13補足：
利用したコンテナイメージは10.0.0でStandalone版は10.0.1がリリースされていて乖離がある。
最初、10.0.0しかドキュメントに載っていなかったので、ここでは10.0.0で試したが、後で確認したところ、
- パッチバージョンの変更はGemFire for Kubernetesのドキュメントには反映されない
- パッチバージョンが変更されたコンテナイメージはStandalone版と同じ日にリリースされる

とのことで、今時点では10.0.1が利用可能なので、試される方はコンテナイメージのタグは最新のパッチバージョンに書き換えて試すことを推奨する。

## インターネット接続環境でイメージをファイルとして取り込む
イメージのダウンロードには[`imgpkg`](https://carvel.dev/imgpkg/)を使う。

最初にGemFireのイメージレジストリにアクセスするために、Tanzu Networkの認証情報を設定する。
```sh
export TANZUNET_USERNAME=xxx@yyy.zzz
export TANZUNET_PASSWORD=xxxxx
```
imgpkgがdockerの認証情報を使ってpullするため、認証情報をファイルに残すために一度ログインする。
```sh
echo $TANZUNET_PASSWORD | docker login registry.tanzu.vmware.com -u $TANZUNET_USERNAME --password-stdin
```
イメージをダウンロードする。`--to-tar`でイメージの保存先を指定する。
```sh
imgpkg copy -i registry.tanzu.vmware.com/pivotal-gemfire/vmware-gemfire:10.0.0 --to-tar /tmp/gemfire.tar
imgpkg copy -i registry.tanzu.vmware.com/tanzu-gemfire-for-kubernetes/gemfire-controller:2.3.0 --to-tar /tmp/gemfire-controller.tar
```

次にHelm Chartをダウンロードする。最初にログインする。
```sh
echo $TANZUNET_PASSWORD | helm registry login registry.tanzu.vmware.com -u $TANZUNET_USERNAME --password-stdin
```
Helm Chartをpullする。
```sh
helm pull oci://registry.tanzu.vmware.com/tanzu-gemfire-for-kubernetes/gemfire-crd --version 2.3.0
helm pull oci://registry.tanzu.vmware.com/tanzu-gemfire-for-kubernetes/gemfire-operator --version 2.3.0
```
pullが終わると、それぞれカレントディレクトリに`gemfire-crd-2.3.0.tgz`と`gemfire-operator-2.3.0.tgz`というファイルが作成されている。
この後はオフライン環境での作業になるので、作成したファイルをUSBメモリ等で頑張ってオフライン環境に持ち込む。

## オフライン環境で取り込んだイメージ・Chartをイメージレジストリにpushする
今回、イメージレジストリとしてHarborを利用し、gemfireというPrivateなプロジェクトが既に作成済みのものとして進める。
持ち込んだイメージをpushするために、最初にpush先のHarborの接続先や認証情報を環境変数に設定する。
```sh
export HARBOR_URL=harbor.10.180.81.126.sslip.io
export HARBOR_USERNAME=admin
export HARBOR_PASSWORD='xxxxx'
```
Harborの証明書をdockerが読める場所に置く。
```sh
sudo mkdir -p /etc/docker/certs.d/$HARBOR_URL
sudo cp ca.crt /etc/docker/certs.d/$HARBOR_URL
sudo systemctl restart docker
```
Harborにログインする。
```sh
echo $HARBOR_PASSWORD | docker login $HARBOR_URL -u $HARBOR_USERNAME --password-stdin
```
イメージをpushする。
```sh
imgpkg copy --tar ./gemfire.tar --to-repo ${HARBOR_URL}/gemfire/gemfire --registry-ca-cert-path /etc/docker/certs.d/$HARBOR_URL/ca.crt
imgpkg copy --tar ./gemfire-controller.tar --to-repo ${HARBOR_URL}/gemfire/gemfire-controller --registry-ca-cert-path /etc/docker/certs.d/$HARBOR_URL/ca.crt
```
HelmでHarborにログインする。
```sh
echo $HARBOR_PASSWORD | helm registry login ${HARBOR_URL} -u $HARBOR_USERNAME --password-stdin
```
Chartをpushする。
```sh
helm push gemfire-crd-2.3.0.tgz oci://$HARBOR_URL/gemfire --ca-file /etc/docker/certs.d/$HARBOR_URL/ca.crt
helm push gemfire-operator-2.3.0.tgz oci://$HARBOR_URL/gemfire --ca-file /etc/docker/certs.d/$HARBOR_URL/ca.crt
```
## GemFire Operatorをインストールする
GemFire OperatorはCRDとOperator本体の2つのチャートからなる。
このうち、Operator本体の方にはイメージのパスを指定する箇所があるため、values.yamlを抜き出してimageの参照元を書き換えてインストールする。
先にCRDからインストールする。
最初にOperatorをインストールするNamespaceを作成する。
```sh
export GF_OP_NS=gemfire-operator
kubectl create ns $GF_OP_NS
```
Helmでインストーする。
```sh
helm install gemfire-crd oci://$HARBOR_URL/gemfire/gemfire-crd --version 2.3.0 --namespace $GF_OP_NS --set operatorReleaseName=gemfire-operator --ca-file /etc/docker/certs.d/$HARBOR_URL/ca.crt
```
次にOperatorをデプロイするが、その前にKubernetesクラスタにHarborの証明書が適用されていない場合、証明書を追加する。
Management Clusterにコンテキストを切り替えて、Clusterリソースを取得する。
```sh
kubectl get cluster -o yaml tkg24-wc |kubectl neat -f - > ./tkg24-wc.yaml
```
Harborの証明書の内容をBase64にエンコードする。
```sh
sudo cat /etc/docker/certs.d/$HARBOR_URL/ca.crt |base64 -w0
```

TKGの[設定手順](https://docs.vmware.com/jp/VMware-Tanzu-Kubernetes-Grid/2.2/using-tkg/workload-clusters-secret.html#--8)に従って、Clusterリソースの`spec.topology.variables`に証明書を追記する。
```diff
：（省略）
     variables:
+    - name: additionalImageRegistries
+      value:
+      - caCert: "LS0tLS1...(省略)...LS0tLQo="
+        host: harbor.10.180.81.126.sslip.io
+        skipTlsVerify: true
     - name: vcenter
       value:
         cloneMode: fullClone
：（省略）
```
設定を追記後、Clusterに設定を反映する。
```sh
kubectl apply -f ./tkg24-wc.yaml
```
反映後、Workload Clusterにコンテキストを戻す。
次にGemFire Operatorのvalues.yamlを取得する。
```sh
helm show values oci://$HARBOR_URL/gemfire/gemfire-operator  --ca-file /etc/docker/certs.d/$HARBOR_URL/ca.crt > gemfire-operator-values.yaml
```
values.yaml内に`controllerImage`という箇所でイメージのパスを指定しているので、これを先程pushした`gemfire-controller`に置き換える
```diff
@@ -1,3 +1,3 @@
-controllerImage: registry.tanzu.vmware.com/tanzu-gemfire-for-kubernetes/gemfire-controller:2.3.0
+controllerImage: harbor.10.180.81.126.sslip.io/gemfire/gemfire-controller:2.3.0
 certManagerNamespace: cert-manager

```
次にdefaultのServiceAccountがイメージをpull出来るよう、Harborの認証情報をSecretで作成し、ServiceAccountに紐付ける。
```sh
kubectl create secret docker-registry image-pull-secret --namespace=$GF_OP_NS --docker-server=$HARBOR_URL --docker-username=$HARBOR_USERNAME --docker-password=$HARBOR_PASSWORD
kubectl patch serviceaccount default -p '{"imagePullSecrets": [{"name": "image-pull-secret"}]}' -n $GF_OP_NS
```
ここまで終わったら、GemFire OperatorをHarborのChartを使ってvaluesを指定してインストールする。
```sh
helm install gemfire-operator oci://$HARBOR_URL/gemfire/gemfire-operator --version 2.3.0 --namespace $GF_OP_NS --ca-file /etc/docker/certs.d/$HARBOR_URL/ca.crt -f ./gemfire-operator-values.yaml
```
ここまでの設定に不備がなければPodが起動する。
```sh
$ kubectl get pod --namespace=$GF_OP_NS 
NAME                                                   READY   STATUS    RESTARTS   AGE
gemfire-operator-controller-manager-78db58bfb7-pg64l   1/1     Running   0          7s
```

## GemFire Clusterを起動する
GemFire Clusterを作成する。ここでは最小限の設定で起動する。
以下でManifestを作成する。
```yaml
cat << EOF > ./gem-cluster.yaml
apiVersion: gemfire.vmware.com/v1
kind: GemFireCluster
metadata:
  name: gemfire1
  namespace: $GF_OP_NS
spec:
  image: $HARBOR_URL/gemfire/gemfire:10.0.0
  imagePullSecrets:
  - name: image-pull-secret 
  security:
    tls: {}
EOF
```
なお、Harborの認証情報Secretを作成する手間を省くために同じNamespaceでリソースを作成しているが、本当はNamespaceを分けた方が良い。
applyしてGemFire Clusterを起動する。
```sh
kubectl apply -f ./gem-cluster.yaml
```
問題なければコンテナが無事起動する。
```sh
$ kubectl get pod -l app.kubernetes.io/instance=gemfire1 -n $GF_OP_NS
NAME                 READY   STATUS    RESTARTS   AGE
gemfire1-locator-0   1/1     Running   0          2m47s
gemfire1-server-0    1/1     Running   0          111s
gemfire1-server-1    1/1     Running   0          111s
```
利用しているイメージを見ると、ちゃんとPrivateなリポジトリから引っ張ってきている事がわかる。
```sh
$ kubectl get pod -o yaml gemfire1-locator-0 |grep "image:" | sort |uniq
    image: harbor.10.180.81.126.sslip.io/gemfire/gemfire-controller:2.3.0
    image: harbor.10.180.81.126.sslip.io/gemfire/gemfire:10.0.0
```