aws --version
Contents
- What you’ll learn
- Additional prerequisites
- Getting started
- Creating a Kubernetes cluster on EKS
- Deploying microservices to Amazon Elastic Container Service for Kubernetes (EKS)
- Testing microservices that are running on AWS EKS
- Deploying new version of system microservice
- Tearing down the environment
- Great work! You’re done!
- Guide Attribution
Tags
Deploying microservices to Amazon Web Services
Prerequisites:
Explore how to deploy microservices to Amazon Elastic Container Service for Kubernetes (EKS) on Amazon Web Services (AWS).
What you’ll learn
You will learn how to deploy two microservices in Open Liberty containers to a Kubernetes cluster on Amazon Elastic Container Service for Kubernetes (EKS).
Kubernetes is an open-source container orchestrator that automates many tasks that are involved in deploying, managing, and scaling containerized applications. If you would like to learn more about Kubernetes, check out the Deploying microservices to Kubernetes guide.
There are different cloud-based solutions for running your Kubernetes workloads. Cloud-based infrastructure enables you to focus on developing your microservices without worrying about low-level infrastructure details for deployment. Using a cloud helps you to easily scale and manage your microservices in a high-availability setup.
Amazon Web Services (AWS) offers a managed Kubernetes service called Amazon Elastic Container Service for Kubernetes (EKS). EKS simplifies the process of running Kubernetes on AWS without needing to install or maintain your Kubernetes control plane. It provides a hosted Kubernetes cluster where you can deploy your microservices. You will use EKS with Amazon Elastic Container Registry (ECR). Amazon ECR is a private registry that is used to store and distribute your container images. Note, because EKS is not free, there is a small cost that is associated with running this guide. See the official Amazon EKS pricing documentation for more details.
The two microservices you will deploy are called system
and inventory
. The system
microservice returns the JVM system properties of the running container. It also returns the pod’s name in the HTTP header, making replicas easy to distinguish from each other. The inventory
microservice adds the properties from the system
microservice to the inventory. This demonstrates how communication can be established between pods inside a cluster.
Additional prerequisites
Before you begin, the following additional tools need to be installed:
-
Docker: You need containerization software for building containers. Kubernetes supports various container types, but you will use Docker in this guide. For installation instructions, refer to the official Docker documentation.
-
kubectl: You need the Kubernetes command-line tool
kubectl
to interact with your Kubernetes cluster. See the official Install and Set Up kubectl documentation for information about downloading and setting upkubectl
on your platform. -
eksctl: In this guide, you will use the
eksctl
Command Line Interface (CLI) tool for provisioning your EKS cluster. Navigate to the eksctl releases page and download the latest stable release. Extract the archive and add the directory with the extracted files to your path. -
AWS CLI: You will need to use the AWS Command Line Interface (CLI). For this guide, use AWS CLI Version 2, which supports IAM authentication for your Amazon EKS cluster and is intended for use in production environments. All installers for AWS CLI version 2 include and use an embedded copy of Python, which operates independently of any other Python version installed on your system. Install the AWS CLI by following the instructions in the official Installing the AWS CLI documentation.
To verify that the AWS CLI is installed correctly, run the following command:
Getting started
The fastest way to work through this guide is to clone the Git repository and use the projects that are provided inside:
git clone https://github.com/openliberty/guide-cloud-aws.git
cd guide-cloud-aws
The start
directory contains the starting project that you will build upon.
The finish
directory contains the finished project that you will build.
Before you begin, make sure you have all the necessary prerequisites.
Creating a Kubernetes cluster on EKS
Before you can deploy your microservices, you must create a Kubernetes cluster.
Configuring the AWS CLI
Before you configure the AWS CLI, you need to create an AWS Identity and Access Management (IAM) user. Navigate to the Identity and Access Management users dashboard and create a user through the UI. When you create the user, select programmatic access
as the AWS access type. You will be prompted to set permissions for the user. To complete this guide, the created user must have the following minimal access levels:
-
Refer to the Minimum IAM Policies for the main use cases of
eksctl
. -
Ensure that the AmazonEC2ContainerRegistryFullAccess policy is attached to the IAM account. This policy grants full access to the Amazon Elastic Container Registry, which is necessary for managing container images for your EKS cluster.
Make sure to copy the AWS Access Key ID
and AWS Secret Access Key
values, as you will need these to configure the AWS CLI. After the AWS CLI is installed, configure it by running the aws configure
command. You will be prompted to provide the AWS Access Key ID
and AWS Secret Access Key
values that are associated with the IAM user you created.
aws configure
Next, you will be prompted to enter a region. This region will be the region of the servers where your requests are sent. Select the region that is closest to you. For a full list of regions, see the AWS Regions and Endpoints.
Finally, enter json
when you are prompted to enter the output format.
After you are done filling out this information, the settings are stored in the default profile. Anytime that you run an AWS CLI command without specifying a profile, the default profile is used.
You can verify your current configuration values by running the following command:
aws configure list
Provisioning a cluster
The eksctl
CLI tool simplifies the process of creating clusters on EKS. By default, the command includes a single t2.small
Amazon Elastic Compute Cloud (EC2) instance that supports both i386
and x86_64
architectures. However, this instance is not covered under the AWS Free Tier. For more information, see the official Amazon EC2 pricing documentation.
If you need to build Docker images using other architectures, such as ARM64
, you must switch the instance type accordingly. To view the AWS supported instance types, use the navigation bar in EC2 home to select Instances > Instance Types.
To create your cluster, use the eksctl create cluster
command:
eksctl create cluster --name=guide-cluster --nodes=1 --node-type=t2.small
Running this command creates a cluster that is called guide-cluster
that uses a single t2.small
instance as the worker node. When the cluster is created, you will see an output similar to the following example:
[✔] EKS cluster "guide-cluster" in "us-east-2" region is ready
After your cluster is ready, EKS connects kubectl
to the cluster. Verify that you’re connected to the cluster by checking the cluster’s nodes:
kubectl get nodes
NAME STATUS ROLES AGE VERSION
ip-192-168-47-186.us-east-2.compute.internal Ready <none> 30m v1.30.4-eks-a737599
Deploying microservices to Amazon Elastic Container Service for Kubernetes (EKS)
In this section, you will learn how to deploy two microservices in Open Liberty containers to a Kubernetes cluster on EKS. You will build and containerize the system
and inventory
microservices, push them to a container registry, and then deploy them to your Kubernetes cluster.
Building and containerizing the microservices
The first step of deploying to Kubernetes is to build your microservices and containerize them.
The starting Java project, which you can find in the start
directory, is a multi-module Maven project. It is made up of the system
and inventory
microservices. Each microservice resides in its own directory, start/system
and start/inventory
. Both of these directories contain a Dockerfile, which is necessary for building the Docker images. If you’re unfamiliar with Dockerfiles, check out the Containerizing microservices guide.
To build these microservices, navigate to the start
directory and run the following command:
mvn package
Next, run the docker build
commands to build the container images for your application:
docker build --platform linux/amd64 -t system:1.0-SNAPSHOT system/.
docker build --platform linux/amd64 -t inventory:1.0-SNAPSHOT inventory/.
The -t
flag in the docker build
command allows the Docker image to be labeled (tagged) in the name[:tag]
format. The tag for an image describes the specific image version. If the optional [:tag]
tag is not specified, the latest
tag is created by default.
During the build, you see various Docker messages that describe what images are being downloaded and built. When the build finishes, run the following command to list all local Docker images:
docker images
Verify that the system:1.0-SNAPSHOT
and inventory:1.0-SNAPSHOT
images are listed among them, for example:
REPOSITORY TAG
system 1.0-SNAPSHOT
inventory 1.0-SNAPSHOT
icr.io/appcafe/open-liberty kernel-slim-java11-openj9-ubi
If you don’t see the system:1.0-SNAPSHOT
and inventory:1.0-SNAPSHOT
images, then check the Maven build log for any potential errors.
Pushing the images to a container registry
Pushing the images to a registry allows the cluster to create pods by using your container images. The registry that you are using is called Amazon Elastic Container Registry (ECR).
First, you must authenticate your Docker client to your ECR registry. Start by running the get-login
command:
aws ecr get-login-password
The get-login
command returns a [password_string]
; take a note of this [password_string]
. Next, running the following will return the [aws_account_id]
needed to authenticate your Docker client.
aws sts get-caller-identity --output text --query "Account"
The [aws_account_id]
is a unique 12-digit ID that is assigned to every AWS account. You will notice this ID in the output from various commands because AWS uses it to differentiate your resources from other accounts.
Replace the [password_string]
, [aws_account_id]
and the [region]
your account is configured under in the following docker login
command, that is used to authenticate your Docker client.
docker login -u AWS -p [password_string] https://[aws_account_id].dkr.ecr.[region].amazonaws.com
Next, make a repository to store the system
and inventory
images:
aws ecr create-repository --repository-name awsguide/system
aws ecr create-repository --repository-name awsguide/inventory
You will see an output similar to the following:
{
"repository": {
"registryId": "[aws_account_id]",
"repositoryName": "awsguide/system",
"repositoryArn": "arn:aws:ecr:[region]:[aws_account_id]:repository/awsguide/system",
"createdAt": 1553111916.0,
"repositoryUri": "[aws_account_id].ecr.[region].amazonaws.com/awsguide/system"
}
}
Take note of the repository URI for both the system
and inventory
repositories, as you need them when you tag and push your images.
Next, you need to tag your container images with the relevant data about your registry:
docker tag system:1.0-SNAPSHOT [system-repository-uri]:1.0-SNAPSHOT
docker tag inventory:1.0-SNAPSHOT [inventory-repository-uri]:1.0-SNAPSHOT
Finally, push your images to the registry:
docker push [system-repository-uri]:1.0-SNAPSHOT
docker push [inventory-repository-uri]:1.0-SNAPSHOT
When you tag and push your images, remember to substitute [system-repository-uri]
and [inventory-repository-uri]
with the appropriate URI for the system and inventory repositories.
Deploying the microservices
Now that your container images are built, deploy them using a Kubernetes resource definition.
A Kubernetes resource definition is a yaml file that contains a description of all your deployments, services, or any other resources that you want to deploy. All resources can also be deleted from the cluster by using the same yaml file that you used to deploy them. The kubernetes.yaml
resource definition file is provided for you. If you are interested in learning more about the Kubernetes resource definition, check out the Deploying microservices to Kubernetes guide.
Update thekubernetes.yaml
file in thestart
directory.kubernetes.yaml
kubernetes.yaml
1apiVersion: apps/v1
2kind: Deployment
3metadata:
4 name: system-deployment
5 labels:
6 app: system
7spec:
8 selector:
9 matchLabels:
10 app: system
11 template:
12 metadata:
13 labels:
14 app: system
15 spec:
16 containers:
17 - name: system-container
18 image: [system-repository-uri]:1.0-SNAPSHOT
19 ports:
20 - containerPort: 9080
21---
22apiVersion: apps/v1
23kind: Deployment
24metadata:
25 name: inventory-deployment
26 labels:
27 app: inventory
28spec:
29 selector:
30 matchLabels:
31 app: inventory
32 template:
33 metadata:
34 labels:
35 app: inventory
36 spec:
37 containers:
38 - name: inventory-container
39 image: [inventory-repository-uri]:1.0-SNAPSHOT
40 ports:
41 - containerPort: 9080
42---
43apiVersion: v1
44kind: Service
45metadata:
46 name: system-service
47spec:
48 type: NodePort
49 selector:
50 app: system
51 ports:
52 - protocol: TCP
53 port: 9080
54 targetPort: 9080
55 nodePort: 31000
56---
57apiVersion: v1
58kind: Service
59metadata:
60 name: inventory-service
61spec:
62 type: NodePort
63 selector:
64 app: inventory
65 ports:
66 - protocol: TCP
67 port: 9080
68 targetPort: 9080
69 nodePort: 32000
The image
is the name and tag of the container image that you want to use for the container. Update the system image
and the inventory image
fields to point to your system
and inventory
repository URIs.
Run the following commands to deploy the resources as defined in kubernetes.yaml:
kubectl apply -f kubernetes.yaml
When the apps are deployed, run the following command to check the status of your pods:
kubectl get pods
If all the pods are healthy and running, you see an output similar to the following:
NAME READY STATUS RESTARTS AGE
system-deployment-6bd97d9bf6-4ccds 1/1 Running 0 15s
inventory-deployment-645767664f-nbtd9 1/1 Running 0 15s
Making requests to the microservices
Before you can make a request to [hostname]:31000
or [hostname]:32000
, you must modify the security group to allow incoming traffic through ports 31000
and 32000
. To get the group-id
of the security group, use the aws ec2 describe-security-groups
command:
aws ec2 describe-security-groups --filters Name=group-name,Values="*eksctl-guide-cluster-cluster-*" --query "SecurityGroups[*].IpPermissions[*].UserIdGroupPairs"
You will see an output similar to the following:
...
{
"Description": "Allow nodes to communicate with each other (all ports)",
"GroupId": "sg-035c858e1ff9c52f1",
"UserId": "208872073932"
},
{
"Description": "Allow managed and unmanaged nodes to communicate with each other (all ports)",
"GroupId": "sg-04a0c50049c10ae54",
"UserId": "208872073932"
}
...
Copy the value of the GroupId
which description is "Allow managed and unmanaged nodes to communicate with each other (all ports)". In this example output, the value is sg-04a0c50049c10ae54
.
Then, add the following rules to the security group to allow incoming traffic through ports 31000
and 32000
. Don’t forget to substitute [security-group-id]
for the GroupId
in the output of the previous command.
aws ec2 authorize-security-group-ingress --protocol tcp --port 31000 --group-id [security-group-id] --cidr 0.0.0.0/0
aws ec2 authorize-security-group-ingress --protocol tcp --port 32000 --group-id [security-group-id] --cidr 0.0.0.0/0
After you finish adding the inbound rules to the security group, you might need to wait a few minutes before you try to access the system
and inventory
microservices.
Take note of the EXTERNAL-IP
in the output of the following command. It is the hostname you will later substitute into [hostname]
:
kubectl get nodes -o wide
Then, curl
or visit the following URLs to access your microservices, substituting the appropriate hostname:
-
http://[hostname]:31000/system/properties
-
http://[hostname]:32000/inventory/systems/system-service
The first URL returns system properties and the name of the pod in an HTTP header called X-Pod-Name
. To view the header, you can use the -I
option in the curl
when you make a request to http://[hostname]:31000/system/properties
. The second URL adds properties from system-service
to the inventory.
Testing microservices that are running on AWS EKS
pom.xml
1<?xml version='1.0' encoding='utf-8'?>
2<project xmlns="http://maven.apache.org/POM/4.0.0"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5
6 <modelVersion>4.0.0</modelVersion>
7
8 <groupId>io.openliberty.guides</groupId>
9
10 <artifactId>guide-cloud-aws-inventory</artifactId>
11 <version>1.0-SNAPSHOT</version>
12 <packaging>war</packaging>
13
14 <properties>
15 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
16 <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
17 <maven.compiler.source>11</maven.compiler.source>
18 <maven.compiler.target>11</maven.compiler.target>
19 <!-- Default test properties -->
20 <!-- tag::cluster[] -->
21 <cluster.ip>localhost</cluster.ip>
22 <!-- end::cluster[] -->
23 <!-- tag::system-service[] -->
24 <system.kube.service>system-service</system.kube.service>
25 <!-- end::system-service[] -->
26 <!-- tag::system-node-port[] -->
27 <system.node.port>31000</system.node.port>
28 <!-- end::system-node-port[] -->
29 <!-- tag::inventory-node-port[] -->
30 <inventory.node.port>32000</inventory.node.port>
31 <!-- end::inventory-node-port[] -->
32 <!-- Liberty configuration -->
33 <liberty.var.system.http.port>9080</liberty.var.system.http.port>
34 <liberty.var.http.port>9080</liberty.var.http.port>
35 <liberty.var.https.port>9443</liberty.var.https.port>
36 </properties>
37
38 <!-- Provided dependencies -->
39 <dependencies>
40 <dependency>
41 <groupId>jakarta.platform</groupId>
42 <artifactId>jakarta.jakartaee-api</artifactId>
43 <version>10.0.0</version>
44 <scope>provided</scope>
45 </dependency>
46 <dependency>
47 <groupId>org.eclipse.microprofile</groupId>
48 <artifactId>microprofile</artifactId>
49 <version>6.1</version>
50 <type>pom</type>
51 <scope>provided</scope>
52 </dependency>
53 <!-- For tests -->
54 <dependency>
55 <groupId>org.junit.jupiter</groupId>
56 <artifactId>junit-jupiter</artifactId>
57 <version>5.11.3</version>
58 <scope>test</scope>
59 </dependency>
60 <dependency>
61 <groupId>org.jboss.resteasy</groupId>
62 <artifactId>resteasy-json-binding-provider</artifactId>
63 <version>6.2.10.Final</version>
64 <scope>test</scope>
65 </dependency>
66 <dependency>
67 <groupId>org.jboss.resteasy</groupId>
68 <artifactId>resteasy-client</artifactId>
69 <version>6.2.10.Final</version>
70 <scope>test</scope>
71 </dependency>
72 <dependency>
73 <groupId>org.glassfish</groupId>
74 <artifactId>jakarta.json</artifactId>
75 <version>2.0.1</version>
76 <scope>test</scope>
77 </dependency>
78 </dependencies>
79
80 <build>
81 <finalName>${project.artifactId}</finalName>
82 <plugins>
83 <plugin>
84 <groupId>org.apache.maven.plugins</groupId>
85 <artifactId>maven-war-plugin</artifactId>
86 <version>3.4.0</version>
87 </plugin>
88 <!-- Enable Liberty Maven plugin -->
89 <plugin>
90 <groupId>io.openliberty.tools</groupId>
91 <artifactId>liberty-maven-plugin</artifactId>
92 <version>3.11.1</version>
93 </plugin>
94 <!-- Plugin to run unit tests -->
95 <plugin>
96 <groupId>org.apache.maven.plugins</groupId>
97 <artifactId>maven-surefire-plugin</artifactId>
98 <version>3.5.1</version>
99 </plugin>
100 <!-- Plugin to run functional tests -->
101 <plugin>
102 <groupId>org.apache.maven.plugins</groupId>
103 <artifactId>maven-failsafe-plugin</artifactId>
104 <version>3.5.1</version>
105 <configuration>
106 <systemPropertyVariables>
107 <cluster.ip>${cluster.ip}</cluster.ip>
108 <system.node.port>${system.node.port}</system.node.port>
109 <inventory.node.port>${inventory.node.port}</inventory.node.port>
110 <system.kube.service>${system.kube.service}</system.kube.service>
111 </systemPropertyVariables>
112 </configuration>
113 </plugin>
114 </plugins>
115 </build>
116</project>
A few tests are included for you to test the basic functionality of the microservices. If a test failure occurs, then you might have introduced a bug into the code. To run the tests, wait for all pods to be in the ready state before you proceed further. The default properties defined in the pom.xml
file are:
Property | Description |
---|---|
|
IP or hostname for your cluster. |
|
Name of the Kubernetes Service wrapping the |
|
The NodePort of the Kubernetes Service |
|
The NodePort of the Kubernetes Service |
Use the following command to run the integration tests against your cluster. Substitute [hostname]
with the appropriate value:
mvn failsafe:integration-test -Dcluster.ip=[hostname]
If the tests pass, you see an output for each service similar to the following:
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running it.io.openliberty.guides.system.SystemEndpointIT
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.673 sec - in it.io.openliberty.guides.system.SystemEndpointIT
Results:
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running it.io.openliberty.guides.inventory.InventoryEndpointIT
Tests run: 4, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.222 sec - in it.io.openliberty.guides.inventory.InventoryEndpointIT
Results:
Tests run: 4, Failures: 0, Errors: 0, Skipped: 0
Deploying new version of system microservice
Optionally, you might want to make changes to your microservice and learn how to redeploy the updated version of your microservice. In this section, you will bump the version of the system
microservice to 2.0-SNAPSHOT
and redeploy the new version of the microservice.
Use Maven to repackage your microservice:
mvn package
Next, build the new version of the container image as 2.0-SNAPSHOT
:
docker build --platform linux/amd64 -t system:2.0-SNAPSHOT system/.
Since you built a new image, it must be pushed to the awsguide/system
repository of your container registry again.
Tag your container image with the relevant data about your registry:
docker tag system:2.0-SNAPSHOT [system-repository-uri]:2.0-SNAPSHOT
Push your image to the registry:
docker push [system-repository-uri]:2.0-SNAPSHOT
Update the system-deployment
deployment to use the new container image that you just pushed to the registry:
kubectl set image deployment/system-deployment system-container=[system-repository-uri]:2.0-SNAPSHOT
Use the following command to find the name of the pod that is running the system
microservice:
kubectl get pods
NAME READY STATUS RESTARTS AGE
inventory-deployment-6fd959cc4-rf2m2 1/1 Running 0 7m
system-deployment-677b9f5d9c-nqzcf 1/1 Running 0 7m
Observe that in this case, the system
microservice is running in the pod called system-deployment-677b9f5d9c-nqzcf
. Substitute the name of your pod into the following command to see more details about the pod:
kubectl get event --field-selector involvedObject.name=[pod-name]
View the events at the bottom of the command’s output. Notice that the pod is using the new container image system:2.0-SNAPSHOT
.
LAST SEEN TYPE REASON OBJECT MESSAGE
97s Normal Scheduled pod/system-deployment-56b4b765d4-9jz5l Successfully assigned default/system-deployment-56b4b765d4-9jz5l to ip-192-168-85-136.us-east-2.compute.internal
97s Normal Pulling pod/system-deployment-56b4b765d4-9jz5l Pulling image "208872073932.dkr.ecr.us-east-2.amazonaws.com/awsguide/system:2.0-SNAPSHOT"
95s Normal Pulled pod/system-deployment-56b4b765d4-9jz5l Successfully pulled image "208872073932.dkr.ecr.us-east-2.amazonaws.com/awsguide/system:2.0-SNAPSHOT" in 1.082459294s
95s Normal Created pod/system-deployment-56b4b765d4-9jz5l Created container system-container
95s Normal Started pod/system-deployment-56b4b765d4-9jz5l Started container system-container
Tearing down the environment
It is important to clean up your resources when you are finished with the guide so that you do not incur additional charges for ongoing service.
When you no longer need your deployed microservices, you can delete all Kubernetes resources by running the kubectl delete
command:
kubectl delete -f kubernetes.yaml
Delete the ECR repositories used to store the system
and inventory
images:
aws ecr delete-repository --repository-name awsguide/system --force
aws ecr delete-repository --repository-name awsguide/inventory --force
Remove your EKS cluster:
eksctl delete cluster --name guide-cluster
Great work! You’re done!
You just deployed two microservices running in Open Liberty to AWS EKS. You also learned how to use the kubectl
command to deploy your microservices on a Kubernetes cluster.
Guide Attribution
Deploying microservices to Amazon Web Services by Open Liberty is licensed under CC BY-ND 4.0
Prerequisites:
Nice work! Where to next?
What did you think of this guide?
Thank you for your feedback!
What could make this guide better?
Raise an issue to share feedback
Create a pull request to contribute to this guide
Need help?
Ask a question on Stack Overflow