Subject Notes: Working a Stateful Java Service on Amazon EKS

This put up was co-authored  by Tom Cheung, Cloud Infrastructure Architect, AWS Skilled Providers and Bastian Klein, Options Architect at AWS.

Containerization helps to create safe and reproducible runtime environments for functions. Container orchestrators assist to run containerized functions by offering prolonged deployment and scaling capabilities, amongst others. Due to this, many organizations are putting in such methods as a platform to run their functions on. Organizations typically begin their container adaption with new workloads which can be properly suited to the way in which how orchestrators handle containers.

After they gained their first experiences with containers, organizations begin migrating their current functions to the identical container platform to simplify the infrastructure panorama and unify their deployment mechanisms.  Migrations include some challenges, because the functions weren’t designed to run in a container surroundings. Lots of the current functions work in a stateful method. They’re persisting recordsdata to the native storage and make use of stateful periods. Each necessities should be met for the appliance to correctly work within the container surroundings.

This weblog put up reveals run a stateful Java service on Amazon EKS with the concentrate on deal with stateful periods You’ll learn to deploy the service to Amazon EKS and save the session state in an Amazon ElastiCache Redis database. There’s a GitHub Repository that gives all sources which can be talked about on this article. It accommodates AWS CloudFormation templates that may setup the required infrastructure, in addition to the Java software code together with the Kubernetes useful resource templates.

The Java code used on this weblog put up and the GitHub Repository are primarily based on a Weblog Submit from Java In Use: Spring Boot + Session Administration Instance Utilizing Redis. Our thanks for this content material contributed beneath the MIT-0 license to the Java In Use creator.

Overview of structure

Kubernetes is a well-liked Open Supply container orchestrator that’s broadly used. Amazon EKS is the managed Kubernetes providing by AWS and used on this illustration to run the Java software. Amazon EKS manages the Management Aircraft for you and provides you the liberty to decide on between self-managed nodes, managed nodes or AWS Fargate to run your compute.

The next structure diagram reveals the setup that’s used for this text.

Container reference architecture

 

  • There’s a VPC composed of three public subnets, three subnets used for the appliance and three subnets reserved for the database.
  • For this software, there may be an Amazon ElastiCache Redis database that shops the person periods and state.
  • The Amazon EKS Cluster is created with a Managed Node Group containing three t3.micro situations per default. These situations run the three Java containers.
  • To have the ability to entry the web site that’s operating contained in the containers, Elastic Load Balancing is ready up inside the general public subnets.
  • The Elastic Load Balancing (Basic Load Balancer) will not be a part of the CloudFormation templates, however will mechanically be created by Amazon EKS, when the appliance is deployed.

Walkthrough

Listed here are the high-level steps on this put up:

  • Deploy the infrastructure to your AWS Account
  • Examine Java software code
  • Examine Kubernetes useful resource templates
  • Containerization of the Java software
  • Deploy containers to the Amazon EKS Cluster
  • Testing and verification

Conditions

  • An AWS account
  • The next instruments should be put in:
  • Fundamental and superior information of Kubernetes, Docker, Java, Spring Boot and microservices

If you do not need to set this up in your native machine, you should use AWS Cloud9.

Deploying the infrastructure

To deploy the infrastructure, you first have to clone the Github repository.

git clone https://github.com/aws-samples/amazon-eks-example-for-stateful-java-service.git

This repository accommodates a set of CloudFormation Templates that arrange the required infrastructure outlined within the structure diagram. This repository additionally accommodates a deployment script deploy.sh that points all the mandatory CLI instructions. The script has one required argument -p that displays the aws cli profile that needs to be used. Overview the Named Profiles documentation to arrange a profile earlier than persevering with.

If the profile is already current, the deployment will be began utilizing the next command:

./deploy.sh -p

The creation of the infrastructure will roughly take half-hour.

The under desk reveals all configurable parameters of the CloudFormation template:

parameter name table

This template is initiating a number of steps to deploy the infrastructure. First, it validates all CloudFormation templates. If the validation was profitable, an Amazon S3 Bucket is created and the CloudFormation Templates are uploaded there. That is needed as a result of nested stacks are used. Afterwards the deployment of the primary stack is initiated. It will mechanically set off the creation of all nested stacks.

Java software code

The next code is a Java internet software applied utilizing Spring Boot. The appliance will persist session knowledge at Amazon ElastiCache Redis, which permits the app to change into stateless. It is a essential a part of the migration, as a result of it permits you to use Kubernetes horizontal scaling options with Kubernetes assets like Deployments, with out the necessity to use sticky load balancer periods.

That is the Java ElastiCache Redis implementation by Spring Knowledge Redis and Spring Boot. It permits you to configure the host and port of the deployed Redis occasion. As a result of that is environment-specific info, it’s not configured within the properties file It’s injected as surroundings variables throughout runtime.

/java-microservice-on-eks/src/essential/java/com/amazon/aws/Config.java

@Configuration
@ConfigurationProperties("spring.redis")
public class Config {

    personal String host;
    personal Integer port;


    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public Integer getPort() {
        return port;
    }

    public void setPort(Integer port) {
        this.port = port;
    }

    @Bean
    public LettuceConnectionFactory redisConnectionFactory() {

        return new LettuceConnectionFactory(new RedisStandaloneConfiguration(this.host, this.port));
    }

}

 

Containerization of Java software

/java-microservice-on-eks/Dockerfile

FROM openjdk:8-jdk-alpine

MAINTAINER Tom Cheung , Bastian Klein
VOLUME /tmp
VOLUME /goal

RUN addgroup -S spring && adduser -S spring -G spring
USER spring:spring
ARG DEPENDENCY=goal/dependency
COPY ${DEPENDENCY}/BOOT-INF/lib /app/lib
COPY ${DEPENDENCY}/META-INF /app/META-INF
COPY ${DEPENDENCY}/BOOT-INF/courses /app
COPY ${DEPENDENCY}/org /app/org

ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-cp","app:app/lib/*", "com/amazon/aws/SpringBootSessionApplication"]

 

That is the Dockerfile to construct the container picture for the Java software. OpenJDK 8 is used as the bottom container picture. Due to the way in which Docker pictures are constructed, this pattern explicitly doesn’t use a so-called ‘fat jar’. Subsequently, you might have separate picture layers for the dependencies and the appliance code. By leveraging the Docker caching mechanism, optimized construct and deploy occasions will be achieved.

Kubernetes Assets

After reviewing the appliance specifics, we are going to now see which Kubernetes Assets are required to run the appliance.

Kubernetes makes use of the idea of config maps to retailer configurations as a useful resource throughout the cluster. This lets you outline key worth pairs that will likely be saved throughout the cluster and that are accessible from different assets.

/java-microservice-on-eks/k8s-resources/config-map.yaml

apiVersion: v1
type: ConfigMap
metadata:
  title: java-ms
  namespace: default
knowledge:
  host: "***.***.0001.euc1.cache.amazonaws.com"
  port: "6379"

On this case, the config map is used to retailer the connection info for the created Redis database.

To have the ability to run the appliance, Kubernetes Deployments are used on this illustration. Deployments take care to keep up the state of the appliance (e.g. variety of replicas) with extra deployment capabilities (e.g. rolling deployments).

/java-microservice-on-eks/k8s-resources/deployment.yaml

apiVersion: apps/v1
type: Deployment
metadata:
  title: java-ms
  # labels in order that we are able to bind a Service to this Pod
  labels:
    app: java-ms
spec:
  replicas: 3
  selector:
    matchLabels:
      app: java-ms
  template:
    metadata:
      labels:
        app: java-ms
    spec:
      containers:
      - title: java-ms
        picture: bastianklein/java-ms:1.2
        imagePullPolicy: At all times
        assets:
          requests:
            cpu: "500m" #half the CPU free: 0.5 Core
            reminiscence: "256Mi"
          limits:
            cpu: "1000m" #max 1.0 Core
            reminiscence: "512Mi"
        env:
          - title: SPRING_REDIS_HOST
            valueFrom:
              configMapKeyRef:
                title: java-ms
                key: host
          - title: SPRING_REDIS_PORT
            valueFrom:
              configMapKeyRef:
                title: java-ms
                key: port
        ports:
        - containerPort: 8080
          title: http
          protocol: TCP

Deployments are additionally the place so that you can use the configurations saved in config maps and map them to surroundings variables. The respective configuration will be discovered beneath “env”. This setup depends on the Spring Boot characteristic that is ready to learn surroundings variables and write them into the in accordance system properties.

Now that the containers are operating, you want to have the ability to entry these containers as an entire from throughout the cluster, but in addition from the web. To have the ability to route visitors cluster internally Kubernetes has a useful resource known as Service. Kubernetes Providers get a Cluster inner IP and DNS title assigned that can be utilized to entry all containers that belong to that Service. Site visitors will, by default, be distributed evenly throughout all replicas.

/java-microservice-on-eks/k8s-resources/service.yaml

apiVersion: v1
type: Service
metadata:
  title: java-ms
spec:
  sort: LoadBalancer
  ports:
    - protocol: TCP
      port: 80 # Port for LB, AWS ELB permit port 80 solely  
      targetPort: 8080 # Port for Goal Endpoint
  selector:
    app: java-ms
    

The “selector“ defines which Pods belong to the services. It has to match the labels assigned to the pods. The labels are assigned in the “metadata” part within the deployment.

Deploy the Java service to Amazon EKS

Earlier than the deployment can begin, there are some steps required to initialize your native surroundings:

  1. Replace the native kubeconfig to configure the kubectl with the created cluster
  2. Replace the k8s-resources/config-map.yaml to the created Redis Database Tackle
  3. Construct and bundle the Java Service
  4. Construct and push the Docker picture
  5. Replace the k8s-resources/deployment.yaml to make use of the newly created picture

These steps will be mechanically executed utilizing the init.sh script situated within the repository. The script wants following parameter:

  1.  -u – Docker Hub Consumer Identify
  2.  -r – Repository Identify
  3.  -t – Docker picture model tag

A pattern invocation appears like this: ./init.sh -u bastianklein -r java-ms -t 1.2

This info is used to concatenate the total docker repository string. Within the previous illustration this could resolve to bastianklein/java-ms:1.2, which can mechanically be pushed to your Docker Hub repository. In case you are not but logged in to docker on the command line execute docker login and observe the displayed steps earlier than executing the init.sh script.

As all the things is ready up, it’s time to deploy the Java service. The under record of instructions first deploys all Kubernetes assets after which lists pods and providers.

kubectl apply -f k8s-resources/

It will output:

configmap/java-ms created
deployment.apps/java-ms created
service/java-ms created

 

Now, record the freshly created pods by issuing kubectl get pods.

NAME                                                READY       STATUS                             RESTARTS   AGE

java-ms-69664cc654-7xzkh   0/1     ContainerCreating   0          1s

java-ms-69664cc654-b9lxb   0/1     ContainerCreating   0          1s

 

Let’s additionally assessment the created service kubectl get svc.

NAME            TYPE                   CLUSTER-IP         EXTERNAL-IP                                                        PORT(S)                   AGE            SELECTOR

java-ms          LoadBalancer    172.20.83.176         ***-***.eu-central-1.elb.amazonaws.com         80:32300/TCP       33s               app=java-ms

kubernetes     ClusterIP            172.20.0.1                                                                                     443/TCP                 2d1h           

 

What we are able to see right here is that the Service with title java-ms has an Exterior-IP assigned to it. That is the DNS Identify of the Basic Loadbalancer that’s created behind the scenes. For those who open that URL, it’s best to see the Web site (this would possibly take a couple of minutes for the ELB to be provisioned).

Testing and verification

The webpage that opens ought to look much like the next screenshot. Within the textual content area you’ll be able to enter textual content that’s saved on clicking the “Save Message” button. This article is going to be listed within the “Messages” as proven within the following screenshot. These messages are saved as session knowledge and now persists at Amazon ElastiCache Redis.

screenboot session example

By destroying the session, you’ll lose the saved messages.

Cleansing up

To keep away from incurring future prices, it’s best to delete all created assets after you’re completed with testing. The repository accommodates a destroy.sh script. This script takes care to delete all deployed assets.

The script requires one parameter -p that requires the aws cli profile title that needs to be used: ./destroy.sh -p

Conclusion

This put up confirmed you the end-to-end setup of a stateful Java service operating on Amazon EKS. The service is made scalable by saving the person periods and the in accordance session knowledge in a Redis database. This resolution requires altering the appliance code, and there are conditions the place this isn’t an choice. By utilizing StatefulSets as Kubernetes Useful resource together with an Utility Load Balancer and sticky periods, the aim of replicating the service can nonetheless be achieved.

We selected to make use of a Kubernetes Service together with a Basic Load Balancer. For a manufacturing workload, managing incoming visitors with a Kubernetes Ingress and an Utility Load Balancer may be the higher choice. If you wish to know extra about Kubernetes Ingress with Amazon EKS, go to our Utility Load Balancing on Amazon EKS documentation.

Subject Notes gives hands-on technical steering from AWS Options Architects, consultants, and technical account managers, primarily based on their experiences within the area fixing real-world enterprise issues for purchasers.

Leave a Reply

Your email address will not be published. Required fields are marked *