Introduction
In recent years, Microservices gained a lot of popularity and most of the systems are adopting this new architecture to develop Line of business applications. However, Microservices might not be a single solution for everyone or every problem. Let’s say if you got an independent team to build and manage independent modules in your system, then it might be an ideal approach. Having said that, it could be a better architecture even for single team projects to develop complex distributed applications and deploy it in any cloud environment.
You can find good resources to learn more about Microservices here.
In this series, I am going to take you on a ride, how to deploy dotnet core Microservices in AWS using ECS Fargate.
Why ECS Fargate?
I love serverless frameworks like AWS lambda and Azure functions. However, they got few limitations around memory, timeout and framework versions. Let's say you got a component which requires more than 3 GB Memory to process its work and/or it might take more than 10 mins and/or it uses an older .NET Core Framework or Node js framework. AWS fargate is a serverless framework to deploy apps on ECS containers, without requiring us to maintain Host machine. We have the freedom to choose framework and memory allocation for these containers.
Prerequisites
- I am assuming you have already worked with ASP.NET Core apps.
- You need to have some basic understanding of AWS services such as EC2, ECS, ELB, ECR, IAM and AWS configuration.
- Dotnet core SDK, AWS CLI, Docker and Visual Studio code or any IDE should be installed in the development machine.
Application Architecture
- I created one application for Vehicle insurance use case. Any client can make REST calls to Metadata service to create/update customer, vehicles information and requests for vehicle insurance quotations. Quote will be generated on server and sent back to clients. Once you pick a quote, the client should call policy service to process and create policy.
- I created two simple ASP.NET Core webapi projects for these services, one to manage basic information like customer, vehicle and quotes. And the other one to manage policies.
- Each service will interact with its own database to make these services purely independent.
- Data between these databases can be synced or changed using Event patterns, which will be out of scope for this demo.
AWS Infrastructure Architecture
We will deploy this simple micro-services to AWS ECS cluster using Fargate.
- Every request from clients can come to a single Application load balancer and then the request will be forwarded to respective target groups by matching URL pattern.
- The idea is to create a unique Target group for each service, so that they will forward the requests to service Containers, that are launched in ECS cluster using Fargate.
- APIs running in ECS containers should be able to communicate with database services such as SQL Server RDS, Elasticache and DynamoDB in the same VPC.
Readiness of ASP.NET Core WebAPI
Let's first understand the necessary parts in ASP.NET Core webapi
services to be able to deploy in ECS cluster.
- All lookup data and session related data should be stored in a single instance redis cache or some common database, so that all service instances should be able to access data from single repository.
services.AddStackExchangeRedisCache(options =>
{
options.Configuration = Configuration["Cache:AWSRedisEndPoint"];
});
- Every service should have a health check route configured, to check service is running in container from ELB. I used built in middleware to configure this.
services.AddHealthChecks();
app.UseHealthChecks("/health");
- All routes in a service should have a common base route path, so that requests from ELB should be able to send to this service target group by matching the base route path.
[Route("metadataapi/[controller]")]
public class CustomersController : ControllerBase
[Route("metadataapi/[controller]")]
public class VehiclesController : ControllerBase
- I used swagger for API discovery documentation. This swagger configuration should also consider using base route path.
app.UseSwagger(c =>
{
c.RouteTemplate="policyapi/swagger/{documentName}/swagger.json";\
});
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/policyapi/swagger/v1/swagger.json","APIdoc");
c.RoutePrefix = "policyapi/swagger";
});
Docker Image to Run Container on ECS
- Docker is a platform to create and deploy application containers on Host machine. If you have not worked on Docker earlier, please consider going through some basics. I loved this pluralsight course.
- I created docker file for each service with basic instructions to build API image.
- I also created a docker-compose file to build and run these containers in local host machine.
- You will require to create a .env file setup environment variables to service
- Build and run images in containers by using this command in terminal:
docker-compose up -d --build
- Make sure the API services are running fine in container by navigating to swagger URLs http://localhost:8080/metadataapi/swagger
- Create image Repositories for each service using this command:
aws ecr create-repository --repository-name metadata-api
- You can also create repository by logging into AWS ECR console.
- Tag running service images with ECR repository URIs with:
docker tag metadataapi:latest
875373411184.dkr.ecr.us-west1.amazonaws.com/insurancemetadata:latest
- Login to ECR to push this image to cloud. We need to run this command to generate login command.
aws ecr get-login --no-include-email --region us-west-2
- Copy and paste the output from the above command in the terminal to perform actual login.
- Once you login successfully, push these service images to Cloud.
docker push
875373411184.dkr.ecr.us-west-1.amazonaws.com/insurancemetadata
Deploy Service Images in ECS Cluster using Cloudformation
Once docker images are pushed to ECR repository, then we can deploy the services using the following two cloud-formation templates.
- First one to create common resources like Load balancer, securitygroups and Cluster.
- Second one to configure service in containers using Fargate and also creates necessary IAM roles, target groups, Task definition and ECS Service.
We need to create one stack for each service in our application by passing the necessary parameters.
Deploy Service Images in ECS Cluster using AWS Console
We learned how to deploy dotnet microservices in AWS ECS Fargate using cloudformation. In this section, we will deploy the same application using AWS Console to understand each AWS service.
Step 1: Application Load Balancer -ELB
-
We use ELB to distribute http requests to all ECS containers equally. ELB is fully manager load balancer in AWS
-
Once the API images are pushed to AWS ECR Repository, just verify they exist in AWS console.
-
Navigate to EC2 Service, click on Load balancers, Select Create Load Balancer and select Application Load Balancer.
- Enter basic information an select VPC and subnets:
- Configure Securitygroup, with required IP address to allow access ELB.
- Enter Default Target-group name and settings. Also:
- Review and click Create and navigate to the ELB Dashboard.
- Navigate to Listeners tab and click on View/edit rules link .
- Navigate to Edit tab and edit default rule to return fixed response 503.
- Click on Update button and Find the DNS Name of ELB and browse.
Step 2: ECS Cluster
- ECS is an AWS custom orchestration for containers in Cloud.
- Navigate to ECS, select Cluster and click on Create Cluster.
- Select Network Only option as Cluster Template. This tells ECS to use Fargate.
- Enter name and click Create.
Step 3: ECS TaskDefinition and ECS Service
Conclusion
Repeat Step 3 for all other services in your micro service application and they should be available on the same ELB DNS URL with different routes.
With this approach, you can deploy micro services without affecting other services. Obviously, this UI approach is just to understand the various services. Mostly, we should use some type of infrastructure as code technology like Cloud-formation or Terraform or AWS Code Deploy to integrate with our CI/CD tools.
References
History
- 18th April, 2019: Initial version