back to all blogsSee all blog posts

Liberty InstantOn on Amazon EKS

image of author
Jarek Gawor on Feb 20, 2023
Post available in languages:

This article was published when Liberty InstantOn was still beta. Liberty InstantOn moved out of beta as of the Liberty 23.0.0.6 release. For the latest information about Liberty InstantOn, see Faster startup for containerized applications with Open Liberty InstantOn in the Open Liberty docs.

Liberty InstantOn beta dramatically improves the startup time of Liberty applications. In this post, we will deploy a simple Liberty application to Amazon Elastic Kubernetes Service (Amazon EKS) and use InstantOn to quickly spin up application containers.

First, we will build an InstantOn container image and push it to Amazon Elastic Container Registry (Amazon ECR). Next, we will create a new Amazon EKS cluster, deploy the Liberty application to the cluster, and scale the application up.

To complete the steps outlined in this post, you need the following resources:

  • Maven to build the Liberty application

  • Podman to build the InstantOn image

  • An Amazon AWS Account

  • The AWS CLI to create and manage AWS services

  • The Amazon EKS CLI (v0.120.0 or higher) to create and manage EKS clusters

  • The kubectl command-line tool to interact with a Kubernetes cluster

Build the InstantOn image

First, clone the repository of the sample Liberty application. We are checking out the instanton branch, which contains the InstantOn modifications.

git clone -b instanton https://github.com/OpenLiberty/sample-getting-started.git
cd sample-getting-started

Next, build the application code using Maven:

mvn install

Once the code is compiled, we can build the InstantOn container image. This process creates two container images:

  • The base image, which contains only the application

  • The InstantOn image, which extends the base image and adds the checkpoint data needed for a quick startup.

A small set of elevated Linux permissions are required to build the InstantOn container image. However, to simplify the example, the next few commands are run as the root user using the sudo command.

To build the base image, run:

sudo ./build-og.sh

The script runs a simple podman build command and creates the dev.local/getting-started container image.

To build the InstantOn image, run:

sudo ./build-instanton.sh

The scripts runs a sequence of podman commands that create the checkpoint data and save that data in a new dev.local/getting-started-instanton container image.

Push the image to ECR

At this point, the InstantOn image on exists on a local machine. We need to push it to a container registry to make it available to the EKS cluster. One option is to make the image available in a public registry, such as DockerHub or Quay. Another option is to use Amazon ECR.

In this post, we will use Amazon ECR for a couple of reasons. First, a default private Amazon ECR is provided with each AWS account, so we don’t have to set up and configure a separate registry elsewhere. Second, Amazon ECR can seamlessly integrate with EKS and other similar AWS services such as Amazon ECS. Therefore, we do not have to configure any image pull secrets in our EKS cluster to pull down images from the private container registry.

To use the private Amazon ECR registry, first create a repository for the InstantOn image:

aws ecr create-repository --repository-name getting-started-instanton

In the output of this command, note the repositoryUri value. It should match the <aws_account_id>.dkr.ecr.<region>.amazonaws.com/getting-started-instanton pattern. For example: 1234567890.dkr.ecr.us-east-1.amazonaws.com/getting-started-instanton. You will need this value when you create the deployment.yaml file to deploy the InstantOn application.

Next, authenticate to the registry using the following command so you can push or pull images using Podman:

aws ecr get-login-password | sudo podman login --username AWS --password-stdin <aws_account_id>.dkr.ecr.<region>.amazonaws.com

After you are authenticated, you can tag and push the InstantOn image to the private ECR registry:

sudo podman tag dev.local/getting-started-instanton <aws_account_id>.dkr.ecr.<region>.amazonaws.com/getting-started-instanton
sudo podman push <aws_account_id>.dkr.ecr.<region>.amazonaws.com/getting-started-instanton

Provision the EKS cluster

We are ready to provision an EKS cluster now. The first step is to create a cluster.yaml file with the following contents.

cluster.yaml
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
  name: instanton
  region: us-east-1
  version: "1.24"

managedNodeGroups:
  - name: ng-instanton
    instanceType: t3.micro
    desiredCapacity: 3
    iam:
       attachPolicyARNs:
          - arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy
          - arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy
          - arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly
          - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore

The initial cluster.yaml file requests a Kuberentes v1.24 cluster to be provisioned with three managed EC2 nodes. The cluster is just big enough to handle the sample application. If you are planning to deploy other applications to the cluster, adjust the instanceType and/or the desiredCapacity parameters. Also, make sure that the region parameter matches your region. See the config file schema for additional settings that can be configured when provisioning a cluster.

With this configuration, the cluster nodes are created using the default Amazon Machine Image (AMI) running the Amazon Linux 2 operating system. The latest Amazon Linux AMI is running a Linux kernel version that supports InstantOn. The other EKS-optimized AMIs, such as Bottlerocket or Ubuntu 20, also support InstantOn. You can use a custom AMI for your cluster as long as it is running Linux kernel 5.9 or higher.

After making updates to the cluster.yaml, run the following command to provision the EKS cluster:

eksctl create cluster -f cluster.yaml

After about 15 minutes, the cluster should be provisioned and ready to use. Double check by running the following command to see the cluster nodes:

kubectl get node -o wide

Look for output similar to the following example:

NAME                             STATUS   ROLES    AGE     VERSION               INTERNAL-IP      EXTERNAL-IP      OS-IMAGE         KERNEL-VERSION                  CONTAINER-RUNTIME
ip-xxx-xxx-xx-xxx.ec2.internal   Ready    <none>   2m44s   v1.24.6-eks-4360b32   xxx.xxx.xx.xxx   xx.xxx.xxx.xxx   Amazon Linux 2   5.10.165-143.735.amzn2.x86_64   containerd://1.6.6
ip-xxx-xxx-xx-xxx.ec2.internal   Ready    <none>   2m42s   v1.24.6-eks-4360b32   xxx.xxx.xx.xxx   xx.xx.xx.xx      Amazon Linux 2   5.10.165-143.735.amzn2.x86_64   containerd://1.6.6

Deploy the InstantOn application

After the cluster is up and running, we can deploy the Liberty InstantOn application.

First, create a deployment.yaml file with the following contents. Update the image value to match the repositoryUri from the create-repository command output.

deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: open-liberty-instanton
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: open-liberty-instanton
  template:
    metadata:
      labels:
        app.kubernetes.io/name: open-liberty-instanton
    spec:
      containers:
      - image: <aws_account_id>.dkr.ecr.<region>.amazonaws.com/getting-started-instanton
        imagePullPolicy: IfNotPresent
        name: app
        ports:
        - containerPort: 9080
          name: 9080-tcp
          protocol: TCP
        resources:
          limits:
            cpu: 1
            memory: 512Mi
          requests:
            cpu: 500m
            memory: 256Mi
        securityContext:
          runAsNonRoot: true
          privileged: false
          capabilities:
            add:
            - CHECKPOINT_RESTORE
            - SETPCAP
            drop:
            - ALL

Next, deploy the application by running the following command:

kubectl apply -f deployment.yaml

Check the logs to see if the application started up successfully. Keep in mind that it might take a few extra seconds for the pod to start for very first time as the cluster nodes must pull down the container image from ECR:

kubectl logs -l app.kubernetes.io/name=open-liberty-instanton --tail=-1

Look for the following output to confirm that the application started successfully with InstantOn:

[AUDIT   ] CWWKZ0001I: Application io.openliberty.sample.getting.started started in 0.331 seconds.
[AUDIT   ] CWWKC0452I: The Liberty server process resumed operation from a checkpoint in 0.464 seconds.
[AUDIT   ] CWWKF0012I: The server installed the following features: [cdi-2.0, checkpoint-1.0, distributedMap-1.0, jaxrs-2.1, jaxrsClient-2.1, jndi-1.0, json-1.0, jsonp-1.1, monitor-1.0, mpConfig-2.0, mpHealth-3.1, mpMetrics-3.0, servlet-4.0, ssl-1.0].
[AUDIT   ] CWWKF0011I: The defaultServer server is ready to run a smarter planet. The defaultServer server started in 0.510 seconds.
[AUDIT   ] CWWKS4104A: LTPA keys created in 0.919 seconds. LTPA key file: /opt/ol/wlp/output/defaultServer/resources/security/ltpa.keys
[AUDIT   ] CWPKI0803A: SSL certificate created in 3.290 seconds. SSL key file: /opt/ol/wlp/output/defaultServer/resources/security/key.p12

Now, you can scale the application up to see how quickly the new pod instances are coming up! Results may vary but you should see up to 90% improvement in the startup time over the same application without InstantOn.

kubectl scale deployment/open-liberty-instanton --replicas=3

In a follow on blog post, we will combine InstantOn with Knative and explore the scale-to-zero scenario.

Clean up

If you no longer need the EKS cluster, make sure to delete it by running the following command:

eksctl delete cluster -f cluster.yaml

Similarly, if you no longer need the ECR repository, delete it using the following command:

aws ecr delete-repository --repository-name getting-started-instanton --force