Skip to content

Commit c89d127

Browse files
authored
Initial Infinispan support as a JCache provider. (#331)
1 parent 221ad41 commit c89d127

File tree

5 files changed

+159
-20
lines changed

5 files changed

+159
-20
lines changed

README.md

+83-20
Original file line numberDiff line numberDiff line change
@@ -111,26 +111,89 @@ For security related configuration see [SECURITY.md](SECURITY.md).
111111

112112
### Session Caching
113113

114-
The Liberty session caching feature builds on top of an existing technology called JCache (JSR 107), which provides an API for distributed in-memory caching. There are several providers of JCache implementations. One example is [Hazelcast In-Memory Data Grid](https://hazelcast.org/). Enabling Hazelcast session caching retrieves the Hazelcast client libraries from the [hazelcast/hazelcast](https://hub.docker.com/r/hazelcast/hazelcast/) Docker image, configures Hazelcast by copying a sample [hazelcast.xml](ga/latest/kernel/helpers/build/configuration_snippets/), and configures the Liberty server feature [sessionCache-1.0](https://www.ibm.com/support/knowledgecenter/en/SSEQTP_liberty/com.ibm.websphere.wlp.doc/ae/twlp_admin_session_persistence_jcache.html) by including the XML snippet [hazelcast-sessioncache.xml](ga/latest/kernel/helpers/build/configuration_snippets/hazelcast-sessioncache.xml). By default, the [Hazelcast Discovery Plugin for Kubernetes](https://github.com/hazelcast/hazelcast-kubernetes) will auto-discover its peers within the same Kubernetes namespace. To enable this functionality, the Docker image author can include the following Dockerfile snippet, and choose from either client-server or embedded [topology](https://docs.hazelcast.org/docs/latest-development/manual/html/Hazelcast_Overview/Hazelcast_Topology.html).
115-
116-
```dockerfile
117-
### Hazelcast Session Caching ###
118-
# Copy the Hazelcast libraries from the Hazelcast Docker image
119-
COPY --from=hazelcast/hazelcast --chown=1001:0 /opt/hazelcast/lib/*.jar /opt/ibm/wlp/usr/shared/resources/hazelcast/
120-
121-
# Instruct configure.sh to copy the client topology hazelcast.xml
122-
ARG HZ_SESSION_CACHE=client
123-
124-
# Default setting for the verbose option
125-
ARG VERBOSE=false
126-
127-
# Instruct configure.sh to copy the embedded topology hazelcast.xml and set the required system property
128-
#ARG HZ_SESSION_CACHE=embedded
129-
#ENV JAVA_TOOL_OPTIONS="-Dhazelcast.jcache.provider.type=server ${JAVA_TOOL_OPTIONS}"
130-
131-
## This script will add the requested XML snippets and grow image to be fit-for-purpose
132-
RUN configure.sh
133-
```
114+
The Liberty session caching feature builds on top of an existing technology called JCache (JSR 107), which provides an API for distributed in-memory caching. There are several providers of JCache implementations. The configuration for two such providers, Infinispan and Hazelcast, are outlined below.
115+
116+
1. **Infinispan(Beta Feature)** - One JCache provider is the open source project [Infinispan](https://infinispan.org/), which is the basis for Red Hat Data Grid. Enabling Infinispan session caching retrieves the Infinispan client libraries from the [Infinispan JCACHE (JSR 107) Remote Implementation](https://mvnrepository.com/artifact/org.infinispan/infinispan-jcache-remote) maven repository, and configures the necessary infinispan.client.hotrod.* properties and the Liberty server feature [sessionCache-1.0](https://www.ibm.com/support/knowledgecenter/en/SSEQTP_liberty/com.ibm.websphere.wlp.doc/ae/twlp_admin_session_persistence_jcache.html) by including the XML snippet [infinispan-client-sessioncache.xml](/releases/latest/kernel/helpers/build/configuration_snippets/infinispan-client-sessioncache.xml).
117+
118+
* **Setup Infinispan Service** - Configuring Liberty session caching with Infinispan depends on an Infinispan service being available in your Kubernetes environment. It is preferable to create your Infinispan service by utilizing the [Infinispan Operator](https://infinispan.org/infinispan-operator/master/operator.html). The [Infinispan Operator Tutorial](https://github.com/infinispan/infinispan-simple-tutorials/tree/master/operator) provides a good example of getting started with Infinispan in OpenShift.
119+
120+
* **Install Client Jars and Set INFINISPAN_SERVICE_NAME** - To enable Infinispan functionality in Liberty, the Docker image author can use the Dockerfile provided below. This Dockerfile assumes an Infinispan service name of `example-infinispan`, which is the default used in the [Infinispan Operator Tutorial](https://github.com/infinispan/infinispan-simple-tutorials/tree/master/operator). To customize your Infinispan service see [Creating Infinispan Clusters](https://infinispan.org/infinispan-operator/master/operator.html#creating_minimal_clusters-start). The `INFINISPAN_SERVICE_NAME` environment variable must be set at build time as shown in the example Dockerfile, or overridden at image deploy time.
121+
* **TIP** - If your Infinispan deployment and Liberty deployment are in different namespaces/projects, you will need to set the `INFINISPAN_HOST`, `INFINISPAN_PORT`, `INFINISPAN_USER`, and `INFINISPAN_PASS` environment variables in addition to the `INFINISPAN_SERVICE_NAME` environment variable. This is due to the Liberty deployment not having the access to the Infinispan service environment variables it requires.
122+
123+
```dockerfile
124+
### Infinispan Session Caching ###
125+
FROM ibmcom/websphere-liberty:kernel-java8-openj9-ubi AS infinispan-client
126+
127+
# Install Infinispan client jars
128+
USER root
129+
RUN infinispan-client-setup.sh
130+
USER 1001
131+
132+
FROM ibmcom/websphere-liberty:kernel-java8-openj9-ubi AS open-liberty-infinispan
133+
134+
# Copy Infinispan client jars to Open Liberty shared resources
135+
COPY --chown=1001:0 --from=infinispan-client /opt/ibm/wlp/usr/shared/resources/infinispan /opt/ibm/wlp/usr/shared/resources/infinispan
136+
137+
# Instruct configure.sh to use Infinispan for session caching.
138+
# This should be set to the Infinispan service name.
139+
# TIP - Run the following oc/kubectl command with admin permissions to determine this value:
140+
# oc get infinispan -o jsonpath={.items[0].metadata.name}
141+
ENV INFINISPAN_SERVICE_NAME=example-infinispan
142+
143+
# Uncomment and set to override auto detected values.
144+
# These are normally not needed if running in a Kubernetes environment.
145+
# One such scenario would be when the Infinispan and Liberty deployments are in different namespaces/projects.
146+
#ENV INFINISPAN_HOST=
147+
#ENV INFINISPAN_PORT=
148+
#ENV INFINISPAN_USER=
149+
#ENV INFINISPAN_PASS=
150+
151+
# This script will add the requested XML snippets and grow image to be fit-for-purpose
152+
RUN configure.sh
153+
```
154+
155+
* **Mount Infinispan Secret** - Finally, the Infinispan generated secret must be mounted as a volume under the mount point of `/platform/bindings/secret/` on Liberty containers. The default location of `/platform/bindings/secret/` can to be overridden by setting the `LIBERTY_INFINISPAN_SECRET_DIR` environment variable. When using the Infinispan Operator, this secret is automatically generated as part of the Infinispan service with the name of `<INFINISPAN_CLUSTER_NAME>-generated-secret`. For the mounting of this secret to succeed, the Infinispan Operator and Liberty must share the same namespace. If they do not share the same namespace, the `INFINISPAN_HOST`, `INFINISPAN_PORT`, `INFINISPAN_USER`, and `INFINISPAN_PASS` environment variables can be used instead(see the dockerfile example above). For an example of mounting this secret, review the `volumes` and `volumeMounts` portions of the YAML below.
156+
157+
```yaml
158+
...
159+
spec:
160+
volumes:
161+
- name: infinispan-secret-volume
162+
secret:
163+
secretName: example-infinispan-generated-secret
164+
containers:
165+
- name: servera-container
166+
image: ol-runtime-infinispan-client:1.0.0
167+
ports:
168+
- containerPort: 9080
169+
volumeMounts:
170+
- name: infinispan-secret-volume
171+
readOnly: true
172+
mountPath: "/config/liberty-infinispan-secret"
173+
...
174+
175+
```
176+
177+
2. **Hazelcast** - Another JCache provider is [Hazelcast In-Memory Data Grid](https://hazelcast.org/). Enabling Hazelcast session caching retrieves the Hazelcast client libraries from the [hazelcast/hazelcast](https://hub.docker.com/r/hazelcast/hazelcast/) Docker image, configures Hazelcast by copying a sample [hazelcast.xml](/releases/latest/kernel/helpers/build/configuration_snippets/), and configures the Liberty server feature [sessionCache-1.0](https://www.ibm.com/support/knowledgecenter/en/SSEQTP_liberty/com.ibm.websphere.wlp.doc/ae/twlp_admin_session_persistence_jcache.html) by including the XML snippet [hazelcast-sessioncache.xml](/releases/latest/kernel/helpers/build/configuration_snippets/hazelcast-sessioncache.xml). By default, the [Hazelcast Discovery Plugin for Kubernetes](https://github.com/hazelcast/hazelcast-kubernetes) will auto-discover its peers within the same Kubernetes namespace. To enable this functionality, the Docker image author can include the following Dockerfile snippet, and choose from either client-server or embedded [topology](https://docs.hazelcast.org/docs/latest-dev/manual/html-single/#hazelcast-topology).
178+
179+
```dockerfile
180+
### Hazelcast Session Caching ###
181+
# Copy the Hazelcast libraries from the Hazelcast Docker image
182+
COPY --from=hazelcast/hazelcast --chown=1001:0 /opt/hazelcast/lib/*.jar /opt/ibm/wlp/usr/shared/resources/hazelcast/
183+
184+
# Instruct configure.sh to copy the client topology hazelcast.xml
185+
ARG HZ_SESSION_CACHE=client
186+
187+
# Default setting for the verbose option
188+
ARG VERBOSE=false
189+
190+
# Instruct configure.sh to copy the embedded topology hazelcast.xml and set the required system property
191+
#ARG HZ_SESSION_CACHE=embedded
192+
#ENV JAVA_TOOL_OPTIONS="-Dhazelcast.jcache.provider.type=server ${JAVA_TOOL_OPTIONS}"
193+
194+
## This script will add the requested XML snippets and grow image to be fit-for-purpose
195+
RUN configure.sh
196+
```
134197

135198
### Applying interim fixes
136199

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<server>
2+
<featureManager>
3+
<feature>sessionCache-1.0</feature>
4+
</featureManager>
5+
<httpSessionCache libraryRef="InfinispanLib">
6+
<properties infinispan.client.hotrod.server_list="${INFINISPAN_HOST}:${INFINISPAN_PORT}"/>
7+
<properties infinispan.client.hotrod.marshaller="org.infinispan.commons.marshall.JavaSerializationMarshaller"/>
8+
<properties infinispan.client.hotrod.java_serial_whitelist=".*"/>
9+
<properties infinispan.client.hotrod.auth_username="${INFINISPAN_USER}"/>
10+
<properties infinispan.client.hotrod.auth_password="${INFINISPAN_PASS}"/>
11+
<properties infinispan.client.hotrod.auth_realm="default"/>
12+
<properties infinispan.client.hotrod.sasl_mechanism="DIGEST-MD5"/>
13+
<properties infinispan.client.hotrod.auth_server_name="infinispan"/>
14+
</httpSessionCache>
15+
<httpSessionCache enableBetaSupportForInfinispan="true"/> <!-- TODO remove once no longer gated -->
16+
<library id="InfinispanLib">
17+
<fileset dir="${shared.resource.dir}/infinispan" includes="*.jar"/>
18+
</library>
19+
</server>

ga/latest/kernel/helpers/build/configure.sh

+5
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,11 @@ then
5555
cp ${SNIPPETS_SOURCE}/hazelcast-${HZ_SESSION_CACHE}.xml ${SHARED_CONFIG_DIR}/hazelcast/hazelcast.xml
5656
fi
5757

58+
# Infinispan Session Caching
59+
if [[ -n "$INFINISPAN_SERVICE_NAME" ]]; then
60+
cp ${SNIPPETS_SOURCE}/infinispan-client-sessioncache.xml ${SNIPPETS_TARGET}/infinispan-client-sessioncache.xml
61+
chmod g+rw $SNIPPETS_TARGET/infinispan-client-sessioncache.xml
62+
fi
5863
# IIOP Endpoint
5964
if [ "$IIOP_ENDPOINT" == "true" ]; then
6065
if [ "$SSL" == "true" ] || [ "$TLS" == "true" ]; then
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#!/bin/bash
2+
if [ "$VERBOSE" != "true" ]; then
3+
exec &>/dev/null
4+
fi
5+
6+
set -Eeox pipefail
7+
8+
yum update -y
9+
yum install -y maven
10+
mkdir -p /opt/ibm/wlp/usr/shared/resources/infinispan
11+
echo '<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>io.openliberty</groupId> <artifactId>openliberty-infinispan-client</artifactId> <version>1.0</version> <!-- https://mvnrepository.com/artifact/org.infinispan/infinispan-jcache-remote --> <dependencies> <dependency> <groupId>org.infinispan</groupId> <artifactId>infinispan-jcache-remote</artifactId> <version>10.1.3.Final</version> </dependency> </dependencies></project>' > /opt/ibm/wlp/usr/shared/resources/infinispan/pom.xml
12+
mvn -f /opt/ibm/wlp/usr/shared/resources/infinispan/pom.xml versions:use-latest-releases -DallowMajorUpdates=false
13+
mvn -f /opt/ibm/wlp/usr/shared/resources/infinispan/pom.xml dependency:copy-dependencies -DoutputDirectory=/opt/ibm/wlp/usr/shared/resources/infinispan
14+
yum remove -y maven
15+
rm -f /opt/ibm/wlp/usr/shared/resources/infinispan/pom.xml
16+
rm -f /opt/ibm/wlp/usr/shared/resources/infinispan/jboss-transaction-api*.jar
17+
rm -f /opt/ibm/wlp/usr/shared/resources/infinispan/reactive-streams-*.jar
18+
rm -f /opt/ibm/wlp/usr/shared/resources/infinispan/rxjava-*.jar
19+
rm -rf ~/.m2
20+
chown -R 1001:0 /opt/ibm/wlp/usr/shared/resources/infinispan
21+
chmod -R g+rw /opt/ibm/wlp/usr/shared/resources/infinispan
22+

ga/latest/kernel/helpers/runtime/docker-server.sh

+30
Original file line numberDiff line numberDiff line change
@@ -88,5 +88,35 @@ keystorePath="$SNIPPETS_TARGET_DEFAULTS/keystore.xml"
8888

8989
importKeyCert
9090

91+
# Infinispan Session Caching
92+
if [[ -n "$INFINISPAN_SERVICE_NAME" ]]; then
93+
echo "INFINISPAN_SERVICE_NAME(original): ${INFINISPAN_SERVICE_NAME}"
94+
INFINISPAN_SERVICE_NAME=$(echo ${INFINISPAN_SERVICE_NAME} | sed 's/-/_/g' | sed 's/./\U&/g')
95+
echo "INFINISPAN_SERVICE_NAME(normalized): ${INFINISPAN_SERVICE_NAME}"
96+
97+
if [[ -z "$INFINISPAN_HOST" ]]; then
98+
eval INFINISPAN_HOST=\$${INFINISPAN_SERVICE_NAME}_SERVICE_HOST
99+
export INFINISPAN_HOST
100+
fi
101+
echo "INFINISPAN_HOST: ${INFINISPAN_HOST}"
102+
103+
if [[ -z "$INFINISPAN_PORT" ]]; then
104+
eval INFINISPAN_PORT=\$${INFINISPAN_SERVICE_NAME}_SERVICE_PORT
105+
export INFINISPAN_PORT
106+
fi
107+
echo "INFINISPAN_PORT: ${INFINISPAN_PORT:=11222}"
108+
109+
if [[ -z "$INFINISPAN_USER" ]]; then
110+
export INFINISPAN_USER=$(cat ${LIBERTY_INFINISPAN_SECRET_DIR:=/platform/bindings/secret}/identities.yaml | grep -m 1 username | sed 's/username://' | sed 's/[[:space:]]*//g' | sed 's/^-//')
111+
fi
112+
echo "INFINISPAN_USER: ${INFINISPAN_USER:=developer}"
113+
114+
if [[ -z "$INFINISPAN_PASS" ]]; then
115+
export INFINISPAN_PASS=$(cat ${LIBERTY_INFINISPAN_SECRET_DIR:=/platform/bindings/secret}/identities.yaml | grep -m 1 password | sed 's/password://' | sed 's/[[:space:]]*//g')
116+
fi
117+
echo "INFINISPAN_PASS: ${INFINISPAN_PASS}"
118+
fi
119+
120+
91121
# Pass on to the real server run
92122
exec "$@"

0 commit comments

Comments
 (0)