This is part of a 2-part blog series about clustering in Red Hat JBoss Enterprise Application Platform (JBoss EAP) 7 and JBoss EAP 8 in Red Hat OpenShift 4. In the 1st part of this series, we examined how to configure DNS_PING for JBoss EAP on OpenShift.
In part 2, we explore the JGroups KUBE_PING discovery protocol, examine how it queries the Kubernetes API directly, compare setup differences between JBoss EAP 7 and JBoss EAP 8, and troubleshoot common permissions and syntax pitfalls.
JBoss EAP clustering in OpenShift: KUBE_PING discovery
When JBoss EAP 7 is deployed in Red Hat OpenShift Container Platform, the JBoss EAP 7 image has clustering capabilities enabled by default. To enable clustering, JBoss EAP 7 relies on JGroups discovery protocols (also known as ping protocols), such as DNS_PING or KUBE_PING, to connect pods.
The 1st article described how to enable DNS_PING, which is not enabled by default on the JBoss EAP 7 image and must be configured manually or built from a template. It drew from knowledge in EAP 7 DNS_PING tracing logs in OCP 4EAP 7 DNS_PING tracing logs in OCP 4. On the other hand, this 2nd article focuses on KUBE_PING, a JGroups protocol that queries the Kubernetes API rather than DNS, and draws on solutions I previously wrote: Custom build EAP 8 image is not abiding by default JVM settings and JBoss EAP KUBE_PING clustering in OpenShift Container Platform. Both articles draw from the main article: EAP 7 image clustering in OCP 4, which provides extensive and detailed guidance on clustering in general for JBoss EAP in containers.
The following table summarizes DNS_PING and KUBE_PING discovery protocols:
| Discovery protocol | Supported versions |
|---|---|
openshift.DNS_PING | Deprecated in JBoss EAP 7.2 and removed in JBoss EAP 7.3 |
dns.DNS_PING | JBoss EAP 7.3 and later |
openshift.KUBE_PING | Replaced with kubernetes.KUBE_PING |
kubernetes.KUBE_PING | JBoss EAP 7.4 and later |
For more technical details on kubernetes.KUBE_PING, see the jgroups-kubernetes GitHub repository.
By default, clustering with KUBE_PING requires additional permissions: the default deployment service account must have permission to view pods in the namespace.
When deploying JBoss EAP 7, template settings default to JGROUPS_PING_PROTOCOL=dns.DNS_PING, which does not require additional service account permissions. However, the default JBoss EAP 7 container image is configured to use KUBE_PING.
You can set OPENSHIFT_DNS_PING_SERVICE_NAME to a unique value to prevent cluster formation. (Clustering remains enabled, but individual pods or deployments cannot see other members.)
Setting OPENSHIFT_KUBE_PING_NAMESPACE to an arbitrary value merely prevents pods from finding each other; however, it does not strip clustering out of the runtime. To remove clustering entirely in JBoss EAP 7, you must remove it from standalone-openshift.xml; in JBoss EAP 8, exclude the clustering layer when provisioning with Galleon.
As explained in the JGroups GitHub documentation, KUBE_PING queries the Kubernetes API for pod IP addresses, then filters them by namespace and labels. After gathering the IP addresses, the protocol establishes TCP connections using the configured ports and port range. The following example shows the core configuration:
<TCP
bind_addr="loopback,match-interface:eth0"
bind_port="7800"
...
/>
<org.jgroups.protocols.kubernetes.KUBE_PING
port_range="1"
namespace="${KUBERNETES_NAMESPACE:production}"
labels="${KUBERNETES_LABELS:cluster=nyc}"
/>To use KUBE_PING, configure the following environment variables:
JGROUPS_PING_PROTOCOL: Sets the protocol tokubernetes.KUBE_PING.KUBERNETES_NAMESPACE: Specifies the OpenShift namespace.KUBERNETES_LABELS: Specifies the label selector used to identify application pods.
These settings provide the essential configuration for KUBE_PING: once JBoss EAP has the protocol, pod namespace, and labels, discovery functions properly.
How KUBE_PING discovery works in Kubernetes
Before diving into deployment manifests, let's examine how KUBE_PING identifies nodes at the API layer.
KUBE_PING queries the Kubernetes API directly to identify active pod IP addresses matching your application labels, establishing peer-to-peer TCP connections without requiring a dedicated headless service for discovery.
Because Kubernetes manages pod orchestration, it maintains the IP addresses of all running pods, making it the central authority for cluster discovery. JGroups performs discovery by querying the Kubernetes API server for the IP addresses of all cluster member pods.
If you use the JBoss EAP 7 operator, it automatically injects the necessary environment variables and RBAC rules into your deployment specification.
Demonstration: Deploying JBoss EAP 8 with Helm charts
Deploying JBoss EAP 8 requires building with Galleon using Helm charts rather than templates:
| EAP | Deployment option | Deployment in JBoss EAP operator |
|---|---|---|
| JBoss EAP 7 | Template; brings DNS_PING by default | JBoss EAP operator 2; brings default image settings: KUBE_PING |
| JBoss EAP 8 | Helm charts; brings DNS_PING by default | JBoss EAP Operator 3; brings default image settings: KUBE_PING |
Recap of DNS_PING for JBoss EAP 8
In JBoss EAP 8, the container image is unprovisioned, which means you must build the image with the specific subsystems required for clustering. As a result, clustering is not enabled by default.
######
###################################################### Value file:
######
$ cat custom-helm-clustering.yaml
build:
uri: https://github.com/jboss-developer/jboss-eap-quickstarts.git
ref: 8.0.x
contextDir: helloworld
env:
- name: MAVEN_OPTS_APPEND
value: '-XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=256m' <-------------- Maven settings
- name: GALLEON_PROVISION_FEATURE_PACKS
value: 'org.jboss.eap:wildfly-ee-galleon-pack, org.jboss.eap.cloud:eap-cloud-galleon-pack'
- name: GALLEON_PROVISION_LAYERS
value: 'cloud-default-config' <----------------------- Provision layers
- name: GALLEON_PROVISION_CHANNELS
value: 'org.jboss.eap.channels:eap-8.0'
deploy:
replicas: 3
######
###################################################### Repo:
######
$ helm repo update jboss-eap
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "jboss-eap" chart repository
Update Complete. ⎈Happy Helming!⎈
### Run your install command again
$ helm install --debug helloworld3 -f helm-galleon.yaml jboss-eap/eap8
########
###################################################### Install
########
$ helm install --debug helloworld3 -f helm-galleon.yaml jboss-eap/eap8
install.go:225: 2026-07-16 18:25:07.276904056 -0400 EDT m=+0.031065003 [debug] Original chart version: ""
install.go:242: 2026-07-16 18:25:07.846243348 -0400 EDT m=+0.600404315 [debug] CHART PATH: /home/path/.cache/helm/repository/eap8-1.1.3.tgz
client.go:144: 2026-07-16 18:25:09.650575152 -0400 EDT m=+2.404736149 [debug] creating 8 resource(s)
NAME: helloworld3
LAST DEPLOYED: Thu Jul 16 18:25:08 2026
NAMESPACE: eap-helm
STATUS: deployed
REVISION: 1
TEST SUITE: None
USER-SUPPLIED VALUES:
build:
contextDir: helloworld
env:
- name: MAVEN_OPTS
value: -XX:MetaspaceSize=251m -XX:MaxMetaspaceSize=256m
ref: 8.0.x
s2i:
channels: org.jboss.eap.channels:eap-8.0
featurePacks: org.jboss.eap.cloud:eap-cloud-galleon-pack
galleonLayers: cloud-default-config
version: 1
uri: https://github.com/jboss-developer/jboss-eap-quickstarts.git
deploy:
env:
- name: JAVA_OPTS_APPEND
value: -XX:MetaspaceSize=251m -XX:MaxMetaspaceSize=256m
replicas: 4
COMPUTED VALUES:
build:
contextDir: helloworld
enabled: true
env:
- name: MAVEN_OPTS
value: -XX:MetaspaceSize=251m -XX:MaxMetaspaceSize=256m
mode: s2i
output:
kind: ImageStreamTag
ref: 8.0.x
s2i:
buildApplicationImage: true
channels: org.jboss.eap.channels:eap-8.0
featurePacks: org.jboss.eap.cloud:eap-cloud-galleon-pack
###
### Get the replicas
###
$ oc get pod
NAME READY STATUS RESTARTS AGE
helloworld3-2-build 0/1 Completed 0 65m
helloworld3-id1 1/1 Running 0 3m
helloworld3-id2 1/1 Running 0 3m
helloworld3-id3 1/1 Running 0 3m
helloworld3-id4 1/1 Running 0 17s
helloworld3-build-artifacts-1-build 0/1 Completed 0 69mWhen deployed in this manner, the default Helm chart configuration—similar to JBoss EAP 7 template deployments—uses DNS_PING:
23:34:08,366 INFO [org.jboss.as.clustering.jgroups] (ServerService Thread Pool -- 78) WFLYCLJG0032: Connecting 'ee' channel. 'helloworld3-68db97fd5c-4nbbd' joining cluster 'ee' via /IP:7600
23:34:08,366 INFO [org.jgroups.JChannel] (ServerService Thread Pool -- 78) local_addr: 44123bb2-a0d7-473d-b561-a1808c657958, name: helloworld3-68db97fd5c-4nbbd
23:34:08,376 INFO [org.jgroups.protocols.FD_SOCK2] (ServerService Thread Pool -- 78) server listening on /IP:57600
23:34:08,467 INFO [org.jboss.as.clustering.jgroups] (ServerService Thread Pool -- 78) WFLYCLJG0033: Connected 'ee' channel. 'helloworld3-68db97fd5c-4nbbd' joined cluster 'ee' with view: [helloworld3-68db97fd5c-jz5wt|3] (4) [helloworld3-68db97fd5c-jz5wt, helloworld3-68db97fd5c-gqx9z, helloworld3-68db97fd5c-pcv9d, helloworld3-68db97fd5c-4nbbd]
...
23:34:09,173 INFO [org.infinispan.LIFECYCLE] (thread-15,ee,helloworld3-68db97fd5c-4nbbd) [Context=org.infinispan.CONFIG] ISPN100002: Starting rebalance with members [helloworld3-68db97fd5c-jz5wt, helloworld3-68db97fd5c-gqx9z, helloworld3-68db97fd5c-pcv9d, helloworld3-68db97fd5c-4nbbd], phase READ_OLD_WRITE_ALL, topology id 10
...
...
###
$ oc rsh helloworld3-id4
$ cat /opt/eap/standalone/configuration/standalone.xml | grep -b10 -a10 jgroups
...
25194- <stack name="tcp">
25229: <transport type="TCP" socket-binding="jgroups-tcp"/>
25302- <protocol type="dns.DNS_PING">
25353- <property name="dns_query">helloworld3-ping</property>
25432- <property name="async_discovery_use_separate_thread_per_request">true</property>
25537- </protocol>Configuring KUBE_PING for JBoss EAP 8
To deploy with KUBE_PING, configure the 3 environment variables discussed earlier:
JGROUPS_PING_PROTOCOL: Sets the protocol tokubernetes.KUBE_PING.KUBERNETES_NAMESPACE: Specifies the OpenShift namespace containing the target pods.KUBERNETES_LABELS: Passes labels directly to the Kubernetes label selector query parameter.
Next, define these environment variables in your Helm values file:
###
### Helm chart value
###
$ cat helm-kube-ping.yaml
build:
uri: https://github.com/jboss-developer/jboss-eap-quickstarts.git
ref: 8.0.x
contextDir: helloworld
env:
- name: MAVEN_OPTS
value: '-XX:MetaspaceSize=251m -XX:MaxMetaspaceSize=252m'
s2i:
version: 1
featurePacks: org.jboss.eap.cloud:eap-cloud-galleon-pack
galleonLayers: cloud-default-config
channels: org.jboss.eap.channels:eap-8.0
deploy:
replicas: 4
env:
- name: JAVA_OPTS_APPEND
value: -XX:MetaspaceSize=253m -XX:MaxMetaspaceSize=254m
- name: JGROUPS_PING_PROTOCOL
value: kubernetes.KUBE_PING
- name: KUBERNETES_NAMESPACE
value: eap-helm
- name: KUBERNETES_LABELS
value: eapTo deploy the application, run the following commands::
#########################################################
######################################################### Install
$ helm install --debug helloworld -f helm-galleon.yaml jboss-eap/eap8
###
######################################################### Permissions == Service Account
###
$ oc create rolebinding eap-kube-ping-binding \
--clusterrole=view \
--serviceaccount=eap-helm:default \
-n eap-helm
rolebinding.rbac.authorization.k8s.io/eap-kube-ping-binding created
###
######################################################### Labels
###
$ oc set env deployment/helloworld KUBERNETES_LABELS="app.openshift.io/runtime=eap"
deployment.apps/helloworld updatedThe following output shows a complete, successful startup log:
00:17:34,665 INFO [org.jgroups.protocols.kubernetes.KUBE_PING] (ServerService Thread Pool -- 78) namespace eap-helm set; clustering enabled
00:17:34,711 INFO [org.jboss.as.clustering.jgroups] (ServerService Thread Pool -- 78) WFLYCLJG0032: Connecting 'ee' channel. 'helloworld-5dc858f98b-5ldjd' joining cluster 'ee' via /IP:7600
00:17:34,712 INFO [org.jgroups.JChannel] (ServerService Thread Pool -- 78) local_addr: fb969e30-d7e7-4727-94c7-5e275ec0e0d8, name: helloworld-5dc858f98b-5ldjd
00:17:34,720 INFO [org.jgroups.protocols.FD_SOCK2] (ServerService Thread Pool -- 78) server listening on /IP:57600
00:17:37,871 WARN [org.jgroups.protocols.kubernetes.KUBE_PING] (ServerService Thread Pool -- 78) failed getting JSON response from Kubernetes Client[masterUrl=https://172.30.0.1:443/api/v1, headers={Authorization=#MASKED:1524#}, connectTimeout=5000, readTimeout=30000, operationAttempts=3, operationSleep=1000, streamProvider=org.jgroups.protocols.kubernetes.stream.TokenStreamProvider@32702a6] for cluster [ee], namespace [eap-helm], labels [eap]; encountered [java.lang.Exception: 3 attempt(s) with a 1000ms sleep to execute [OpenStream] failed. Last failure was [java.io.IOException: Server returned HTTP response code: 403 for URL: https://172.30.0.1:443/api/v1/namespaces/eap-helm/pods?labelSelector=eap]]
00:17:39,872 INFO [org.jgroups.protocols.pbcast.GMS] (ServerService Thread Pool -- 78) helloworld-5dc858f98b-5ldjd: no members discovered after 5150 ms: creating cluster as coordinator
00:17:39,878 INFO [org.jboss.as.clustering.jgroups] (ServerService Thread Pool -- 78) WFLYCLJG0033: Connected 'ee' channel. 'helloworld-5dc858f98b-5ldjd' joined cluster 'ee' with view: [helloworld-5dc858f98b-5ldjd|0] (1) [helloworld-5dc858f98b-5ldjd]
00:17:40,154 INFO [org.infinispan.CONTAINER] (ServerService Thread Pool -- 82) ISPN000556: Starting user marshaller 'org.wildfly.clustering.infinispan.marshall.InfinispanProtoStreamMarshaller'
...
01:08:40,361 INFO [org.infinispan.CLUSTER] (thread-14,ee,helloworld-8676499675-8jrqr) [Context=org.infinispan.CONFIG] ISPN100002: Starting rebalance with members [helloworld-8676499675-8jrqr, helloworld-8676499675-ddwvf, helloworld-8676499675-svjlg], phase READ_OLD_WRITE_ALL, topology id 6
01:08:40,468 INFO [org.infinispan.CLUSTER] (thread-12,ee,helloworld-8676499675-8jrqr) [Context=org.infinispan.CONFIG] ISPN100009: Advancing to rebalance phase READ_ALL_WRITE_ALL, topology id 7
...
01:08:40,979 INFO [org.infinispan.CLUSTER] (thread-14,ee,helloworld-8676499675-8jrqr) [Context=http-remoting-connector] ISPN100010: Finished rebalance with members [helloworld-id1, helloworld-id2, helloworld-id3, helloworld-id4], topology id 13 <---- 4 podsDeploying JBoss EAP 7 using Deployment and DeploymentConfig
Deploying with JBoss EAP 7 follows a similar process using kubernetes.KUBE_PING:
- Create a
DeploymentorDeploymentConfigresource. - Deploy the YAML configuration with the required environment variables and service account permissions.
- Deploy the clustered application.
- Verify that the cluster forms successfully.
Note
JBoss EAP 7 template deployments do not configure KUBE_PING by default from the base image.
Troubleshooting
The following log snippet confirms that the namespace is set and clustering is enabled:
00:25:19,829 INFO [org.jgroups.protocols.kubernetes.KUBE_PING] (ServerService Thread Pool -- 78) namespace eap-helm set; clustering enabled
00:25:19,943 INFO [org.jgroups.protocols.FD_SOCK2] (ServerService Thread Pool -- 78) server listening on /IP:57600Consider the following troubleshooting tips if issues arise:
Verify service account permissions. If the deployment's service account cannot inspect pods, the server logs an HTTP 403 error:
WARN Service account has insufficient permissions to view pods in kubernetes (HTTP 403). Clustering might be unavailable. Please refer to the documentation for configuration.Verify environment variable syntax. Extra quotes or formatting errors will prevent cluster formation:
00:53:00,613 WARN [org.jgroups.protocols.kubernetes.KUBE_PING] (ServerService Thread Pool -- 78) failed getting JSON response from Kubernetes Client[masterUrl=https://172.30.0.1:443/api/v1, headers={Authorization=#MASKED:1524#}, connectTimeout=5000, readTimeout=30000, operationAttempts=3, operationSleep=1000, streamProvider=org.jgroups.protocols.kubernetes.stream.TokenStreamProvider@68d6054c] for cluster [ee], namespace [eap-helm], labels ["app.openshift.io/runtime=eap"]; encountered [java.lang.Exception: 3 attempt(s) with a 1000ms sleep to execute [OpenStream] failed. Last failure was [java.io.IOException: Server returned HTTP response code: 400 for URL: https://172.30.0.1:443/api/v1/namespaces/eap-helm/pods?labelSelector=%22app.openshift.io%2Fruntime%3Deap%22]]- When upgrading Helm charts in JBoss EAP 8, verify that updated environment variables replace existing variables rather than creating duplicate entries.
Ensure that you specify the full protocol name as
kubernetes.KUBE_PINGrather thanKUBE_PING:00:11:59,691 INFO [org.jboss.as.repository] (ServerService Thread Pool -- 10) WFLYDR0001: Content added at location /opt/server/standalone/data/content/e7/00ce84bd3b83372c9ac6aabac9ed63c20334e1/content 00:11:59,709 ERROR [org.jboss.as.controller.management-operation] (ServerService Thread Pool -- 21) WFLYCTL0013: Operation ("add") failed - address: ([ ("subsystem" => "jgroups"), ("channel" => "ee") ]) - failure description: "WFLYCLJG0016: Unable to load protocol class org.jgroups.protocols.KUBE_PING" 00:11:59,710 ERROR [org.jboss.as.controller.management-operation] (Controller Boot Thread) "WFLYCTL0193: Failed executing subsystem jgroups boot operations" 00:11:59,711 ERROR [org.jboss.as.controller.management-operation] (Controller Boot Thread) WFLYCTL0013: Operation ("parallel-subsystem-boot") failed - address: ([]) - failure description: "\"WFLYCTL0193: Failed executing subsystem jgroups boot operations\""
The following list summarizes common clustering issues and their solutions:
Protocol loading error (WFLYCLJG0016): The protocol name is invalid. Set
JGROUPS_PING_PROTOCOLtokubernetes.KUBE_PING.Service account permissions error (HTTP 403): The default service account lacks permissions to view pods in the namespace. Grant the view role to the service account:
oc create rolebinding eap-kube-ping-binding --clusterrole=view --serviceaccount=eap-helm:default -n eap-helmMalformed label selector query (HTTP 400): Extra quotation marks (
%22) or spaces that encode colons as plus signs (+) invalidate the query. Set the variable correctly:oc set env deployment/helloworld KUBERNETES_LABELS="app.openshift.io/runtime=eap"Incorrect namespace (HTTP 403): The target namespace does not match the deployment. Update the namespace variable:
oc set env deployment/helloworld KUBERNETES_NAMESPACE=dg-test
FAQ
The following frequently asked questions address common considerations for JBoss EAP clustering:
What is the difference between the discovery protocols?
KUBE_PING queries the Kubernetes API server for pod IP addresses, whereas DNS_PING resolves pod IP addresses directly through DNS.
Why does KUBE_PING require namespace details?
The protocol queries pod IP addresses across the cluster, then uses the namespace and labels to filter which pods receive ping and join requests.
Do all JBoss EAP 8 Helm chart deployments enable clustering?
Clustering is available as long as you configure the appropriate Galleon layer, unlike JBoss EAP 7 where clustering is included by default. For KUBE_PING, you must also set 3 environment variables and configure service account permissions.
What is required to configure KUBE_PING in JBoss EAP 7 or JBoss EAP 8?
Configuring kubernetes.KUBE_PING requires service account permissions and 3 environment variables: JGROUPS_PING_PROTOCOL, KUBERNETES_NAMESPACE, and KUBERNETES_LABELS.
How do you disable clustering capabilities in JBoss EAP 7 and 8?
To disable clustering, use the method that corresponds to your JBoss EAP version and discovery protocol:
JBoss EAP 7
Because the builder image includes clustering capabilities by default (with Galleon used only for trimming), disabling clustering depends on your discovery protocol:
DNS_PING: SetOPENSHIFT_DNS_PING_SERVICE_PORTto an unused port or remove the headless service. This disables the DNS_PING protocol.KUBE_PING: SetOPENSHIFT_KUBE_PING_NAMESPACEto an unused namespace or configureKUBERNETES_LABELSwith non-matching labels. Omitting these variables causes the protocol to default to the current namespace.
JBoss EAP 8
Because Galleon provisions the runtime during the build process based on your selected layers, provision JBoss EAP 8 without clustering layers if clustering is not required.
Both versions (runtime override)
If the clustering subsystem is already present in your image, set LOCAL_PING as the discovery protocol to restrict discovery to the local process. Setting this environment variable provides a straightforward way to disable cross-pod clustering.
Conclusion
KUBE_PING provides a direct alternative to DNS_PING for establishing JBoss EAP clusters in Red Hat OpenShift 4. Whether deploying using templates (deprecated) or provisioning JBoss EAP 8 with Helm charts using Galleon layers, successful cluster discovery relies on precise environment variable configuration and appropriate RBAC permissions.
Configuring these environment variables ensures enterprise Java workloads form reliable, predictable clusters in Red Hat OpenShift without relying on DNS protocols.
Additional resources
For part 1, read Set up JBoss EAP 7 clustering in OpenShift using DNS_PING.
For foundational guidance, review EAP 7 and 8 image clustering in OpenShift 4 on the Red Hat Customer Portal.
Running into unexpected cluster behavior in your OpenShift environment? Contact Red Hat support for assistance with on JBoss EAP 8 and Red Hat OpenShift 4.
Special thanks to Dennis Reed, Jonathan Mason, and Wagner Queiroz for their collaboration on clustering over the last eight years. Zusammen.