WebSphere Application Server & Liberty

 View Only

Liberty InstantOn on Azure Kubernetes Service

By Tam Dinh posted 12 days ago


This blog will demonstrate how to deploy sample Open Liberty getting started application with InstantOn to Azure Kubernetes Service (AKS) using WebSphere Liberty Operator. The Liberty InstantOn is a new exciting feature which improves the Liberty startup time dramatically as described in new enhancements for Liberty InstantOn in blog.



  • Create AKS cluster and Azure container registry (ACR)
  • Create application checkpoint image and push to ACR
  • Install WebSphere Liberty Operator and deploy application checkpoint image to AKS

Create AKS cluster and Azure container registry 

We use Azure CLI az to create Azure container registry svtacr and AKS cluster svtCluster in svtrg resource group in southcentralus location as in the following script.  The  svtCluster and svtrg names will be used as examples through out this blog.  The variables section can be updated to have your location, resource group, cluster, and ARC names.  This script will create a small cluster with 2 nodes size Standard_D2s_v3 (2 vCPUs and 8 GiB memory) since we will run a small sample application.  The InstantOn feature requires Linux kernel 5.9 or higher so we are creating the cluster with Kubernetes version 1.25 which has the supported Linux kernel for InstantOn.  The --attach-acr flag in "az aks create" command will integrate the AKS cluster with ACR so that it will create the appropriate AcrPull role for the managed identity to allow the AKS cluster to pull image from ACR.

  • #!/usr/bin/env bash
    set -euo pipefail
    echo "Set variables"
    set -x
    echo "Create a resource group"
    az group create \
    	--name "$RESOURCEGROUP" \
    	--location "$LOCATION"
    echo "Create Azure container registry"
    az acr create \
        --resource-group "$RESOURCEGROUP" \
        --name $ACRNAME \
        --sku Basic
    echo "Create AKS cluster"
    az aks create \
        --resource-group "$RESOURCEGROUP" \
        --name "$CLUSTER" \
        --enable-managed-identity \
        --node-count "$NODECOUNT" \
        --node-vm-size "$NODESIZE" \
        --kubernetes-version "$KUBEVERSION" \
        --enable-addons monitoring \
        --generate-ssh-keys \
        --attach-acr $ACRNAME

Once the AKS cluster is done creating, you can login to the cluster and view its nodes, status, kernel level and AcrPull role.

    • Login svtCluster in svtrg resource group.  
      az aks get-credentials --resource-group svtrg --name svtCluster

    • View nodes to verify nodes ready status and kernel level.
      kubectl get nodes -o wide
      NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME aks-nodepool1-xxxxxxxx-vmss000000 Ready agent 16m v1.25.5 <none> Ubuntu 22.04.1 LTS 5.15.0-1033-azure containerd://1.6.17+azure-1 aks-nodepool1-xxxxxxxx-vmss000001 Ready agent 16m v1.25.5 <none> Ubuntu 22.04.1 LTS 5.15.0-1033-azure containerd://1.6.17+azure-1

    • Verify role in Azure container registry.
      az role assignment list --scope /subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/svtrg/providers/Microsoft.ContainerRegistry/registries/svtacr -o table
      Principal                             Role     Scope
      ------------------------------------  -------  --------------------------------------------------------------------------------------------------------------------------------
      xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx  AcrPull  /subscriptions/ xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx /resourceGroups/svtrg/providers/Microsoft.ContainerRegistry/registries/svtacr 

Create application checkpoint image and push the image to Azure container registry

We use sample Open Liberty getting started application to build application checkpoint image and push it to ACR.

    • Clone the application to local machine and build application WAR file.
      git clone https://github.com/openliberty/guide-getting-started.git
      cd guide-getting-started
      cd finish
      mvn package

    • Build application checkpoint image during container image build process.  Edit the Dockerfile to pull image from icr.io/appcafe/open-liberty:beta-instanton and add RUN checkpoint.sh applications as the last line in the Dockerfile.  This will create a checkpoint at applications phase during startup process.  The checkpoint.sh script takes either applications or deployments parameter to indicate during which phase to perform the checkpoint.  The --cap-add and --security-opt parameters in podman build are for granting necessary capabilities for the checkpoint process.  Here is an example of the Dockerfile
      FROM icr.io/appcafe/open-liberty:beta-instanton
      COPY --chown=1001:0 src/main/liberty/config/ /config/
      COPY --chown=1001:0 target/*.war /config/apps/
      RUN configure.sh
      RUN checkpoint.sh applications
    • Create getting-started-instanton checkpoint application image with podman build command
      podman build \
         -t getting-started-instanton \
         --cap-add=CHECKPOINT_RESTORE \
         --cap-add=SETPCAP \
         --security-opt seccomp=unconfined .

    • Authenticate with Azure container registry. 
      TOKEN=$(az acr login --name svtacr --expose-token --output tsv --query accessToken)
      podman login svtacr.azurecr.io -u 00000000-0000-0000-0000-000000000000 -p $TOKEN

    • Tag and push getting-started-instanton application image to Azure container registry svtacr  
      podman tag dev.local/getting-started-instanton svtacr.azurecr.io/getting-started-instanton
      podman push svtacr.azurecr.io/getting-started-instanton

    • Verify that the application image is in ACR. 
      az acr repository list --name svtacr --output table

Install WebSphere Liberty Operator (WLO) and deploy application checkpoint image to AKS

Before installing WLO, we will install cert-manager since WLO has transport layer security (TLS) enable by default.  Then we will install ingress and configure DNS record set so the application can be run with the ingress host.  There are multiple ways of installing WLO in Kubernetes, but we are going to use Kubernetes CLI kubectl to install WLO.  You can also deploy applications using Kubernetes deployment, but we choose to use WLO since it helps with deploying and managing Liberty applications on Kubernetes-based clusters.

    • Setting variables.  The values for RESOURCEGROUP and CLUSTER names must be the same as what were provided in the script to create AKS cluster.  APP_NS is the namespace where you want to deploy the application.
      export RESOURCEGROUP=svtrg
      export CLUSTER=svtCluster
      export APP_NS=ol-sample
      export CERT_MANAGER_VERSION=v1.11.0
      export WLO_VERSION=1.1.0
      Note: you need to login the AKS cluster before running the following steps.  We have already logged in the AKS cluster in the previous step.
    • Install cert-manger.  By default, it installs to cert-manager namespace. 
      kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/$CERT_MANAGER_VERSION/cert-manager.yaml


    • Install Nginx ingress.  By default, it installs to ingress-nginx namespace.
      kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/cloud/deploy.yaml

    • Get ingress public IP and add it to DNS record set.  Update the --resource-group and --zone-name to have for your subscription's zone name and resource group.  Record set name can be any name and we use svtaks. 
      ingress_ext_ip=`kubectl -n ingress-nginx get svc ingress-nginx-controller --no-headers |awk '{print $4}'`
      az network dns record-set a add-record \
          --resource-group <your_dns_zone_rg> \
          --zone-name "<your_dns_zone_name>" \
          --record-set-name "svtaks" \
          --ipv4-address $ingress_ext_ip

    • To run TLS with ingress controller, we use Let's Encrypt certificate authority (CA) and let cert-manger automatically generate and configure certificates, but you can also bring your own certificates or use a different CA. Create the following issuer.yaml and run kubectl -n $APP_NS apply -f issuer.yaml to create letsencrypt issuer which will be used in the step of deploying application to AKS.
      apiVersion: cert-manager.io/v1
      kind: Issuer
        name: letsencrypt
          server: https://acme-v02.api.letsencrypt.org/directory
          email: <your-email>
            name: letsencrypt
          - http01:
                class: nginx
                      "kubernetes.io/os": linux
    • Create namespace, create custom resource definitions (CRDs) for WebSphere Liberty Application and day-2 operations, configure cluster level role based and install WLO to watch all namespaces in the cluster. 
      export WLO_NAMESPACE=wlo-ns
      export WLO_TARGET_NAMESPACE='""'
      kubectl create namespace $WLO_NAMESPACE
      kubectl apply -f https://raw.githubusercontent.com/WASdev/websphere-liberty-operator/main/deploy/releases/$WLO_VERSION/kubectl/websphereliberty-app-crd.yaml curl -L https://raw.githubusercontent.com/WASdev/websphere-liberty-operator/main/deploy/releases/$WLO_VERSION/kubectl/websphereliberty-app-rbac-watch-all.yaml \ | sed -e "s/WEBSPHERE_LIBERTY_OPERATOR_NAMESPACE/${WLO_NAMESPACE}/" \ | kubectl apply -f - curl -L https://raw.githubusercontent.com/WASdev/websphere-liberty-operator/main/deploy/releases/$WLO_VERSION/kubectl/websphereliberty-app-operator.yaml \ | sed -e "s/WEBSPHERE_LIBERTY_WATCH_NAMESPACE/${WLO_TARGET_NAMESPACE}/" \ | kubectl apply -n ${WLO_NAMESPACE} -f -

    • View WLO controller manager pod to ensure it is running.  For example:
      kubectl -n $WLO_NAMESPACE get pods
      NAME                                      READY   STATUS    RESTARTS   AGE
      wlo-controller-manager-6bff4c98dd-fwh62   1/1     Running   0          60s

    • Deploy getting-started-instanton application checkpoint image to AKS using the following app-deploy.yaml.  The spec.applicationImage: svtacr.azurecr.io/getting-started-instanton:latest is the application image in ACR.  The spec.route section has the information for the Nginx ingress and issuer resource.  The spec.route.host is <record-set-name.zone-name> which was created in the adding record set step. The spec.securityContext section adds privileges and capabilities to the restore process at server startup time.  Create namespace with kubectl create namespace $APP_NS command, then run kubectl -n $APP_NS apply -f app-deploy.yaml to install the sample application to AKS.
      apiVersion: liberty.websphere.ibm.com/v1
      kind: WebSphereLibertyApplication
        name: getting-started-instanton
          accept: true
          edition: IBM WebSphere Application Server
          productEntitlementSource: Standalone
        applicationImage: svtacr.azurecr.io/getting-started-instanton:latest
        pullPolicy: IfNotPresent
        manageTLS: true
        replicas: 1
        expose: true
            kubernetes.io/ingress.class: nginx
            cert-manager.io/issuer: letsencrypt
            nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
            nginx.ingress.kubernetes.io/affinity: "cookie"
            nginx.ingress.kubernetes.io/session-cookie-name: "route"
            nginx.ingress.kubernetes.io/session-cookie-max-age: "172800"
          host: svtaks.green-chesterfield.com
          certificateSecretRef: tls-secret
          path: /
          pathType: Prefix
          port: 9443
          type: ClusterIP
            value: 'simple'
          runAsNonRoot: true
          privileged: false
          allowPrivilegeEscalation: true
            - SETPCAP
            - ALL

    • Check for application pods and wait for the status to become ready.  It should look similar to the following: 
      kubectl -n $APP_NS get pods
      NAME READY STATUS RESTARTS AGE getting-started-instanton-6866c57ff9-wt8xm 1/1 Running 0 49s

    • View ingress to see hosts URL to run the application.  The output should look similar to the following:
      kubectl -n $APP_NS get ingress
      NAME CLASS HOSTS ADDRESS PORTS AGE getting-started-instanton <none> svtaks.green-chesterfield.com 80, 443 50s

    • View log and you should see that the server is started very fast in milliseconds.  In this case the default server was started in 0.403 seconds instead of several seconds if the application image doesn't have checkpoint.
      kubectl -n $APP_NS logs getting-started-instanton-6866c57ff9-wt8xm
      Found mounted TLS certificates, generating keystore
      Found mounted TLS CA certificate, adding to truststore
      [3/9/23, 16:38:19:757 UTC] 0000002e com.ibm.ws.app.manager.AppMessageHelper                      A CWWKZ0001I: Application guide-getting-started started in 0.173 seconds.
      [3/9/23, 16:38:19:777 UTC] 0000002e com.ibm.ws.config.xml.internal.ConfigRefresher               A CWWKG0016I: Starting server configuration update.
      [3/9/23, 16:38:19:778 UTC] 0000002e com.ibm.ws.config.xml.internal.ServerXMLConfiguration        A CWWKG0093A: Processing configuration drop-ins resource: /opt/ol/wlp/usr/servers/defaultServer/configDropins/defaults/checkpoint.xml
      [3/9/23, 16:38:19:778 UTC] 0000002e com.ibm.ws.config.xml.internal.ServerXMLConfiguration        A CWWKG0093A: Processing configuration drop-ins resource: /opt/ol/wlp/usr/servers/defaultServer/configDropins/defaults/keystore.xml
      [3/9/23, 16:38:19:779 UTC] 0000002e com.ibm.ws.config.xml.internal.ServerXMLConfiguration        A CWWKG0093A: Processing configuration drop-ins resource: /opt/ol/wlp/usr/servers/defaultServer/configDropins/defaults/open-default-port.xml
      [3/9/23, 16:38:19:781 UTC] 0000002e com.ibm.ws.config.xml.internal.ServerXMLConfiguration        A CWWKG0093A: Processing configuration drop-ins resource: /opt/ol/wlp/usr/servers/defaultServer/configDropins/overrides/truststore.xml
      [3/9/23, 16:38:19:866 UTC] 00000030 com.ibm.ws.config.xml.internal.ConfigRefresher               A CWWKG0017I: The server configuration was successfully updated in 0.091 seconds.
      [3/9/23, 16:38:19:929 UTC] 0000002e io.openliberty.checkpoint.internal.CheckpointImpl            A CWWKC0452I: The Liberty server process resumed operation from a checkpoint in 0.346 seconds.
      [3/9/23, 16:38:19:931 UTC] 0000002e com.ibm.ws.tcpchannel.internal.TCPPort                       I CWWKO0219I: TCP Channel defaultHttpEndpoint has been started and is now listening for requests on host *  (IPv6) port 9080.
      [3/9/23, 16:38:19:956 UTC] 0000002e com.ibm.ws.kernel.feature.internal.FeatureManager            A CWWKF0012I: The server installed the following features: [cdi-3.0, checkpoint-1.0, concurrent-2.0, distributedMap-1.0, jndi-1.0, json-1.0, jsonb-2.0, jsonp-2.0, monitor-1.0, mpConfig-3.0, mpHealth-4.0, mpMetrics-4.0, restfulWS-3.0, restfulWSClient-3.0, servlet-5.0, ssl-1.0, transportSecurity-1.0].
      [3/9/23, 16:38:19:983 UTC] 0000002e com.ibm.ws.kernel.feature.internal.FeatureManager            I CWWKF0008I: Feature update completed in 0.400 seconds.
      [3/9/23, 16:38:19:987 UTC] 0000002e com.ibm.ws.kernel.feature.internal.FeatureManager            A CWWKF0011I: The defaultServer server is ready to run a smarter planet. The defaultServer server started in 0.403 seconds.
      [3/9/23, 16:38:19:990 UTC] 00000038 com.ibm.ws.security.token.ltpa.internal.LTPAKeyCreateTask    I CWWKS4105I: LTPA configuration is ready after 0.136 seconds.
      [3/9/23, 16:38:20:158 UTC] 0000002a com.ibm.ws.ssl.config.WSKeyStore                             I Successfully loaded default keystore: /opt/ol/wlp/output/defaultServer/resources/security/key.p12 of type: PKCS12
      [3/9/23, 16:38:20:179 UTC] 00000044 com.ibm.ws.tcpchannel.internal.TCPPort                       I CWWKO0219I: TCP Channel defaultHttpEndpoint-ssl has been started and is now listening for requests on host *  (IPv6) port 9443.

    Now you can run the sample Open Liberty getting started application using the ingress host. In our case it is https://svtaks.green-chesterfield.com/dev