Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Modernizing Java Apps and Data on Azure - Part Four: Migrating to Azure Kubernetes Service

0.00/5 (No votes)
13 Apr 2022 1  
How to containerize a legacy Java app and deploy it to an AKS cluster
This is Part 4 of a 6-part series that demonstrates how to take a monolithic Java application and gradually modernize both the application and its data using Azure tools and services. This article demonstrates how to containerize a legacy Java app and deploy it to an AKS cluster.

The previous article in this series demonstrated deploying an application to machines running in the cloud. That’s an excellent first step, but managing the cloud server farm is as labor intensive as managing physical servers in a data center. Additionally, application update packages contain significant amounts of software for the target platform.

Although developers need a copy of the platform code to create the application, deployment results in re-uploading duplicate code. Therefore, we need a way to identify code that exists on the platform and add only what’s unique to the application.

For this, Docker created a solution that packages applications in containers and builds a platform to run the containers. The platform provides the operating system and relevant support code while the containers run on top. Using this packaging method, we can build containers from layers of software.

The first layer describes the operating platform. We can then add a layer containing the application description. Unlike a traditional virtual machine package that includes the operating system and its supporting data (e.g., file system, application, and supporting applications like Tomcat), the container contains no data redundant to the platform.

In more complex solutions, we can insert additional layers to add services or update services already on the platform. For example, we can inject an HTTPS Secure Socket Layer (SSL), offloading service between an application and the network when the application only provides HTTP services, but the application must connect to the network using Transport Layer Security (TSL) over SSL.

Furthermore, we can tell Docker to replace specific files or volumes when it starts the container. For example, we can build the PetClinic application with one version of the application.properties file and tell Docker to replace that file with one from the local environment when the application starts.

Alternatively, if we’d initially built PetClinic in a container, we could have told Docker to replace the application.properties file to change the connection string when moving it to the cloud. Then, PetClinic would use the updated connection string.

This article provides only an elementary introduction to this compelling technology, but Docker's website has more information about containerization. Additionally, Microsoft published an introductory article where you can learn more.

It’s easy to write some scripts to manage only a few containers. However, containers connect to external services like shared file systems and load balancers. Furthermore, running multiple instances of an application results in an additional container using, for example, a port. So, we must remap the container to use a different port.

It becomes daunting to keep track of which containers are running, which application versions they are running, and which resources they use. We need an orchestration service to help configure, deploy, and monitor these containers. That’s precisely what Kubernetes accomplishes. Kubernetes is an open-source container orchestration server. Azure Kubernetes Service (AKS), as described here, is Microsoft’s implementation of this service on Azure.

This technology enables developers to replace a cloud server farm built on the Azure App Service with Docker containers managed by AKS. This eases maintenance and scalability through a “separation of concerns.”

Consider the current implementation of the PetClinic app. To deploy it and obtain data from another server, we must update the application_postgres.properties file, build the application, push it to a server, and start the service. In contrast, containerizing it and allowing AKS to manage the deployment enables AKS to overlay the application_postgres.properties file without changing the container image and launch the container without assistance.

Using Docker and AKS, developers can build an application to use a data service. However, DevOps determines which service the application uses. This separates the issues of how the application works from where it obtains the necessary resources.

Prerequisites

Before creating an AKS cluster, ensure that the Azure Plugin for IntelliJ is installed. IntelliJ provides tools to build and deploy the container. Restart IntelliJ. Then install kubectl, which enables you to interact with the AKS cluster.

Create the Container Registry

AKS must have access to an image to launch it. While AKS works with any registry, Azure conveniently provides the Azure Container Registry (ACR) to store Docker container images. This demonstration will use ACR.

Start by logging in to your portal and selecting Create a resource. Type “container reg” into the search box and select Container Registry. When the Container Registry dialog box appears, click Create.

Next, either select a Resource group or create a new one.

For this example, allow public access to the cluster by accepting the networking defaults. Set the registry name, then scroll down and set the SKU to Basic. Finally, click Review + create.

Review the settings in the Create container registry dialog box and click Create.

Creating the cluster takes a while, but upon completion, you’ll see this:

Next, enable Administrator logins so that IntelliJ can push containers into the registry. To do that, navigate to the new resource and click Access Keys.

In the Access Keys dialog box, you must set the Admin user to Enabled. Copy the Username and password values and keep them for later to provide them to IntelliJ.

Build the Container

There are two ways to build an image: with Docker, or with IntelliJ. Docker uses a list of instructions to guide the building process. By default, these instructions are in a file named Dockerfile. You can debug this file to ensure that it builds a valid image.

In the Upload the Image to the Registry section, you can use the Azure Plugin for IntelliJ to rebuild the image using Dockerfile and push it to the container registry in a single step. After this, the tools can automate rebuilding the image whenever necessary.

This project contains a straightforward set of build instructions:

FROM mcr.microsoft.com/openjdk/jdk:11-ubuntu
EXPOSE 8080
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-Dspring.profiles.active=postgres","-jar","/app.jar"]

The FROM instruction identifies the Linux image that the container uses as its base. This image, provided by Microsoft, implements OpenJDK version 11 on Ubuntu Linux. You need to use this image so that Docker can run on your container with a Java version that’s compatible with Windows. This is the required configuration for AKS.

When running the Docker build command, Docker downloads an image named jdk:11-ubuntu from a registry hosted at mcr.microsoft.com. Microsoft provides general information on available images here. As image names change frequently, you should verify that a version exists before trying to build your container. The Microsoft Container Registry (MCR) has instructions for browsing the registry.

If you retrieve this URL, https://mcr.microsoft.com/v2/openjdk/jdk/tags/list, you’ll see a list like this, which includes the 11-ubuntu image:

Java
{"name": "openjdk/jdk",
"tags": [
"11-cbld",
"11-mariner",
"11-ubuntu",
"16-cbld",
"16-mariner",
"16-ubuntu",
"17-cbld",
"17-mariner",
"17-ubuntu"
]}

The EXPOSE statement tells Docker that PetClinic needs port 8080. When AKS launches the container, it maps a port on the AKS internal network to the port on the container. The port that AKS assigns isn’t critical because end users run PetClinic using a URL that doesn’t include a port. The container won’t be aware of the remapping.

The ARG statement creates a symbol like an environment variable. The symbol JAR_FILE contains the path to the file that Maven produces when it builds PetClinic. Docker won’t run Maven to build the target, but it must know where Maven created it.

The COPY statement tells Docker to copy the target file from the source location into the image and name it app.jar.

The ENTRYPOINT statement contains the parts of the command line needed to start the application. AKS executes this command after it has loaded the container.

There is a file named Dockerfile in the root directory of the PetClinic project. To build the container, open a command window, change to the root directory of the PetClinic project, and execute the following command:

Docker
C:\Projects\PetClinic\repos\spring-petclinic>docker build 
  -t springboot/petclinic-docker -f ./Dockerfile .

You’ll see the following results:

Upload the Image to the Registry

To simplify storing images when building them, use IntelliJ to push the image into the registry. Start by logging into Azure by selecting Tools > Azure > Azure Sign In.

Select an authentication method. For this demonstration, select OAuth 2.0 and work through the process.

After authentication completes, return to the main screen, and right-click the project. Select Azure, then Push Image.

A profile editor opens. Fill in the Server URL, Username, and Password fields from the MCR. You can ignore the Container Registry setting. The Image and tag field is the name of your image in the registry, and you can append a tag to it. For this tutorial, set this value to pet-clinic-demo:latest, which sets the image name to pet-clinic-demo and the tag to latest.

Click Run to start the build and push process.

This takes a while. Don’t worry if the process gets stuck here for a few minutes:

When the process continues, you see this:

IntelliJ starts uploading the image. When complete, you see a display like this:

You can verify the image uploaded by checking the portal.

Create a Cluster

If you’re new to Kubernetes, Microsoft provides a Kubernetes overview. This page also provides links to learning paths for the service. The Kubernetes e-book collection is a set of three free downloadable books on designing and implementing cloud-native systems. One book covers Kubernetes and the other two cover designing cloud-native systems, which is the topic of this series’ final article.

Now that you have an image, you need a place to run it. AKS provides a complete Kubernetes implementation that can launch and monitor your images. To use it, you must create an AKS cluster. Use this tutorial to set up your cluster.

Deploy the Container to AKS

Kubernetes needs instructions for how to deploy your image. You can use a Deployment — a specific type of Kubernetes resource used to create pods — but there are some support tasks to do before you can apply it. Although the tasks in this list appear somewhat disconnected, they configure additional resources in your environment so that:

  • The Azure Command-Line Interface (CLI) can execute commands.
  • AKS has the information needed to download your image from the MCR when it tries to implement your Deployment.
  • kubectl can run commands on your cluster.
  • AKS can configure a load balancer that enables everyone to connect to your cluster using an Ingress resource, a Kubernetes resource that provides controlled access to a port.

To use the Azure CLI, use the tool to log in to Azure so that it has the necessary credentials when using the login command:

Azure-CLI
C:\Projects\PetClinic\repos\spring-petclinic>az login

For AKS to pull images from your container registry, you must attach the registry to AKS with the update command:

Azure-CLI
C:\Projects\PetClinic\repos\spring-petclinic>az aks update -n petClinicDemo -g PetClinicDemo 
  --attach-acr PetClinicDemoRegistry

The command returns a lot of information that isn’t relevant to this project. However, running this enables you to retrieve the credentials for the cluster so that kubectl can execute your commands within it. The aks get-credentials command writes them to a file that the Azure CLI reads:

Azure-CLI
C:\Projects\PetClinic\repos\spring-petclinic> az aks get-credentials 
  --resource-group PetClinicDemo --name petClinicDemo

You must tell AKS to create a load balancer for your application and associate a hostname with that load balancer. To accomplish this, AKS provides the HTTP Application Routing feature.

Navigate to your cluster in the Azure Portal and click Networking to ensure this feature is enabled. If you change the setting, save your changes and wait a few minutes while AKS updates your cluster.

When the cluster is ready, you must find out which DNS zone the HTTP Application Routing feature created. To do this, use the aks show command:

Azure-CLI
C:\Projects\PetClinic\repos\spring-petclinic>az aks show 
  --resource-group PetClinicDemo --name petClinicDemo –query

Your Deployment includes instructions for creating an Ingress resource to provide access to the load balancer. The argument of the query parameter is the class name of the Ingress resource as defined in the Deployment. The code for the complete Deployment is below. The file is in YAML format, so ensure accurate spacing if you copy it.

Note: If you use the sample code, you must update it in two places.

First, set the host parameter for the Ingress. The value has this format:

<myHostname>.<DNS Region name from the previous "az" command>
petclinic-container-demo.7a125b5db23047ffb5f7.eastus.aksapp.io

The image parameter for the container in the Deployment:

petclinicdemoregistry.azurecr.io/pet-clinic-demo:latest

Here’s the complete code for the deployment. It’s in a file named PetClinicDeployment.yaml.

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: default
  name: petclinic-container-demo
  labels:
    app: petclinic-container-demo
spec:
  replicas: 2
  selector:
    matchLabels:
      app: petclinic-container-demo
  template:
    metadata:
      labels:
        app: petclinic-container-demo
    spec:
      containers:
      - name: petclinic-container-demo
        image: petclinicdemoregistry.azurecr.io/pet-clinic-demo:latest
        ports:
        - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  namespace: default
  name: petclinic-container-service
spec:
  type: ClusterIP
  ports:
  - port: 8080
  selector:
    app: petclinic-container-demo
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  namespace: default
  name: petclinic-container-frontend
  annotations:
    kubernetes.io/ingress.class: addon-http-application-routing
spec:
  rules:
  - host: pet-clinic-demo.7a125b5db23047ffb5f7.eastus.aksapp.io
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: petclinic-container-service
            port:
              number: 8080

Now that you have the Deployment, apply it to your cluster to tell Kubernetes to create a pod, which will launch the application in the container. Use the kubeclt apply command:

C:\Projects\PetClinic\repos\spring-petclinic>kubectl apply –f PetClinicDeployment.yaml

Verify the Application is Running

Now you need to verify that the pods are up and running using the kubectl get pods command.

C:\Projects\PetClinic\repos\spring-petclinic>kubectl get pods

Then verify that the load balancer has an external IP address so users can run the application. One way to do this is to look at the log for the DNS Addon resource and verify that there’s a record for your DNS zone. The kubectl logs command returns a lot of text, but the message you’re looking for is near the end of the log.

C:\Projects\PetClinic\repos\spring-petclinic>kubectl logs 
-f deploy/addon-http-application-routing-external-dns -n kube-system

The URL for your web page has two parts: the application name, pet-clinic-demo, and the host name, 7a125b5db23047ffb5f7.eastus.aksapp.io, from the Azure DNS zone shown above. Combine them to create the following URL:

http://pet-clinic-demo.7a125b5db23047ffb5f7.eastus.aksapp.io

Finally, you can view the console logs for the pods that are running PetClinic as follows. First, get the names of the pods with the kubectl get pods command:

C:\Projects\PetClinic\repos\spring-petclinic>kubectl get pods

Then get the log:

C:\Projects\PetClinic\repos\spring-petclinic>kubectl logs petclinic-container-demo-749ff8dfc4-d85p5

This is the same console log (trimmed) that you see when running PetClinic in IntelliJ. You shouldn’t see any errors here. If the pods don’t shift to Running status, check this log to see why PetClinic didn’t start.

Summary

Our application is now a container that is readily deployable in a managed cluster. We’ve enhanced the scalability of our application by moving away from requiring a single EC2 instance, which requires manual startup and monitoring for each instance deployed. Instead, AKS manages the hardware and keeps our application running. This is the advantage of using Deployments to create pods.

Docker containers are highly portable and can run on any system that provides a Docker host. Host machines can run images that use any operating system. Furthermore, Azure hosts running Windows can run Ubuntu Linux-based applications because the container isolates the application from the host OS.

Because the application obtains its resources from the Docker host, it’s no longer bound to the host machine’s resources. Plus, that machine’s other applications no longer need it. This enables us to rebuild containers on updated operating systems without worrying whether the host or its applications are up to date. Gone is the need for wall-sized spreadsheets connecting applications to their resources to determine which upgrades affect which applications.

AKS provides benefits far beyond launching instances. Suppose you rebuild an application and update the image in the MCR using a Deployment. Here, you can tell AKS to perform a ripple restart and deploy the new image automatically. This frees the continuous integration and continuous deployment (CI/CD) process to handle updating the container image while Kubernetes oversees its deployment.

In addition to the aforementioned Kubernetes eBook collection and Docker introductory material, Microsoft offers a learning path entitled Introduction to Kubernetes on Azure. Additionally, you can learn more about designing containerized applications from Docker’s Principles of Container-based Application Design. These publications provide you with the foundation to create decoupled, modular applications that are easily scalable and deployable.

This series’ next article will explore ways to improve data scalability.

To see how four companies transformed their mission-critical Java applications to achieve better performance, security, and customer experiences, check out the e-book Modernize Your Java Apps.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here