WebSphere Application in Kubernetes

Yaroslav Novytskyy
5 min readApr 18, 2022

You might find yourself in a situation where a legacy java application built to run on WebSphere needs to be migrated to Kubernetes. One of the options is to containerize it but keep it on WebSphere at the same time. This can be an interim step on your modernization journey to mitigate the risks related to the size and complexity of the application and to withhold from the code changes needed to take it off of WebSphere.

While the other, more aggressive modernization approach, would be to run the app as a standalone (e.g. Spring Boot JAR) application in a container, the described modernization step has it’s benefits:
- smaller and more controlled scope of change (aka baby-steps);
- no code change to the application;
- no change to the runtime platform.

Your app on WebSphere in a container

The first great thing is that IBM provides official images of containerized WebSphere of versions 8.5.x and 9.0.x that are an obvious choice for base image:

Not diving into how to build new container images based on an existing image — it’s widely accessible knowledge on the internet. Plus there’s a well-described examples specific to the websphere-traditional image in the GitHub repo that is used to build the image itself:

I suggest basing your application on the example in the ./samples/hello-world folder of the above repo. One important place to note is the install_app.py file — it gets copied in Dockerfile and then it is executed during the build of the image, so that the resulting image has WebSphere with the app installed, and the needed configuration applied.

The examples and solutions below are built on top of that same hello-world sample.

WAS VirtualHost and port mappings

IBM WebSphere, similar to HTTP servers like Apache or Nginx, has a built-in concept of virtual hosts that allows colocation of multiple web-application on one instance of WAS mapped to different hostnames, ports, and/or context paths.

The ibmcom/websphere-traditional WebSphere image comes preconfigured with the following configuration for default_host and admin_host virtual hosts:

+---------------------+---------------------+
| default_host | admin_host |
+--------------+------+--------------+------+
| Host Name | Port | Host Name | Port |
+--------------+------+--------------+------+
| * | 9080 | * | 9060 |
| * | 80 | * | 9043 |
| * | 9443 | | |
| * | 5060 | | |
| * | 5061 | | |
| * | 443 | | |
+--------------+------+--------------+------+

On the other hand, in Kubernetes, mapping ports to different values across layers (e.g. container to pod, to service, to ingress, or load balancer) is a very routine thing to do. Sometimes, as with NodePort, you might not be able to choose the needed port to match the VirtualHost configuration. Or you want your WAS-based app to be functional on a port that is not planned upfront. Kubernetes gives you this flexibility, but not with WebSphere’s VirtualHost preconfigured by default:

Once you access your app on a port that does not match the port configured to serve by the virtual host configuration (even though it is correctly mapped to the port that is configured to be handled by VirtualHost), your requests won’t be served and you’ll see the following error:

SRVE0255E: A WebGroup/Virtual Host to handle / has not been defined.
SRVE0255E: A WebGroup/Virtual Host to handle localhost:30080 has not been defined.

To make a WAS-based app work in a way, where it does not differentiate which port/hostname it was accessed by, add the following to the install_app.py file that configures WebSphere and the application during the build of the image:

default_host = AdminConfig.getid('/VirtualHost:default_host/')AdminConfig.modify(default_host, [['aliases', [[['port', '*'], ['hostname', '*']]]]])AdminConfig.save()

This adds * to the ports handled by default_host under which your app is served by default. This routs requests to your app regardless of which port it was requested on — and that’s what you’d expect from a microservice.

Extending trust

Many times your app needs to trust SSL certificates that are signed by in-house certificate authorities that are not in the default trust store. In such a case, I find it cleaner to import such certificates into WebSphere’s trust store rather than Java’s — keeps things cleaner by customizing the least generic level of runtime. Prepare a certificate file and add the following to your Dockerfile :

COPY --chown=was:root company_root.cer /work/config/RUN /opt/IBM/WebSphere/AppServer/java/8.0/bin/keytool \
-noprompt -storetype PKCS12 -storepass WebAS \
-keystore \ /opt/IBM/WebSphere/AppServer/profiles/AppSrv01/config/cells/DefaultCell01/nodes/DefaultNode01/trust.p12 \
-import -file /work/config/company_root.cer \
-alias company_root

More WebSphere configuration

If you found yourself in a similar modernization situation when you still don’t fully decouple from WebSphere, your application might still be coupled with some WebSphere-specific features. Until you refactor your app to take it off of WebSphere, you need to code this configuration to be applied during the build of the image.

Containers are ephemeral — configuring WebSphere in container manually in runtime is not an option.

Examples of such configuration might include Dynamic SSL configuration, JNDI bindings, IBM MQ config, custom JVM arguments, etc. Luckily, most of these tasks can be accomplished in install_app.py with AdminTask , AdminConfig and AdminApp objects. IBM has fairly good documentation on coding configuration in Jython. You can start by Googling “Automating SSL configurations using scripting” or AdminTask.createSSLConfig and follow the pattern.

Productivity tip for IBM Console password

Just a tip for the R&D phase. WAS password is regenerated in each image build, it might come useful to add the following to your Dockerfile :

RUN echo "*** WAS Console password ***" && cat /tmp/PASSWORD

While not a big deal, it will save you time on many occasions when needed to log into WAS to check/experiment on WebSphere’s configuration while working with this setup in development environments.

Happy modernization!

--

--