export AWS_ACCOUNT_ID="$(aws sts get-caller-identity --query \"Account\" --output text)"
export AWS_REGION="$(aws configure get region)"
export EKS_CLUSTER_NAME="micronaut-k8s"
Table of Contents
Service discovery and distributed configuration with Amazon Elastic Kubernetes Service (EKS)
Service discovery and distributed configuration in a Micronaut application with Amazon Elastic Kubernetes Service (EKS)
Authors: Nemanja Mikic, Nemanja Mikic
Micronaut Version: 4.6.3
1. Getting Started
In this guide, we will deploy three microservices on the Amazon Elastic Kubernetes Service (EKS). We will use Kubernetes Service discovery and Distributed configuration to wire up our microservices.
You will discover how the Micronaut framework eases Kubernetes integration and deployment to ECR.
2. What you will need
To complete this guide, you will need the following:
-
Some time on your hands
-
A decent text editor or IDE (e.g. IntelliJ IDEA)
-
JDK 17 or greater installed with
JAVA_HOME
configured appropriately -
An AWS account with:
-
Already created EKS. For that, you can follow Getting started with Amazon EKS – AWS Management Console and AWS CLI guide.
Some of the following commands use jq
jq is a lightweight and flexible command-line JSON processor
3. The Application
Download the complete solution of the Kubernetes and the Micronaut Framework guide. You will use same three microservices (users
, orders
, and api
) as a starting point.
4. Prepare and Deploy Microservices
We will define some environment variables to make deploying process easier. In AWS_ACCOUNT_ID
store your AWS account id and in the AWS_REGION
variable store your AWS region, both you can find by executing commands in aws cli. We will store our EKS cluster name in EKS_CLUSTER_NAME
. For this guide we will use micronaut-k8s
.
Run the next command to log in to Amazon Elastic Container Registry (Amazon ECR):
aws ecr get-login-password --region $AWS_REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com
4.1. Users Microservice
Edit k8s.yml
inside users
service.
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: micronaut-k8s
name: "users"
spec:
selector:
matchLabels:
app: "users"
template:
metadata:
labels:
app: "users"
spec:
serviceAccountName: micronaut-service
containers:
- name: "users"
image: <aws-account-id>.dkr.ecr.<aws-region>.amazonaws.com/users:latest (1)
imagePullPolicy: Always (2)
ports:
- name: http
containerPort: 8080
readinessProbe:
httpGet:
path: /health/readiness
port: 8080
initialDelaySeconds: 5
timeoutSeconds: 3
livenessProbe:
httpGet:
path: /health/liveness
port: 8080
initialDelaySeconds: 5
timeoutSeconds: 3
failureThreshold: 10
---
apiVersion: v1
kind: Service
metadata:
namespace: micronaut-k8s
name: "users"
spec:
selector:
app: "users"
type: NodePort
ports:
- protocol: "TCP"
port: 8080
1 | Repository URI that we created in ECR container registry. Change the <aws-region> to your region and change the <aws-account-id> to your aws account id. You can achieve this by running sed -i'' -e "s/<aws-region>/$AWS_REGION/" users/k8s.yml and sed -i'' -e "s/<aws-account-id>/$AWS_ACCOUNT_ID/" users/k8s.yml |
2 | Change imagePullPolicy to Always Create container repository in your AWS account. |
export USERS_REPOSITORY=$(aws ecr create-repository --repository-name users --image-scanning-configuration scanOnPush=true --region us-east-1 --output json | jq -r .repository.repositoryUri)
Build a docker image of the users
service with the name users
.
Ensure that Docker images are constructed for the correct CPU architecture. For instance, if you’re utilizing Apple Silicon (aarch64), you can consider modifying the DOCKER_DEFAULT_PLATFORM environment variable to the value linux/amd64 . Alternatively, you have the option to use ARM (arch64) instances within your Kubernetes cluster.
|
Tag an existing users microservice image.
docker tag users:latest ${USERS_REPOSITORY}:latest
Push tagged users microservice image to remote repository.
docker push ${USERS_REPOSITORY}:latest
4.2. Orders Microservice
Edit k8s.yml
inside orders
service.
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: micronaut-k8s
name: "orders"
spec:
selector:
matchLabels:
app: "orders"
template:
metadata:
labels:
app: "orders"
spec:
serviceAccountName: micronaut-service
containers:
- name: "orders"
image: <aws-account-id>.dkr.ecr.<aws-region>.amazonaws.com/orders:latest (1)
imagePullPolicy: Always (2)
ports:
- name: http
containerPort: 8080
readinessProbe:
httpGet:
path: /health/readiness
port: 8080
initialDelaySeconds: 5
timeoutSeconds: 3
livenessProbe:
httpGet:
path: /health/liveness
port: 8080
initialDelaySeconds: 5
timeoutSeconds: 3
failureThreshold: 10
---
apiVersion: v1
kind: Service
metadata:
namespace: micronaut-k8s
name: "orders"
spec:
selector:
app: "orders"
type: NodePort
ports:
- protocol: "TCP"
port: 8080
1 | Repository URI that we created in ECR container registry. Change the <aws-region> to your region and change the <aws-account-id> to your aws account id. You can achieve this by running sed -i'' -e "s/<aws-region>/$AWS_REGION/" orders/k8s.yml and sed -i'' -e "s/<aws-account-id>/$AWS_ACCOUNT_ID/" orders/k8s.yml |
2 | Change imagePullPolicy to Always Create container repository in your AWS account. |
export ORDERS_REPOSITORY=$(aws ecr create-repository --repository-name orders --image-scanning-configuration scanOnPush=true --region us-east-1 --output json | jq -r .repository.repositoryUri)
Build a docker image of the orders
service with the name orders
.
Ensure that Docker images are constructed for the correct CPU architecture. For instance, if you’re utilizing Apple Silicon (aarch64), you can consider modifying the DOCKER_DEFAULT_PLATFORM environment variable to the value linux/amd64 . Alternatively, you have the option to use ARM (arch64) instances within your Kubernetes cluster.
|
Tag an existing orders microservice image.
docker tag orders:latest ${ORDERS_REPOSITORY}:latest
Push tagged orders microservice image to remote repository.
docker push ${ORDERS_REPOSITORY}:latest
4.3. API Microservice
Edit k8s.yml
inside api
service.
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: micronaut-k8s
name: "api"
spec:
selector:
matchLabels:
app: "api"
template:
metadata:
labels:
app: "api"
spec:
serviceAccountName: micronaut-service
containers:
- name: "api"
image: <aws-account-id>.dkr.ecr.<aws-region>.amazonaws.com/api:latest (1)
imagePullPolicy: Always (2)
ports:
- name: http
containerPort: 8080
readinessProbe:
httpGet:
path: /health/readiness
port: 8080
initialDelaySeconds: 5
timeoutSeconds: 3
livenessProbe:
httpGet:
path: /health/liveness
port: 8080
initialDelaySeconds: 5
timeoutSeconds: 3
failureThreshold: 10
---
apiVersion: v1
kind: Service
metadata:
namespace: micronaut-k8s
name: "api"
spec:
selector:
app: "api"
type: LoadBalancer
ports:
- protocol: "TCP"
port: 8080
1 | Repository URI that we created in ECR container registry. Change the <aws-region> to your region and change the <aws-account-id> to your aws account id. You can achieve this by running sed -i'' -e "s/<aws-region>/$AWS_REGION/" api/k8s.yml and sed -i'' -e "s/<aws-account-id>/$AWS_ACCOUNT_ID/" api/k8s.yml |
2 | Change imagePullPolicy to Always Create container repository in your AWS account. |
export API_REPOSITORY=$(aws ecr create-repository --repository-name api --image-scanning-configuration scanOnPush=true --region us-east-1 --output json | jq -r .repository.repositoryUri)
Build a docker image of the api
service with the name api
.
Ensure that Docker images are constructed for the correct CPU architecture. For instance, if you’re utilizing Apple Silicon (aarch64), you can consider modifying the DOCKER_DEFAULT_PLATFORM environment variable to the value linux/amd64 . Alternatively, you have the option to use ARM (arch64) instances within your Kubernetes cluster.
|
Tag an existing api microservice image.
docker tag api:latest ${API_REPOSITORY}:latest
Push tagged api microservice image to remote repository.
docker push ${API_REPOSITORY}:latest
4.4. Deploy Services to EKS
Create a directory for kubectl
configuration.
mkdir -p $HOME/.kube
Generate kubectl
configuration for authentication to EKS.
aws eks update-kubeconfig --region $AWS_REGION --name $EKS_CLUSTER_NAME
Set KUBECONFIG
to the created config file. This variable is consumed by kubectl
.
export KUBECONFIG=$HOME/.kube/config
Deploy the auth.yml file that we created in the Kubernetes and the Micronaut Framework guide.
kubectl apply -f auth.yml
Run the next command to deploy for users
microservice:
kubectl apply -f users/k8s.yml
Run the next command to deploy for orders
microservice:
kubectl apply -f orders/k8s.yml
Run the next command to deploy for api
microservice:
kubectl apply -f api/k8s.yml
5. Test integration between applications deployed on EKS
Run the next command to check status of the pods and make sure that all of them have the status "Running":
kubectl get pods -n=micronaut-k8s
NAME READY STATUS RESTARTS AGE
api-6fb4cd949f-kxxx8 1/1 Running 0 2d1h
orders-595887ddd6-6lzp4 1/1 Running 0 2d1h
users-df6f78cd7-lgnzx 1/1 Running 0 2d1h
Run the next command to check the status of the microservices:
kubectl get services -n=micronaut-k8s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
api LoadBalancer 10.100.208.154 <redacted> 8080:31171/TCP 30s
orders NodePort 10.100.157.155 <none> 8080:30742/TCP 20m
users NodePort 10.100.126.97 <none> 8080:31580/TCP 20m
If EXTERNAL-IP is in <pending> state wait a couple of seconds and then run command again. AWS will provide you a hostname instead of ip address. To access your application you will have to wait that DNS can resolve hostname that was created.
|
Run the next command to retrieve the URL of the api
microservice:
export API_URL=http://$(kubectl get svc api -n=micronaut-k8s -o json | jq -r '.status.loadBalancer.ingress[0].hostname'):8080
Run a cURL command to create a new user via the api
microservice:
curl -X "POST" "$API_URL/api/users" -H 'Content-Type: application/json; charset=utf-8' -d '{ "first_name": "Nemanja", "last_name": "Mikic", "username": "nmikic" }'
{"id":1,"username":"nmikic","first_name":"Nemanja","last_name":"Mikic"}
Run a cURL command to a new order via the api
microservice:
curl -X "POST" "$API_URL/api/orders" -H 'Content-Type: application/json; charset=utf-8' -d '{ "user_id": 1, "item_ids": [1,2] }'
{"id":1,"user":{"first_name":"Nemanja","last_name":"Mikic","id":1,"username":"nmikic"},"items":[{"id":1,"name":"Banana","price":1.5},{"id":2,"name":"Kiwi","price":2.5}],"total":4.0}
Run a cURL command to list created orders:
curl "$API_URL/api/orders" -H 'Content-Type: application/json; charset=utf-8'
[{"id":1,"user":{"first_name":"Nemanja","last_name":"Mikic","id":1,"username":"nmikic"},"items":[{"id":1,"name":"Banana","price":1.5},{"id":2,"name":"Kiwi","price":2.5}],"total":4.0}]
We can try to place an order for a user who doesn’t exist (with id 100). Run a cURL command:
curl -X "POST" "$API_URL/api/orders" -H 'Content-Type: application/json; charset=utf-8' -d '{ "user_id": 100, "item_ids": [1,2] }'
{"message":"Bad Request","_links":{"self":[{"href":"/api/orders","templated":false}]},"_embedded":{"errors":[{"message":"User with id 100 doesn't exist"}]}}
6. Cleaning Up
To delete all resources that were created in this guide run next command.
kubectl delete namespaces micronaut-k8s
Run the next command to delete micronaut-k8s/users
artifacts container repository:
aws ecr delete-repository --repository-name users --force
Run the next command to delete micronaut-k8s/orders
artifacts container repository:
aws ecr delete-repository --repository-name orders --force
Run the next command to delete micronaut-k8s/api
artifacts container repository:
aws ecr delete-repository --repository-name api --force
NOTE: If you were following the Getting started with Amazon EKS – AWS Management Console and AWS CLI and you want to clean up everything, don’t forget to follow Step 5: Delete resources chapter.
7. Next Steps
Explore more features with Micronaut Guides.
Read more about Micronaut Kubernetes module.
Read more about Amazon Elastic Kubernetes Service (EKS)
8. License
All guides are released with an Apache license 2.0 license for the code and a Creative Commons Attribution 4.0 license for the writing and media (images…). |