Containers

Microservices development using AWS controllers for Kubernetes (ACK) and Amazon EKS blueprints

Introduction

Microservices architectures make applications easier to scale and faster to develop, which enables innovation and accelerating time-to-market for new features. For business applications with multiple clients (web, mobile, desktop, and smart devices), the application programming interface (API) Gateway microservices design pattern is helpful for adding centralized control and security. Containers and serverless are two main technologies to enable microservices application development. For building serverless applications, developers have commonly used solutions like AWS Serverless Application Model (AWS SAM) to define APIs, databases, and event source mappings.

With Kubernetes gaining in popularity for building microservices applications, some customers prefer to provision and configure AWS resources such as Amazon API Gateway, Amazon Simple Storage Service (Amazon S3) buckets, and Amazon Relational Database Service (Amazon RDS) instances by using the kubernetes API and configuration language. In this post, we use AWS Controllers for Kubernetes (ACK) along with AWS Load Balancer Controller to fulfill this need. Using ACK, you can create and configure API Gateway resources and DynamoDB tables the same way you create and configure a Kubernetes deployment or service. AWS Load Balancer Controller  is for creating Application Load Balancer (ALB) and Amazon EKS Blueprints for Terraform is used to automate resources provisioning.

Solution overview

Implement API gateway microservices design using ACK controllers

ACK let’s you define and use AWS service resources directly from Kubernetes. With ACK, you take advantage of AWS-managed services for your Kubernetes applications without needing to define resources outside of the cluster or run services that provide supporting capabilities (e.g., databases or message queues) within the cluster. The ACK project contains a series of service controllers, with one for each AWS service API.

In this post, we’ll create an Amazon Elastic Kubernetes Service (Amazon EKS) cluster with ACK controllers and AWS Load Balancer Controller. A sample application is deployed and exposed using an internal ALB. The sample application uses a DynamoDB table as storage, which is provisioned by the ACK DynamoDB controller. Then, we’ll use an ACK API Gateway controller to create an API Gateway HTTP API with a route linking to the sample application through VpcLink.

The solution architecture is shown in the following diagram:

Although this post uses only the ACK API Gateway controller and ACK DynamoDB controller, the architecture remains identical if you choose to use other ACK controllers. Please check this link for more examples.

Provision Amazon EKS cluster and install ACK controllers using AWS EKS Blueprints for Terraform

Prerequisites

Ensure that you have the following tools installed locally:

  1. Amazon Command Line Interface (AWS CLI)
  2. kubectl
  3. Terraform
  4. Docker

Walkthrough

Since each ACK service controller requires different AWS Identify and Access Management (AWS IAM) roles for managing AWS resources, it’s better use an automation tool to install the required service controllers. We choose to use Amazon EKS Blueprints for Terraform to provision the following components:

  • A new Virtual Private Cloud (VPC) with three Private Subnets and three Public Subnets
  • Internet gateway for Public Subnets and NAT Gateway for Private Subnets
  • Amazon EKS Cluster Control plane with one managed node group
  • Amazon EKS Managed Add-ons: VPC_CNI, CoreDNS, and Kube_Proxy
  • AWS Load Balancer controller and ACK controllers
  • API Gateway VpcLink
  • DynamoDB read/write IAM role for sample API application

Let’s start by cloning the code repo to your local. The module eks_ack_addons in main.tf is for installing ACK controllers.

ACK controllers are installed by using helm charts in Amazon ECR public galley. You need to log in before running the Terraform script.

cd terraform-aws-eks-ack-addons/examples/complete
aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws
terraform init
terraform plan
terraform apply -auto-approve -var aws_region=<aws_region> #defaults to us-west-2

Once done, you’ll get the outputs similar to the following diagram. You need to modify your deployment yaml files with those output values in the following steps.

Configure kubeconfig

Use the configure_kubectl output from the Terraform output to configure your kubectl access from your workstation.

region=<your region> # set region variable for following commands
aws eks --region $region update-kubeconfig --name ack-eks-complete

Verify cluster access

Ensure kubectl access is configured correctly.

kubectl get nodes

Deploy the sample application

The sample application is a simple NodeJS API application that has two API methods. The post /rows/add method takes input payload and saves it to DynamoDB. The get /rows/all method fetches all the data from the DynamoDB table and returns to frontend. The sample application relies on the IAM role created by Amazon EKS Blueprints above to access DynamoDB.

Modify app.yaml before deployment:

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-api-dynamodb
  namespace: ack-demo
....

    env:
    - name: aws_region
        value: "<same region as your eks cluster>" # replace with your region 
kubectl apply -f sample-app/app.yaml

Verify the deployment is successful:

kubectl get pods -n ack-demo

The deployment script exposes the API application through an internal ALB. Use the script below to get the ALB listener arn:

aws elbv2 describe-listeners \
  --region $region \
  --load-balancer-arn $(aws elbv2 describe-load-balancers \
  --region $region \
  --query “LoadBalancers[?contains(DNSName, ‘$(kubectl get ingress ingress-api-dynamodb -n ack-demo -o=jsonpath=”{.status.loadBalancer.ingress[].hostname}”)’)].LoadBalancerArn” \
  --output text) \
  --query “Listeners[0].ListenerArn” \
  --output text

Deploy API gateway resources

The ACK controller for API Gateway and the VPClink, which is required for connecting API Gateway with internal ALB, have been created by the Amazon EKS Blueprints.

Update apigwv2-httpapi.yaml before deploy:

apiVersion: apigatewayv2.services.k8s.aws/v1alpha1
kind: Integration
metadata:
  name: "vpc-integration"
spec:
  apiRef:
    from:
      name: "ack-api"
  integrationType: HTTP_PROXY
  integrationURI: "<your ALB listener arn>" # replace
  integrationMethod: ANY
  payloadFormatVersion: "1.0"
  connectionID: "<your vpclink id>" # api_gatewayv2_vpc_link_id in terraform output
  connectionType: "VPC_LINK"
kubectl apply -f sample-app/apigwv2-httpapi.yaml

Verify API Gateway is deployed via the AWS CLI:

aws apigatewayv2 get-apis --region $region

Next, let’s verify the integration with ALB was created successfully:

aws apigatewayv2 get-integrations --api-id <insert-api-id> --region $region

Deploy DynamoDB table

Deploy the DynamoDB table and verify it was created successfully:

kubectl apply -f sample-app/dynamodb-table.yaml
aws dynamodb list-tables --region $region

Test API methods

Now, you have deployed all the components for your API methods. Let’s use the following script to get the API gateway endpoint and test:

URL=$(kubectl get -n ack-demo api ack-api -o jsonpath="{.status.apiEndpoint}") 

We first test the post method with curl:

curl -X POST $URL/rows/add -H 'Content-Type: application/json' -d '{"name": "external"}'

Response: 
{"success":true} 

Then test get method  <your api gateway endpoint>/rows/all. Since we only posted one record, you only see one record returned for now.

curl $URL/rows/all

Response:
["external"]

Cleaning up

kubectl delete -f sample-app/.

### Please wait a couple of minutes for ACK deleting resources before running code below
terraform destroy -target="module.eks_ack_addons" -target="module.eks_blueprints_kubernetes_addons" -auto-approve -var aws_region=$region
terraform destroy -target="module.eks_blueprints" -auto-approve -var aws_region=$region
terraform destroy -auto-approve -var aws_region=$region

Conclusion

In this post, we showed how to deploy microservices API application to your Amazon EKS cluster only using Kubernetes API and commands. The AWS Controller for Kubernetes allows you to manage Amazon API Gateway and DynamoDB in the same way you manage Kubernetes resources (e.g., pods, deployments, services, ingresses, and so on). Amazon EKS Blueprints automates the Amazon EKS cluster provision and ACK controller installation.

With ACK, you can create and manage more AWS services like Amazon RDS, Amazon S3, AWS Lambda, and others from your Amazon EKS cluster. Please refer to this link for the supported service list. Amazon EKS Blueprints for Terraform can be used to provision many other Kubernetes add-ons. Please refer to this link for the add-ons list.

Victor Gu

Victor Gu

Victor Gu is a Containers & Serverless Architect at Amazon Web Services. He works with AWS customers to design microservices and cloud native solutions using Amazon EKS/ECS and AWS serverless services. His specialties are Kubernetes, Spark on Kubernetes, MLOps and DevOps.

Apoorva Kulkarni

Apoorva Kulkarni

Apoorva is a Sr. Specialist Solutions Architect, Containers, at AWS where he helps customers who are building modern application platforms on AWS container services.