Balu Vyamajala
- Principal Software Engineer
In most micro-service architectures, applications are broken down into multiple small apis which fall into two categories: server or server-less. This blog is about how we serve such content with web apps using AWS services.
Going fully server-less is not always going to be practical
Why not server-less for everything?
My choice is always ‘Go Server-Less’ unless one of the below criteria is met.
- Total Run time: An api is heavily used and is constantly running for more than 50% of the time, setting up a server might actually save some cost.
- Development Time: Imagine building CRUD APIs for a bunch of tables with a framework like Spring Boot vs building multiple NodeJs Lambdas for each table. Time needed on the former is just 10% of time needed for development and Dev-Ops of the later. Setting up a single small server on Fargate is a far easier choice.
- Datastore type: Managing Transmission Control Protocol (TCP) connection pools to relational database in server-less might get tricky and will overhead to API performance especially when running Lambdas within Virtual Private Cloud (VPC) to be able to connect to private Relational Database Service (RDS) or on-prem.
So most of the times we end up having a mix of server and server-less.
Imagine we have a relation database running in RDS in a private subnet in our VPC and we need a bunch of APIs to be exposed with a combination of server and server-less. Let’s put together an architecture.
Server-less APIs
AWS Lambda functions:
- I typically choose a simple NodeJS instead of heavy framework with Java to reduce startup time.
- We can run Lambdas within VPC to be able to connect to RDS privately.
Server APIs
Java Spring boot:
- The simplest choice in my opinion for exposing Rest APIs built as a Docker container deployed to AWS ECS Fargate.
Load Balancer (LB)
- With servers we need to handle scaling, health checks, and monitoring CPU usage, etc.
- Setting up an AWS ELB to redirect requests to a healthy task.
- This can be an internal LB as requests will not be directly from the internet but only from Gateway.
Gateway
Public facing AWS Api Gateway to expose APIs from both Lambdas and Fargate.
- Choose a prefix for Fargate APIs and another prefix for APIs from Lambda. For example /server and /serverLess.
- Any API prefix with /server/** should be proxied to ELB while all other endpoints will be sent to individual Lambdas.
API Gateway to Private Elastic Load Balancing (ELB)
- Integration from AWS API Gateway to a private ELB can only be done to a Network Load Balancer (NLB).
- We must create a VPC link to NLB and redirect /server/{proxy+} to nlb-dns-name/{proxy} via Integration type ‘VPC Link’.
- We don’t need Transport Layer Security (TLS) Termination at NLB, instead an API Gateway will terminate and initiate a new connection to NLB, which is simply passed to Fargate services.
Offloading security outside application code is always a better choice.
API Security
- Likely to get a Bearer Token like a JSON Web Token (JWT) for most of the Authentication types. It is best to offload activities like token validation and parsing outside the application code instead of implementing something like Spring Security within server code.
- We can go with AWS API Gateway Custom Authorizer to validate the token, and set context attributes to pass ID information as http headers.
- The same custom authorizer works for both server and server-less endpoints.