Manually deploy a Java application with Open Liberty or WebSphere Liberty on an Azure Kubernetes Service (AKS) cluster
This article provides step-by-step manual guidance for running Open/WebSphere Liberty on Azure.
Specifically, this article explains how to accomplish the following tasks:
- Run your Java, Java EE, Jakarta EE, or MicroProfile application on the Open Liberty or WebSphere Liberty runtime.
- Build the application Docker image using Liberty container images.
- Deploy the containerized application to an Azure Kubernetes Service (AKS) cluster using the Liberty Operator.
The Liberty Operator simplifies the deployment and management of applications running on Kubernetes clusters. With the Open Liberty Operator or WebSphere Liberty Operator, you can also perform more advanced operations, such as gathering traces and dumps.
For a more automated solution that accelerates your journey to AKS, see Deploy a Java application with Open Liberty/WebSphere Liberty on an Azure Kubernetes Service (AKS) cluster.
For more information on Open Liberty, see the Open Liberty project page. For more information on IBM WebSphere Liberty, see the WebSphere Liberty product page.
This article is intended to help you quickly get to deployment. Before going to production, you should explore Tuning Liberty.
If you're interested in providing feedback or working closely on your migration scenarios with the engineering team developing WebSphere on Azure solutions, fill out this short survey on WebSphere migration and include your contact information. The team of program managers, architects, and engineers will promptly get in touch with you to initiate close collaboration.
Prerequisites
- An Azure subscription. If you don't have an Azure subscription, create a free account before you begin.
- Prepare a local machine with Windows, macOS, or Linux installed.
- Install the Azure CLI 2.31.0 or above to run Azure CLI commands.
- Sign in with Azure CLI by using the az login command. To finish the authentication process, follow the steps displayed in your terminal. See Sign into Azure with Azure CLI for other sign-in options.
- When you're prompted, install the Azure CLI extension on first use. For more information about extensions, see Use and manage extensions with the Azure CLI.
- Run az version to find the version and dependent libraries that are installed. To upgrade to the latest version, run az upgrade.
- Install a Java Standard Edition (SE) implementation, version 17 or later (for example, Eclipse Open J9).
- Install Maven version 3.5.0 or later.
- Install Docker for your OS.
- Ensure that Git is installed.
- Make sure you're assigned either the
Owner
role or theContributor
andUser Access Administrator
roles in the subscription. You can verify the assignment by following the steps in List Azure role assignments using the Azure portal.
Sign in to Azure
If you didn't do so already, sign in to your Azure subscription by using the az login command and follow the on-screen directions.
az login
Note
You can run most Azure CLI commands in PowerShell the same as in Bash. The difference exists only when using variables. In the following sections, the difference is addressed in different tabs when needed.
If you have multiple Azure tenants associated with your Azure credentials, you must specify which tenant you want to sign in to. You can do this with the --tenant
option. For example, az login --tenant contoso.onmicrosoft.com
.
Create a resource group
An Azure resource group is a logical group in which Azure resources are deployed and managed.
Create a resource group called java-liberty-project using the az group create command in the eastus location. This resource group is used later for creating the Azure Container Registry (ACR) instance and the AKS cluster.
export RESOURCE_GROUP_NAME=java-liberty-project
az group create --name $RESOURCE_GROUP_NAME --location eastus
Create an ACR instance
Use the az acr create command to create the ACR instance. The following example creates an ACR instance named youruniqueacrname. Make sure youruniqueacrname is unique within Azure.
export REGISTRY_NAME=youruniqueacrname
az acr create \
--resource-group $RESOURCE_GROUP_NAME \
--name $REGISTRY_NAME \
--sku Basic \
--admin-enabled
After a short time, you should see a JSON output that contains the following lines:
"provisioningState": "Succeeded",
"publicNetworkAccess": "Enabled",
"resourceGroup": "java-liberty-project",
Connect to the ACR instance
You need to sign in to the ACR instance before you can push an image to it. Use the following commands to verify the connection:
export LOGIN_SERVER=$(az acr show \
--name $REGISTRY_NAME \
--query 'loginServer' \
--output tsv)
export USER_NAME=$(az acr credential show \
--name $REGISTRY_NAME \
--query 'username' \
--output tsv)
export PASSWORD=$(az acr credential show \
--name $REGISTRY_NAME \
--query 'passwords[0].value' \
--output tsv)
docker login $LOGIN_SERVER -u $USER_NAME -p $PASSWORD
You should see Login Succeeded
at the end of command output if you're logged into the ACR instance successfully.
Create an AKS cluster
Use the az aks create command to create an AKS cluster. The following example creates a cluster named myAKSCluster with one node. This command takes several minutes to complete.
export CLUSTER_NAME=myAKSCluster
az aks create \
--resource-group $RESOURCE_GROUP_NAME \
--name $CLUSTER_NAME \
--node-count 1 \
--generate-ssh-keys \
--enable-managed-identity
After a few minutes, the command completes and returns JSON-formatted information about the cluster, including the following output:
"nodeResourceGroup": "MC_java-liberty-project_myAKSCluster_eastus",
"privateFqdn": null,
"provisioningState": "Succeeded",
"resourceGroup": "java-liberty-project",
Connect to the AKS cluster
To manage a Kubernetes cluster, you use kubectl, the Kubernetes command-line client. To install kubectl
locally, use the az aks install-cli command, as shown in the following example:
az aks install-cli
To configure kubectl
to connect to your Kubernetes cluster, use the az aks get-credentials command. This command downloads credentials and configures the Kubernetes CLI to use them.
az aks get-credentials \
--resource-group $RESOURCE_GROUP_NAME \
--name $CLUSTER_NAME \
--overwrite-existing \
--admin
Note
The above command uses the default location for the Kubernetes configuration file, which is ~/.kube/config
. You can specify a different location for your Kubernetes configuration file using --file
.
To verify the connection to your cluster, use the kubectl get command to return a list of the cluster nodes.
kubectl get nodes
The following example output shows the single node created in the previous steps. Make sure that the status of the node is Ready:
NAME STATUS ROLES AGE VERSION
aks-nodepool1-xxxxxxxx-yyyyyyyyyy Ready agent 76s v1.23.8
Create an Azure SQL Database
In this section, you create an Azure SQL Database single database for use with your app.
Create a single database in Azure SQL Database by following the Azure CLI or PowerShell steps in Quickstart: Create an Azure SQL Database single database. Use the following directions as you go through the article, then return to this document after you create and configure the database server.
When you reach the Set parameter values section of the quickstart, copy and save aside the values of all variables in the code example labeled
Variable block
, includinglocation
,resourceGroup
,database
,server
,login
, andpassword
. This article refers to the databaseresourceGroup
as<db-resource-group>
.After you create the database server, go to the newly created server in the Azure portal. In the Networking pane, under the Connectivity tab, set the Minimum TLS version to TLS 1.0.
In the Networking pane, under the Public access tab, select Allow Azure services and resources to access this server.
If you want to test the application locally, ensure your client IPv4 address is in the allowlist of Firewall rules
Save your networking changes.
Use the following command to create an environment variable for the resource group name for the database:
export DB_RESOURCE_GROUP_NAME=<db-resource-group>
Now that you created the database and AKS cluster, you can prepare AKS to host Liberty.
Install Open Liberty Operator
After creating and connecting to the cluster, install the Open Liberty Operator.
Install the Open Liberty Operator by running the following commands:
# Install cert-manager Operator
CERT_MANAGER_VERSION=v1.11.2
kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/${CERT_MANAGER_VERSION}/cert-manager.yaml
# Install Open Liberty Operator
export OPERATOR_VERSION=1.2.2
mkdir -p overlays/watch-all-namespaces
wget https://raw.githubusercontent.com/OpenLiberty/open-liberty-operator/main/deploy/releases/${OPERATOR_VERSION}/kustomize/overlays/watch-all-namespaces/olo-all-namespaces.yaml -q -P ./overlays/watch-all-namespaces
wget https://raw.githubusercontent.com/OpenLiberty/open-liberty-operator/main/deploy/releases/${OPERATOR_VERSION}/kustomize/overlays/watch-all-namespaces/cluster-roles.yaml -q -P ./overlays/watch-all-namespaces
wget https://raw.githubusercontent.com/OpenLiberty/open-liberty-operator/main/deploy/releases/${OPERATOR_VERSION}/kustomize/overlays/watch-all-namespaces/kustomization.yaml -q -P ./overlays/watch-all-namespaces
mkdir base
wget https://raw.githubusercontent.com/OpenLiberty/open-liberty-operator/main/deploy/releases/${OPERATOR_VERSION}/kustomize/base/kustomization.yaml -q -P ./base
wget https://raw.githubusercontent.com/OpenLiberty/open-liberty-operator/main/deploy/releases/${OPERATOR_VERSION}/kustomize/base/open-liberty-crd.yaml -q -P ./base
wget https://raw.githubusercontent.com/OpenLiberty/open-liberty-operator/main/deploy/releases/${OPERATOR_VERSION}/kustomize/base/open-liberty-operator.yaml -q -P ./base
wget https://raw.githubusercontent.com/OpenLiberty/open-liberty-operator/main/deploy/releases/${OPERATOR_VERSION}/kustomize/base/open-liberty-roles.yaml -q -P ./base
kubectl create namespace open-liberty
kubectl apply --server-side -k overlays/watch-all-namespaces
Configure and build the application image
To deploy and run your Liberty application on the AKS cluster, containerize your application as a Docker image using Open Liberty container images or WebSphere Liberty container images.
Follow the steps in this section to deploy the sample application on the Liberty runtime. These steps use Maven.
Check out the application
Clone the sample code for this guide. The sample is on GitHub. There are a few samples in the repository. This article uses java-app. Here's the file structure of the application.
git clone https://github.com/Azure-Samples/open-liberty-on-aks.git
cd open-liberty-on-aks
git checkout 20230830
If you see a message about being in "detached HEAD" state, this message is safe to ignore. It just means you checked out a tag.
java-app
├─ src/main/
│ ├─ aks/
│ │ ├─ db-secret.yaml
│ │ ├─ openlibertyapplication.yaml
│ ├─ docker/
│ │ ├─ Dockerfile
│ │ ├─ Dockerfile-wlp
│ ├─ liberty/config/
│ │ ├─ server.xml
│ ├─ java/
│ ├─ resources/
│ ├─ webapp/
├─ pom.xml
The directories java, resources, and webapp contain the source code of the sample application. The code declares and uses a data source named jdbc/JavaEECafeDB
.
In the aks directory, there are two deployment files. db-secret.xml is used to create Kubernetes Secrets with database connection credentials. The file openlibertyapplication.yaml is used to deploy the application image. In the docker directory, there are two files to create the application image with either Open Liberty or WebSphere Liberty.
In directory liberty/config, the server.xml is used to configure the database connection for the Open Liberty and WebSphere Liberty cluster.
Build the project
Now that you gathered the necessary properties, you can build the application. The POM file for the project reads many variables from the environment. As part of the Maven build, these variables are used to populate values in the YAML files located in src/main/aks. You can do something similar for your application outside Maven if you prefer.
cd <path-to-your-repo>/java-app
# The following variables are used for deployment file generation into target/
export LOGIN_SERVER=${LOGIN_SERVER}
export REGISTRY_NAME=${REGISTRY_NAME}
export USER_NAME=${USER_NAME}
export PASSWORD=${PASSWORD}
export DB_SERVER_NAME=<Server name>.database.windows.net
export DB_NAME=<Database name>
export DB_USER=<Server admin login>@<Server name>
export DB_PASSWORD=<Server admin password>
mvn clean install
(Optional) Test your project locally
You can now run and test the project locally before deploying to Azure. For convenience, use the liberty-maven-plugin
. To learn more about the liberty-maven-plugin
, see Building a web application with Maven. For your application, you can do something similar using any other mechanism such as your local IDE. You can also consider using the liberty:devc
option intended for development with containers. You can read more about liberty:devc
in the Liberty docs.
Note
If you selected a "serverless" database deployment, verify that your SQL database has not entered pause mode. One way to do this is to log in to the database query editor as described in Quickstart: Use the Azure portal query editor (preview) to query Azure SQL Database.
Start the application using
liberty:run
.liberty:run
uses the environment variables defined in the previous step.cd <path-to-your-repo>/java-app mvn liberty:run
Verify the application works as expected. You should see a message similar to
[INFO] [AUDIT] CWWKZ0003I: The application javaee-cafe updated in 1.930 seconds.
in the command output if successful. Go tohttp://localhost:9080/
in your browser to verify the application is accessible and all functions are working.Press Ctrl+C to stop.
Build the image for AKS deployment
You can now run the docker buildx build
command to build the image, as shown in the following example:
cd <path-to-your-repo>/java-app/target
# If you are running with Open Liberty
docker buildx --platform linux/amd64 build -t javaee-cafe:v1 --pull --file=Dockerfile .
# If you are running with WebSphere Liberty
docker buildx --platform linux/amd64 build -t javaee-cafe:v1 --pull --file=Dockerfile-wlp .
(Optional) Test the Docker image locally
You can now use the following steps to test the Docker image locally before deploying to Azure.
Run the image using the following command. This command uses the environment variables defined previously.
docker run -it --rm -p 9080:9080 \ -e DB_SERVER_NAME=${DB_SERVER_NAME} \ -e DB_NAME=${DB_NAME} \ -e DB_USER=${DB_USER} \ -e DB_PASSWORD=${DB_PASSWORD} \ javaee-cafe:v1
After the container starts, go to
http://localhost:9080/
in your browser to access the application.Press Ctrl+C to stop.
Upload the image to ACR
Next, upload the built image to the ACR you created in the previous steps.
If you didn't already do so, sign in to the container registry by using the following command:
docker login -u ${USER_NAME} -p ${PASSWORD} ${LOGIN_SERVER}
Use the following commands to tag and push the container image:
docker tag javaee-cafe:v1 ${LOGIN_SERVER}/javaee-cafe:v1
docker push ${LOGIN_SERVER}/javaee-cafe:v1
Deploy the application to the AKS cluster
Use the following steps to deploy the Liberty application on the AKS cluster:
Attach the ACR instance to the AKS cluster so that the AKS cluster is authenticated to pull image from the ACR instance, as shown in the following example:
az aks update \ --resource-group $RESOURCE_GROUP_NAME \ --name $CLUSTER_NAME \ --attach-acr $REGISTRY_NAME
Apply the database secret and deployment file by running the following commands:
cd <path-to-your-repo>/java-app/target # Apply database secret kubectl apply -f db-secret.yaml # Apply deployment file kubectl apply -f openlibertyapplication.yaml
Determine whether the
OpenLibertyApplication
instance is created by running the following command:kubectl get openlibertyapplication javaee-cafe-cluster
You should see output similar to the following example:
NAME IMAGE EXPOSED RECONCILED AGE javaee-cafe-cluster youruniqueacrname.azurecr.io/javaee-cafe:1.0.25 True 59s
Determine whether the deployment created by the Operator is ready by running the following command:
kubectl get deployment javaee-cafe-cluster --watch
You should see output similar to the following example:
NAME READY UP-TO-DATE AVAILABLE AGE javaee-cafe-cluster 0/3 3 0 20s
Wait until you see
3/3
under theREADY
column and3
under theAVAILABLE
column, then use Ctrl+C to stop thekubectl
watch process.
Test the application
When the application runs, a Kubernetes load balancer service exposes the application front end to the internet. This process can take a while to complete.
To monitor progress, use the kubectl get service command with the --watch
argument, as shown in the following example:
kubectl get service javaee-cafe-cluster --watch
You should see output similar to the following example:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
javaee-cafe-cluster LoadBalancer 10.0.251.169 52.152.189.57 80:31732/TCP 68s
After the EXTERNAL-IP address changes from pending to an actual public IP address, use Ctrl+C to stop the kubectl
watch process.
If some time passed between executing the steps in this section and the preceding one, ensure the database is active, if necessary. See the previous note regarding database pause.
Open a web browser to the external IP address of your service (52.152.189.57
for the above example) to see the application home page. If the page isn't loaded correctly, that's because the app is starting. You can wait for a while and refresh the page later. You should see the pod name of your application replicas displayed at the top-left of the page. Wait for a few minutes and refresh the page to see a different pod name displayed due to load balancing provided by the AKS cluster.
Note
Currently, the application doesn't use HTTPS. We recommend that you enable TLS with your own certificates. For more information, see Use TLS with an ingress controller on Azure Kubernetes Service (AKS).
Clean up resources
To avoid Azure charges, you should clean up unnecessary resources. When the cluster is no longer needed, use the az group delete command to remove the resource group, container service, container registry, database, and all related resources.
az group delete --name $RESOURCE_GROUP_NAME --yes --no-wait
az group delete --name $DB_RESOURCE_GROUP_NAME --yes --no-wait
Next steps
You can learn more from references used in this guide:
- Azure Kubernetes Service
- Open Liberty
- Open Liberty Operator
- Open Liberty Server Configuration
- Liberty Maven Plugin
- Open Liberty Container Images
- WebSphere Liberty Container Images
To incorporate Azure Cache for Redis into a Java app, see Use Azure Cache for Redis in Java with Redisson Redis client.
To explore options to run WebSphere products on Azure, see What are solutions to run the WebSphere family of products on Azure?