---
title: VMware Tanzu Gemfire on Kubernetes 2.6をインストールするメモ
summary: この記事では、Tanzu GemFire on Kubernetes 2.6のインストールからクラスター構築、Dockerイメージのリロケート、TLS設定、外部からの接続手順まで解説します。
tags: ["Gemfire", "Tanzu", "Kubernetes", "Helm", "Contour"]
categories: ["Middleware", "DistributedSystem", "InMemoryDataGrid", "Gemfire"]
date: 2025-06-23T05:28:49Z
updated: 2026-04-27T04:02:02.754Z
---

> [!NOTE] 
> 2026-04-27 Tanzu Gemfire on Kubernetes 2.6版に更新しました

[Tanzu Gemfire on Kubernetes 2.6](https://techdocs.broadcom.com/us/en/vmware-tanzu/data-solutions/tanzu-gemfire-on-kubernetes/2-6/gf-k8s/index.html)をインストールしてKubernetes環境でGemFireクラスターを構築する手順を説明します。

**目次**
<!-- toc -->

### Tanzu GemFire on Kubernetes Docker Registryのアクセストークン取得

https://support.broadcom.com にログインして、"My Downloads"ページにアクセスし、"Registry Tokens"ボタンをクリックします。

![image](https://s3.ik.am/ikam/_/1770692193915_pasted-image.png)

"Generate Registry Token"ボタンをクリックして、"Submit"ボタンをクリックします。

![image](https://s3.ik.am/ikam/_/1770692238297_pasted-image.png)

生成されたトークンの"Copy Token"ボタンをクリックし、トークンをクリップボードにコピーします。

![image](https://s3.ik.am/ikam/_/1770692268848_pasted-image.png)

このページにアクセスできない場合は、ライセンスが有効化されていない可能性があるため、
担当のアカウントチームに連絡してライセンスの有効化を依頼してください。


次のコマンドで`registry.packages.broadcom.com`にログインします。認証情報を自分のものに置き換えてください。

```bash
BC_SUPPORT_USERNAME=your-email@example.com
BC_SUPPORT_PASSWORD=eyJ2ZX*************************************
docker login registry.packages.broadcom.com -u ${BC_SUPPORT_USERNAME} -p ${BC_SUPPORT_PASSWORD}
```

```
WARNING! Using --password via the CLI is insecure. Use --password-stdin.
Login Succeeded
```

今回はコンテナイメージをPrivate Network上のSelf HostedなContainer Registryにリロケートして使用します。
リロケート先はPrivate Network上でないとEULAに違反する恐れがあるので気をつけてください。

### Helm ChartとコンテナイメージをContainer Registryへリロケート


次のコマンドでContainer Registryにログインします。認証情報は自分のものに置き換えてください。

```bash
REGISTRY_HOSTNAME=my-private-registry.example.com
REGISTRY_USERNAME=your-username
REGISTRY_PASSWORD=your-password
docker login ${REGISTRY_HOSTNAME} -u ${REGISTRY_USERNAME} -p ${REGISTRY_PASSWORD}
```

リロケートには[imgpkg](https://carvel.dev/imgpkg/)を使用します。imgpkgがインストールされていない場合は、[公式ドキュメント](https://carvel.dev/imgpkg/docs/v0.41.x/install/)を参照してインストールしてください。

```bash
imgpkg copy -i registry.packages.broadcom.com/tanzu-gemfire-for-kubernetes/gemfire-crd:2.6.3 --to-repo ${REGISTRY_HOSTNAME}/tanzu-gemfire-for-kubernetes/gemfire-crd
imgpkg copy -i registry.packages.broadcom.com/tanzu-gemfire-for-kubernetes/gemfire-operator:2.6.3 --to-repo ${REGISTRY_HOSTNAME}/tanzu-gemfire-for-kubernetes/gemfire-operator
```

リロケート後のHelm Chartにアクセスして設定可能なvaluesを確認します。

```bash
$ helm show values oci://${REGISTRY_HOSTNAME}/tanzu-gemfire-for-kubernetes/gemfire-operator --version 2.6.3
Pulled: my-private-registry.example.com/tanzu-gemfire-for-kubernetes/gemfire-operator:2.6.3
Digest: sha256:a0ff0f18bac48fd24cb81817ee2d30d06dcfe012800c3b49d2d21bb155ab7221
controllerImage: registry.packages.broadcom.com/tanzu-gemfire-for-kubernetes/gemfire-controller:2.6.3
certManagerNamespace: cert-manager
```

`controllerImage`も次のコマンドで`registry.packages.broadcom.com`から`my-private-registry.example.com`にリロケートします。


```bash
imgpkg copy -i registry.packages.broadcom.com/tanzu-gemfire-for-kubernetes/gemfire-controller:2.6.3 --to-repo ${REGISTRY_HOSTNAME}/tanzu-gemfire-for-kubernetes/gemfire-controller
```

### Tanzu GemFire on Kubernetesのインストール

Tanzu GemFire for KubernetesのCRDとOperatorをインストールします。

まずはKubernetesの名前空間を作成し、Container RegistryのSecretを作成します。

```bash
kubectl create namespace gemfire-system
kubectl create secret docker-registry gemfire-registry-secret \
    --docker-server=${REGISTRY_HOSTNAME} \
    --docker-username=${REGISTRY_USERNAME} \
    --docker-password="${REGISTRY_PASSWORD}" \
    -n gemfire-system
```

次のコマンドでGemfire CRDをインストールします。

```bash
helm upgrade --install \
  -n gemfire-system \
  gemfire-crd \
  oci://${REGISTRY_HOSTNAME}/tanzu-gemfire-for-kubernetes/gemfire-crd \
  --version 2.6.3 \
  --set operatorReleaseName=gemfire-operator \
  --wait
```

次のコマンドでGemfire Operatorをインストールします。リロケート後のChartとコンテナイメージを指定します。

```bash
helm upgrade --install \
  -n gemfire-system \
  gemfire-operator \
  oci://${REGISTRY_HOSTNAME}/tanzu-gemfire-for-kubernetes/gemfire-operator \
  --version 2.6.3 \
  --set controllerImage=${REGISTRY_HOSTNAME}/tanzu-gemfire-for-kubernetes/gemfire-controller:2.6.3 \
  --set imagePullSecretName=gemfire-registry-secret \
  --wait
```

しばらくするとインストールが完了します。helm listでインストール状態を確認します。

```bash
$ helm list -n gemfire-system
NAME            	NAMESPACE     	REVISION	UPDATED                             	STATUS  	CHART                 	APP VERSION
gemfire-crd     	gemfire-system	1       	2025-06-20 11:55:13.47622 +0900 JST 	deployed	gemfire-crd-2.5.0     	2.5.0      
gemfire-operator	gemfire-system	1       	2025-06-20 11:56:56.713258 +0900 JST	deployed	gemfire-operator-2.5.0	2.5.0 
```

Podの状態を確認して、Operatorが正常に起動していることを確認します。

```bash
$ kubectl get pod -n gemfire-system 
NAME                                                 READY   STATUS    RESTARTS   AGE
gemfire-operator-controller-manager-c4d8dfd5-nx6p5   1/1     Running   0          2m42s
```

利用可能なカスタムリソースを確認します。

```bash
$ kubectl api-resources --api-group=gemfire.vmware.com 
NAME              SHORTNAMES   APIVERSION              NAMESPACED   KIND
gemfireclusters                gemfire.vmware.com/v1   true         GemFireCluster
```

### GemFireClusterの作成

Gemfire Operatorを使ってdemo namespaceにGemFireClusterインスタンスを作成します。


GemFireのコンテナイメージは別途指定する必要があり、これも先と同様に`my-private-registry.example.com`にリロケートしておきます。Operatorのバージョンと独立して、サポートされている最新のGemFireのコンテナイメージを使用することができます。
ここでは本稿執筆時点で最新のバージョンである10.2.3を使用します。

```bash
imgpkg copy -i registry.packages.broadcom.com/pivotal-gemfire/vmware-gemfire:10.2.3 --to-repo ${REGISTRY_HOSTNAME}/pivotal-gemfire/vmware-gemfire
imgpkg copy -i registry.packages.broadcom.com/pivotal-gemfire/vmware-gemfire-all:10.2.3 --to-repo ${REGISTRY_HOSTNAME}/pivotal-gemfire/vmware-gemfire-all
```

次のコマンドでnamespaceとdocker pull secretを作成します。

```bash
kubectl create namespace demo
kubectl create secret docker-registry gemfire-registry-secret \
    --docker-server=${REGISTRY_HOSTNAME} \
    --docker-username=${REGISTRY_USERNAME} \
    --docker-password="${REGISTRY_PASSWORD}" \
    -n  demo
```


次のコマンドでGemFireClusterインスタンスを作成します。Locator 2台、Server 3台の構成にします。

```yaml
cat <<EOF > /tmp/demo-gemfire.yaml
---
apiVersion: gemfire.vmware.com/v1
kind: GemFireCluster
metadata:
  name: demo
spec:
  image: ${REGISTRY_HOSTNAME}/pivotal-gemfire/vmware-gemfire:10.2.3
  imagePullSecrets:
  - name: gemfire-registry-secret
  persistentVolumeClaim:
    deleteOnShutdown: true
  locators:
    replicas: 2
  servers:
    replicas: 3
    resources:
      requests:
        memory: 4Gi
      limits:
        memory: 4Gi
---
EOF

kubectl apply -f /tmp/demo-gemfire.yaml -n demo
```

> [!NOTE]
> `spec.persistentVolumeClaim.deleteOnShutdown`を`true`に設定すると、GemFireClusterが削除されたときにPersistentVolumeClaimも削除されます。
> デフォルトでは`false`になっているので、GemFireClusterを削除してもPersistentVolumeClaimは残ります。プロダクションでは、念の為`false`にしておくことが良いでしょう。


次のコマンドで、GemFireClusterの状態を確認します。

```bash
$ kubectl get gemfirecluster,sts,pod,pvc -n demo -owide
NAME                                     LOCATORS   SERVERS   CLUSTER IMAGE                                                           OPERATOR VERSION
gemfirecluster.gemfire.vmware.com/demo   2/2        3/3       my-private-registry.example.com/pivotal-gemfire/vmware-gemfire:10.2.3   2.5.0

NAME                            READY   AGE     CONTAINERS   IMAGES
statefulset.apps/demo-locator   2/2     5m32s   locator      my-private-registry.example.com/pivotal-gemfire/vmware-gemfire:10.2.3
statefulset.apps/demo-server    3/3     4m9s    server       my-private-registry.example.com/pivotal-gemfire/vmware-gemfire:10.2.3

NAME                 READY   STATUS    RESTARTS   AGE     IP             NODE     NOMINATED NODE   READINESS GATES
pod/demo-locator-0   1/1     Running   0          5m32s   10.1.42.145    banana   <none>           <none>
pod/demo-locator-1   1/1     Running   0          5m32s   10.1.42.146    banana   <none>           <none>
pod/demo-server-0    1/1     Running   0          4m9s    10.1.42.147    banana   <none>           <none>
pod/demo-server-1    1/1     Running   0          4m9s    10.1.173.139   cherry   <none>           <none>
pod/demo-server-2    1/1     Running   0          4m9s    10.1.42.148    banana   <none>           <none>

NAME                                        STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE     VOLUMEMODE
persistentvolumeclaim/data-demo-locator-0   Bound    pvc-50d09d5f-bcac-4e74-889f-372fa212c05c   2Gi        RWO            nfs-csi        <unset>                 5m32s   Filesystem
persistentvolumeclaim/data-demo-locator-1   Bound    pvc-cd7d814a-d5e4-455c-b890-d88713778e7b   2Gi        RWO            nfs-csi        <unset>                 5m32s   Filesystem
persistentvolumeclaim/data-demo-server-0    Bound    pvc-baa12461-2220-4142-96d6-820a78a4379a   4Gi        RWO            nfs-csi        <unset>                 4m9s    Filesystem
persistentvolumeclaim/data-demo-server-1    Bound    pvc-423de0c1-782b-442d-8aeb-55909b14e9ab   4Gi        RWO            nfs-csi        <unset>                 4m9s    Filesystem
persistentvolumeclaim/data-demo-server-2    Bound    pvc-90253b95-16f4-4569-adba-9b568daa256a   4Gi        RWO            nfs-csi        <unset>                 4m9s    Filesystem
```

### GemFireクラスターへの接続と動作確認

次のコマンドでLocatorのPod内でbashを実行します。

```bash
kubectl -n demo exec -it demo-locator-0 -- bash
```

Tanzu Gemfire on Kubernetesで作成されるGemfireクラスターはデフォルトでTLSが有効になっています。`/certs`ディレクトリにGemFireの証明書が作成されていることを確認します。

```bash
[root@demo-locator-0 data]# ls -l /certs
total 0
lrwxrwxrwx 1 root root 13 Jun 20 05:42 ca.crt -> ..data/ca.crt
lrwxrwxrwx 1 root root 19 Jun 20 05:42 keystore.p12 -> ..data/keystore.p12
lrwxrwxrwx 1 root root 15 Jun 20 05:42 password -> ..data/password
lrwxrwxrwx 1 root root 14 Jun 20 05:42 tls.crt -> ..data/tls.crt
lrwxrwxrwx 1 root root 14 Jun 20 05:42 tls.key -> ..data/tls.key
lrwxrwxrwx 1 root root 21 Jun 20 05:42 truststore.p12 -> ..data/truststore.p12
```

証明書のTruststoreとKeystoreのパスワードは、`/certs/password`に保存されています。これを使ってgfshでGemFireに接続します。

```bash
[root@demo-locator-0 data]# echo $(cat /certs/password)
rpUt17JjuLLoxN7S9CzRZ8WbwYqMaDjINTZ9OxetAU4=
```

`gfsh`を実行して、GemFireに接続します。

```bash
[root@demo-locator-0 data]# gfsh
/gemfire/bin/gfsh: line 36: tput: command not found
    _________________________     __
   / _____/ ______/ ______/ /____/ /
  / /  __/ /___  /_____  / _____  / 
 / /__/ / ____/  _____/ / /    / /  
/______/_/      /______/_/    /_/    10.2.3

Monitor and Manage Tanzu GemFire
gfsh>
```

`connect`コマンドを実行して、Locatorに接続します。ここでは、Locatorのホスト名とポート番号を指定します。`--trust-store`と`--key-store`オプションで証明書のパスを指定し、パスワードは先ほど確認したものを使用します。

```bash
connect --locator=demo-locator-0.demo-locator.demo.svc.cluster.local[10334] --trust-store=/certs/truststore.p12 --trust-store-password=rpUt17JjuLLoxN7S9CzRZ8WbwYqMaDjINTZ9OxetAU4= --key-store=/certs/keystore.p12 --key-store-password=rpUt17JjuLLoxN7S9CzRZ8WbwYqMaDjINTZ9OxetAU4=
```

以下の項目に対して、プロンプト上で入力を求められますが、全てデフォルトでEnterを押して進めます。

```
key-store-type(default: JKS): 
trust-store-type(default: JKS): 
ssl-ciphers(default: any): 
ssl-protocols(default: any): 
ssl-enabled-components(default: all):
```

これでGemFireに接続できました。以下のようなメッセージが表示されます：

```
Connecting to Locator at [host=demo-locator-0.demo-locator.demo.svc.cluster.local, port=10334] ..
Connecting to Manager at [host=demo-locator-0.demo-locator.demo.svc.cluster.local, port=1099] ..
Successfully connected to: [host=demo-locator-0.demo-locator.demo.svc.cluster.local, port=1099]

You are connected to a cluster of version 10.2.3.
```

なお、Pod内からは`connect --url=https://demo-locator.demo.svc.cluster.local:7070/gemfire/v1 --skip-ssl-validation`を実行しても接続できました。

`list members`コマンドで、GemFireのメンバー（LocatorとServer）が正しく起動していることを確認します：

```bash
gfsh>list members
Member Count : 5

     Name      |                                  Id                                  |  Type   | Status
-------------- | -------------------------------------------------------------------- | ------- | ------
demo-locator-0 | demo-locator-0(demo-locator-0:1:locator)<ec><v0>:60681 [Coordinator] | Locator | Ready
demo-locator-1 | demo-locator-1(demo-locator-1:1:locator)<ec><v1>:54760               | Locator | Ready
demo-server-0  | demo-server-0(demo-server-0:1)<v2>:42292                             | Server  | Ready
demo-server-1  | demo-server-1(demo-server-1:1)<v3>:56073                             | Server  | Ready
demo-server-2  | demo-server-2(demo-server-2:1)<v2>:57696                             | Server  | Ready
```

PARTITION_PERSISTENTタイプのRegionを作成し、冗長度1（各データが2つのServerに保存される）を設定します。その後、テストデータを追加します：


```bash
create region --name=demo --type=PARTITION_PERSISTENT --redundant-copies=1

put --region=/demo --key=aaa --value=1
put --region=/demo --key=bbb --value=2
put --region=/demo --key=ccc --value=3
put --region=/demo --key=ddd --value=4
put --region=/demo --key=eee --value=5
```

データが正しく保存されているかをクエリで確認します：

```bash
gfsh>query --query="SELECT * FROM /demo"
Result : true
Limit  : 100
Rows   : 5

Result
------
3
5
2
1
4
```

### 外部のgfshからGemFireアクセス設定

Podの外からgfshでGemFireに接続するために、Locatorの管理APIを公開します。ここではContourのHTTPProxyを使用して、[Upstream TLS](https://projectcontour.io/docs/1.32/config/upstream-tls/)の機能を使います。

> [!NOTE]
> この例では`projectcontoure` namespaceに作成されたCertificate`default-tls` (Let's Encryptによるワイルドカード証明書)が[TLSCertificateDelegation](https://projectcontour.io/docs/1.32/config/tls-delegation/#tls-certificate-delegation)で公開されている前提です。環境に応じて適切な証明書設定を行ってください。

次のコマンドで、Locatorの管理APIを公開するためのServiceとHTTPProxyを作成します。


```yaml
cat <<EOF > /tmp/demo-locator-management-api.yaml
apiVersion: v1
kind: Service
metadata:
  name: demo-locator-management-api
  namespace: demo
  annotations:
    projectcontour.io/upstream-protocol.tls: "7070"
spec:
  type: ClusterIP
  ports:
  - name: locator-management-api
    port: 7070
  selector:
    gemfire.vmware.com/app: demo-locator
---
apiVersion: projectcontour.io/v1
kind: HTTPProxy
metadata:
  name: demo-locator-management-api
  namespace: demo
spec:
  virtualhost:
    fqdn: demo-locator.lan.ik.am
    tls:
      secretName: projectcontour/default-tls
  routes:
  - services:
    - name: demo-locator-management-api
      port: 7070
      validation:
        caSecret: demo-cert
        subjectName: demo-locator.demo.svc.cluster.local
---
EOF

kubectl apply -f /tmp/demo-locator-management-api.yaml
```

これでPodの外から`gfsh`を使って次のようにGemFireに接続できるようになります。

```
connect --url=https://demo-locator.lan.ik.am/gemfire/v1
```


### JavaアプリケーションからGemFireに接続

[こちらの記事](/entries/854)と同様に、 https://github.com/making/demo-gemfire のサンプルアプリからGemfireに接続してみます。ソースコードはGithubを参照してください。

まずはgfshでRegionを作成します：

```bash
create region --name=Customers --type=PARTITION_PERSISTENT --redundant-copies=1
```

Tanzu Gemfire on Kubernetesでは自動的に次のdisk storeとpdxの設定が行われているので、追加設定なして`PARTITION_PERSISTENT`タイプのRegionでPDXを使用することができます。

```xml
    <disk-store name="pdxmetadata">
        <disk-dirs>
            <disk-dir>/data/pdxmetadata</disk-dir>
        </disk-dirs>
    </disk-store>
    <pdx read-serialized="true" persistent="true" disk-store-name="pdxmetadata"/>
```

デモアプリをK8s上にデプロイするために、https://github.com/stakater/application の汎用的なHelm Chartを使用します。

```bash
helm repo add stakater https://stakater.github.io/stakater-charts
```

Helm用のvaluesファイルを作成します。`env`に設定する内容は次のドキュメントを参考にしました。

* https://techdocs.broadcom.com/us/en/vmware-tanzu/data-solutions/tanzu-gemfire-on-kubernetes/2-5/gf-k8s/app-dev.html
* https://techdocs.broadcom.com/us/en/vmware-tanzu/data-solutions/tanzu-gemfire-on-kubernetes/2-5/gf-k8s/security-tls-security.html

```yaml
cat <<EOF > helm-values.yaml
---
applicationName: demo-gemfire
deployment:
  image:
    repository: ghcr.io/making/demo-gemfire
    tag: jvm
    pullPolicy: Always
  ports:
  - name: http
    containerPort: 8080
    protocol: TCP
  env:
    gemfire.locators:
      value: demo-locator-0.demo-locator.demo.svc.cluster.local:10334,demo-locator-1.demo-locator.demo.svc.cluster.local:10334
    gemfire.properties.ssl-enabled-components:
      value: all
    gemfire.properties.ssl-endpoint-identification-enabled:
      value: "true"
    gemfire.properties.ssl-keystore:
      value: /certs/truststore.p12
    gemfire.properties.ssl-keystore-password:
      valueFrom:
        secretKeyRef:
          name: demo-cert
          key: password
    gemfire.properties.ssl-truststore:
      value: /certs/keystore.p12
    gemfire.properties.ssl-truststore-password:
      valueFrom:
        secretKeyRef:
          name: demo-cert
          key: password
  volumeMounts:
    cert-volume:
      mountPath: /certs
  volumes:
    cert-volume:
      secret:
        secretName: demo-cert
  resources:
    limits:
      cpu:
      memory: 768Mi
    requests:
      cpu:
      memory: 768Mi
  livenessProbe:
    enabled: true
    httpGet:
      path: /actuator/health/liveness
      port: 8080
      scheme: HTTP
  readinessProbe:
    enabled: true
    httpGet:
      path: /actuator/health/readiness
      port: 8080
      scheme: HTTP
  containerSecurityContext:
    allowPrivilegeEscalation: false
    capabilities:
      drop:
      - ALL
    readOnlyRootFilesystem: false
    runAsNonRoot: true
    runAsUser: 1002
    seccompProfile:
      type: RuntimeDefault
  affinity:
    podAntiAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - podAffinityTerm:
          labelSelector:
            matchLabels:
              app.kubernetes.io/part-of: demo-gemfire
          topologyKey: kubernetes.io/hostname
        weight: 1
ingress:
  enabled: true
  annotations:
    projectcontour.io/tls-cert-namespace: projectcontour
  hosts:
  - host: demo-gemfire.lan.ik.am
    paths:
    - path: /
      pathType: Prefix
  tls:
  - hosts:
    - demo-gemfire.lan.ik.am
    secretName: default-tls
---
EOF
```

> [!NOTE]
> この`helm-values.yaml`を使って次の`helm template`コマンドで生成されるYAMLは https://gist.github.com/making/3d32b0ac35ece4ac7f3ef70f168e58f2 です。
>
> ```bash
> helm template demo-gemfire stakater/application -n demo -f helm-values.yaml
> ```

次のコマンドでデプロイします：

```bash
helm upgrade --install demo-gemfire stakater/application -n demo -f helm-values.yaml --wait
```

Ingressに設定したドメイン（この例では`https://demo-gemfire.lan.ik.am`）にアクセスすると、次の画面が表示されます：

![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1852/30faf48a-c5dc-4c4e-b6e4-098b504e01ae.png)

適当に顧客情報を登録します。

![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1852/ceb8b86b-fb20-44fe-9072-94f0f149df8f.png)

![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1852/15c63a87-cac7-4bd0-913d-abafb14ae03c.png)

UI上に登録した顧客情報が表示されます。gfshで確認しても、登録した顧客情報がRegionに保存されていることがわかります：


```bash
gfsh>query --query="SELECT * FROM /Customers"
Result : true
Limit  : 100
Rows   : 2

id | name
-- | -------------
2  | Ichiro Suzuki
1  | Taro Yamada
```

### 外部のJavaアプリからGemFireに接続

すでに`gfsh`でGemFireに接続できることを確認していますが、外部のJavaアプリからも同様にGemFireに接続できます。
クラスタ外のJavaアプリからGemfireにアクセスするにはSNI Proxyを使用する必要があります。

[こちらのドキュメント](https://techdocs.broadcom.com/us/en/vmware-tanzu/data-solutions/tanzu-gemfire-on-kubernetes/2-5/gf-k8s/off_platform.html)に説明されていますが、このGateway APIを使う方法は、Contourがすでにインストールされている環境では採用しづらいため、今回はContourのHTTPProxyの[TLS Session Passthrough](https://projectcontour.io/docs/1.32/config/tls-termination/#tls-session-passthrough)を使います。

なお、このドキュメントのコードに従って、デモアプリは[SNI Proxy対応済み](https://github.com/making/demo-gemfire/commit/4f57bf87519ce906e41ce7051181efa63664393f)です。

既存のGemFireクラスターに対して、SNI Proxyを設定するための次のHTTPProxyを作成します。LocatorからアクセスすべきServerの情報がクラスタ内部のホスト名で返ってくるため、Locatorだけでなく、ServerのHTTPProxyをインスタンス単位で作成する必要があります。

```yaml
cat <<EOF > /tmp/sni-proxy.yaml
---
apiVersion: projectcontour.io/v1
kind: HTTPProxy
metadata:
  name: demo-locator-0
  namespace: demo
spec:
  virtualhost:
    fqdn: demo-locator-0.demo-locator.demo.svc.cluster.local
    tls:
      passthrough: true
  tcpproxy:
    services:
    - name: demo-locator-0
      port: 10334
---
apiVersion: projectcontour.io/v1
kind: HTTPProxy
metadata:
  name: demo-locator-1
  namespace: demo
spec:
  virtualhost:
    fqdn: demo-locator-1.demo-locator.demo.svc.cluster.local
    tls:
      passthrough: true
  tcpproxy:
    services:
    - name: demo-locator-1
      port: 10334
---
apiVersion: projectcontour.io/v1
kind: HTTPProxy
metadata:
  name: demo-server-0
  namespace: demo
spec:
  virtualhost:
    fqdn: demo-server-0.demo-server.demo.svc.cluster.local
    tls:
      passthrough: true
  tcpproxy:
    services:
    - name: demo-server-0
      port: 40404
---
apiVersion: projectcontour.io/v1
kind: HTTPProxy
metadata:
  name: demo-server-1
  namespace: demo
spec:
  virtualhost:
    fqdn: demo-server-1.demo-server.demo.svc.cluster.local
    tls:
      passthrough: true
  tcpproxy:
    services:
    - name: demo-server-1
      port: 40404
---
apiVersion: projectcontour.io/v1
kind: HTTPProxy
metadata:
  name: demo-server-2
  namespace: demo
spec:
  virtualhost:
    fqdn: demo-server-2.demo-server.demo.svc.cluster.local
    tls:
      passthrough: true
  tcpproxy:
    services:
    - name: demo-server-2
      port: 40404
---
EOF

kubectl apply -f /tmp/sni-proxy.yaml
```

全てのHTTPProxyの状態が`valid`になっていることを確認します。

```bash
$ kubectl get httpproxy -n demo
NAME                          FQDN                                                 TLS SECRET                   STATUS   STATUS DESCRIPTION
demo-locator-0                demo-locator-0.demo-locator.demo.svc.cluster.local                                valid    Valid HTTPProxy
demo-locator-1                demo-locator-1.demo-locator.demo.svc.cluster.local                                valid    Valid HTTPProxy
demo-locator-management-api   demo-locator.lan.ik.am                               projectcontour/default-tls   valid    Valid HTTPProxy
demo-server-0                 demo-server-0.demo-server.demo.svc.cluster.local                                  valid    Valid HTTPProxy
demo-server-1                 demo-server-1.demo-server.demo.svc.cluster.local                                  valid    Valid HTTPProxy
demo-server-2                 demo-server-2.demo-server.demo.svc.cluster.local                                  valid    Valid HTTPProxy
```

EnvoyのIPアドレスとポートを確認します。ここでは`192.168.11.240`および`443`です。JavaアプリからはこのIPアドレスとポートをSNI ProxyとしてGemFireに接続し、ホスト名はK8sクラスタ内と同じものを使用します。

```bash
$ kubectl get svc -n projectcontour 
NAME            TYPE           CLUSTER-IP       EXTERNAL-IP      PORT(S)                      AGE
contour         ClusterIP      10.152.183.197   <none>           8001/TCP                     79m
contour-envoy   LoadBalancer   10.152.183.23    192.168.11.240   80:31496/TCP,443:31967/TCP   79m
```

クラスタ外のJavaアプリとして`ghcr.io/making/demo-gemfire:jvm`のコンテナイメージをDockerから使用します。
以下のコマンドでGemFireの証明書を取得し、アプリケーションの実行に必要なファイルを作成します。

```bash
mkdir certs
kubectl get secret -n demo demo-cert -o=template='{{index .data "password" | base64decode}}' > ./certs/password
kubectl get secret -n demo demo-cert -o=template='{{index .data "keystore.p12" | base64decode}}' > ./certs/keystore.p12
kubectl get secret -n demo demo-cert -o=template='{{index .data "truststore.p12" | base64decode}}' > ./certs/truststore.p12
```

次のプロパティを設定してアプリケーションを起動します。

```bash
export CERT_PASSWORD=$(cat ./certs/password)

docker run \
  --rm \
  --name demo-gemfire \
  --pull always \
  -p 8080:8080 \
  -v $(pwd)/certs:/certs \
  -e gemfire.locators=demo-locator-0.demo-locator.demo.svc.cluster.local:10334,demo-locator-1.demo-locator.demo.svc.cluster.local:10334 \
  -e gemfire.sni-proxy.host=192.168.11.240 \
  -e gemfire.sni-proxy.port=443 \
  -e gemfire.properties.ssl-enabled-components=all \
  -e gemfire.properties.ssl-endpoint-identification-enabled=true \
  -e gemfire.properties.ssl-keystore=/certs/keystore.p12 \
  -e gemfire.properties.ssl-keystore-password=${CERT_PASSWORD} \
  -e gemfire.properties.ssl-truststore=/certs/truststore.p12 \
  -e gemfire.properties.ssl-truststore-password=${CERT_PASSWORD} \
  ghcr.io/making/demo-gemfire:jvm
```

起動に少し時間がかかりましたが、アプリケーションが起動します。起動しない場合は、Contourの設定がおかしい可能性があります。

```
  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/

 :: Spring Boot ::                (v3.5.3)

2025-06-24T03:30:18.821Z  INFO 1 --- [demo-gemfire] [           main] am.ik.demo.DemoGemfireApplication        : Starting DemoGemfireApplication v0.0.1.6bcdb85dc79968717e19d67d0de88335e9e5e9ef using Java 21.0.7 with PID 1 (/workspace/BOOT-INF/classes started by cnb in /workspace)
2025-06-24T03:30:18.822Z  INFO 1 --- [demo-gemfire] [           main] am.ik.demo.DemoGemfireApplication        : No active profile set, falling back to 1 default profile: "default"
2025-06-24T03:30:19.263Z  INFO 1 --- [demo-gemfire] [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port 8080 (http)
2025-06-24T03:30:19.268Z  INFO 1 --- [demo-gemfire] [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2025-06-24T03:30:19.268Z  INFO 1 --- [demo-gemfire] [           main] o.apache.catalina.core.StandardEngine    : Starting Servlet engine: [Apache Tomcat/10.1.42]
2025-06-24T03:30:19.278Z  INFO 1 --- [demo-gemfire] [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2025-06-24T03:30:19.279Z  INFO 1 --- [demo-gemfire] [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 434 ms
2025-06-24T03:30:19.525Z  INFO 1 --- [demo-gemfire] [           main] o.a.g.l.internal.LoggingProviderLoader   : Using org.apache.geode.logging.internal.SimpleLoggingProvider for service org.apache.geode.logging.internal.spi.LoggingProvider
2025-06-24T03:30:19.554Z  INFO 1 --- [demo-gemfire] [           main] o.a.g.internal.InternalDataSerializer    : initializing InternalDataSerializer with 4 services
2025-06-24T03:30:19.555Z  INFO 1 --- [demo-gemfire] [           main] o.a.g.i.s.f.SanctionedSerializables      : loaded 43 sanctioned serializables from ManagementSanctionedSerializablesService
2025-06-24T03:30:19.558Z  INFO 1 --- [demo-gemfire] [           main] o.a.g.i.s.f.SanctionedSerializables      : loaded 462 sanctioned serializables from CoreSanctionedSerializablesService
2025-06-24T03:30:19.559Z  INFO 1 --- [demo-gemfire] [           main] o.a.g.i.s.f.SanctionedSerializables      : loaded 6 sanctioned serializables from SerializationSanctionedSerializablesService
2025-06-24T03:30:19.559Z  INFO 1 --- [demo-gemfire] [           main] o.a.g.i.s.f.SanctionedSerializables      : loaded 0 sanctioned serializables from MembershipSanctionedSerializablesService
2025-06-24T03:30:19.571Z  INFO 1 --- [demo-gemfire] [           main] org.apache.geode                         : [ThreadsMonitor] New Monitor object and process were created.

2025-06-24T03:30:19.582Z  INFO 1 --- [demo-gemfire] [    StatSampler] o.a.g.i.statistics.StatArchiveHandler    : Disabling statistic archival.
2025-06-24T03:30:19.616Z  INFO 1 --- [demo-gemfire] [           main] o.a.g.internal.cache.GemFireCacheImpl    : Running in client mode
2025-06-24T03:30:19.635Z  INFO 1 --- [demo-gemfire] [           main] o.a.g.internal.cache.GemFireCacheImpl    : Initialized cache service org.apache.geode.cache.query.internal.QueryConfigurationServiceImpl
2025-06-24T03:30:59.827Z  INFO 1 --- [demo-gemfire] [           main] i.n.f.FileWatchingX509ExtendedKeyManager : Initialized KeyManager for /certs/keystore.p12
2025-06-24T03:30:59.829Z  INFO 1 --- [demo-gemfire] [           main] o.a.g.i.n.filewatch.PollingFileWatcher   : Started watching /certs/keystore.p12
2025-06-24T03:30:59.831Z  INFO 1 --- [demo-gemfire] [           main] n.f.FileWatchingX509ExtendedTrustManager : Initialized TrustManager for /certs/truststore.p12
2025-06-24T03:30:59.831Z  INFO 1 --- [demo-gemfire] [           main] o.a.g.i.n.filewatch.PollingFileWatcher   : Started watching /certs/truststore.p12
2025-06-24T03:30:59.839Z  INFO 1 --- [demo-gemfire] [           main] o.a.g.c.c.i.AutoConnectionSourceImpl     : AutoConnectionSource UpdateLocatorListTask started with interval=10000 ms.
2025-06-24T03:30:59.842Z  INFO 1 --- [demo-gemfire] [           main] o.a.g.cache.client.internal.PoolImpl     : Pool DEFAULT started with multiuser-authentication=false
2025-06-24T03:31:00.098Z  INFO 1 --- [demo-gemfire] [Timer-DEFAULT-2] o.a.g.c.c.i.AutoConnectionSourceImpl     : online locators was 0 and is now 2
2025-06-24T03:31:10.156Z  INFO 1 --- [demo-gemfire] [Timer-DEFAULT-4] org.apache.geode                         : Updating membership port.  Port changed from 0 to 43084.  ID is now 1b9f0b56148a(1:loner):0:2f93fc9f
2025-06-24T03:31:39.983Z  INFO 1 --- [demo-gemfire] [           main] o.s.b.a.w.s.WelcomePageHandlerMapping    : Adding welcome page: class path resource [META-INF/resources/index.html]
2025-06-24T03:31:40.120Z  INFO 1 --- [demo-gemfire] [           main] o.s.b.a.e.web.EndpointLinksResolver      : Exposing 1 endpoint beneath base path '/actuator'
2025-06-24T03:31:40.157Z  INFO 1 --- [demo-gemfire] [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port 8080 (http) with context path '/'
2025-06-24T03:31:40.164Z  INFO 1 --- [demo-gemfire] [           main] am.ik.demo.DemoGemfireApplication        : Started DemoGemfireApplication in 81.507 seconds (process running for 81.635)
```

アプリケーションが起動したら、ブラウザで`http://localhost:8080`にアクセスします。Gemfire上の既存のデータが表示されるはずです。

![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1852/ecd04060-3c4c-403d-b67e-1dbe3e8eb6ea.png)

データの追加ももちろんできます。

![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1852/e22d1890-0d7e-4bfa-a8ff-2894d835337c.png)

K8sクラスタの外からもGemFireに接続できることが確認できました。

### クリーンアップ

アプリケーションを削除します。

```bash
helm delete -n demo demo-gemfire --wait
```

GemFireClusterを削除します。

```bash
kubectl delete -f /tmp/demo-gemfire.yaml -n demo
kubectl delete -f /tmp/demo-locator-management-api.yaml -n demo
```

GemFire OperatorとCRDを削除します。

```bash
helm delete -n gemfire-system gemfire-operator --wait
helm delete -n gemfire-system gemfire-crd --wait
```

---

Tanzu GemFire on Kubernetesのインストールと、Javaアプリケーションからの接続までの一連の流れを紹介しました。GemFire Operatorを使用することで、Kubernetes上でのGemFireクラスターの管理が容易になり、アプリケーション開発者はGemFireの機能を簡単に利用できるようになります。
デフォルトでTLSが有効になっているため、セキュリティも強化されて、プロダクションで使う場合に安心です。
