AWS ECS service with multiple task need load balancer - amazon-web-services

I have the following stack (deployed by CloudFormation):
SQS queue that trigger a lambda function
The lambda function is calling an ECS service (by http post request - which is an express.js server)
I am going to create an autoscaling configuration for the ECS service to scale up and down based on SQS metric.
If there will be multiple tasks in the service (means there were a lot of SQS messages) how will the service manage the calls to the tasks? will I need to add a load balancer for the service? or the service know how to balance it between the tasks without load balancer?

I think there are two ways to deal with this.
Use load balancer as you pointed out. It can be internal load balancer. In this case, lambda will be associated with a VPC and will call the balancer's private dns.
Use ECS service discovery. This can also server as sort-of load balancer, though not as feature reach as regular balancer. The reason is that the private url associated with the service will return multiple IPs of its tasks, and the distribution of incoming requests is based on DNS cache timeouts. After each timeout, the IPs will be in different order. For this lambda would also be in a vpc and use private url associated with the ECS service to invoke your service.

Related

Is there a way to configure health checks to an ECS service without a load balancer?

I have an ECS Cluster with 2 ECS Services (1 app-controller, 1 app-event-processor). Is there a way to get health checks on both while API traffic only goes to app-controller? I realize health checks normally come from the load balancer but if I configure the load balancer to hit app-event-processor then API traffic also starts flowing to app-event-processor which is undesirable since I want that to handle only messages from SQS for example.
As #jordanm mentioned in their comment ECS does provide a built in health-check mechamism that is orthogonal (and in addition) to the "outside" LB health-check.

Do I need a loadbalancer in an AWS elastic beanstak environment

My applications run on ElasticBeanstalk and communicate purely with internal services like Kinesis and DynamoDB. There is no web traffic needed? Do I need an ElasticLoadBalancer in order to scale my instances up and down. I want to add and remove instances purely based on some cloudwatch metrics? Do I need the ELB to do managed updates etc.?
If there is no traffic to the service then there is no need to have a load balancer.
In fact the load balancer is primarily to distribute inbound traffic such as web requests.
Autoscaling can still be accomplished without a load balancer with scaling based on the CloudWatch metric that you want to use. In fact this is generally how consumer based applications tend to work.
To create this without a load balancer you would want to configure you environment as a worker environment.
#Chris already anwsered, but I would like to complement his answer for the following:
There is no web traffic needed?
Even if you communicate with Kinesis and DynamoDB only, your instances still need to be able to access internet to communicate with the AWS services. So the web traffic is required from your instances. The direct inbound traffic to your instances is not needed.
To fully separate your EB env from the internet you should have a look at the following:
Using Elastic Beanstalk with Amazon VPC
The document describes what you can do and want can't be done when using private subnets.

AWS ECS Private and Public Services

I have a scenario where I have to deploy multiple micro-services on AWS ECS. I want to make services able to communicate with each other via APIs developed in each micro-service. I want to deploy the front-end on AWS ECS as well that can be accessed publicly and can also communicate with other micro-services deployed on AWS ECS. How can I achieve this? Can I use AWS ECS service discovery by having all services in a private subnet to enable communication between each of them? Can I use Elastic Load Balancer to make front-end micro-service accessible to end-users over the internet only via HTTP/HTTPS protocols while keeping it in a private subnet?
The combination of both AWS load balancer ( for public access) and Amazon ECS Service Discovery ( for internal communication) is the perfect choice for the web application.
Built-in service discovery in ECS is another feature that makes it
easy to develop a dynamic container environment without needing to
manage as many resources outside of your application. ECS and Route 53
combine to provide highly available, fully managed, and secure service
discovery
Service discovery is a technique for getting traffic from one container to another using the containers direct IP address, instead of an intermediary like a load balancer. It is suitable for a variety of use cases:
Private, internal service discovery
Low latency communication between services
Long lived bidirectional connections, such as gRPC.
Yes, you can use AWS ECS service discovery having all services in a private subnet to enable communication between them.
This makes it possible for an ECS service to automatically register
itself with a predictable and friendly DNS name in Amazon Route 53. As
your services scale up or down in response to load or container
health, the Route 53 hosted zone is kept up to date, allowing other
services to lookup where they need to make connections based on the
state of each service.
Yes, you can use Load Balancer to make front-end micro-service accessible to end-users over the internet. You can look into this diagram that shows AWS LB and service discovery for a Web application in ECS.
You can see the backend container which is in private subnet, serve public request through ALB while rest of the container use AWS service discovery.
Amazon ECS Service Discovery
Let’s launch an application with service discovery! First, I’ll create
two task definitions: “flask-backend” and “flask-worker”. Both are
simple AWS Fargate tasks with a single container serving HTTP
requests. I’ll have flask-backend ask worker.corp to do some work and
I’ll return the response as well as the address Route 53 returned for
worker. Something like the code below:
#app.route("/")
namespace = os.getenv("namespace")
worker_host = "worker" + namespace
def backend():
r = requests.get("http://"+worker_host)
worker = socket.gethostbyname(worker_host)
return "Worker Message: {]\nFrom: {}".format(r.content, worker)
Note that in this private architecture there is no public subnet, just a private subnet. Containers inside the subnet can communicate to each other using their internal IP addresses. But they need some way to discover each other’s IP address.
AWS service discovery offers two approaches:
DNS based (Route 53 create and maintains a custom DNS name which
resolves to one or more IP addresses of other containers, for
example, http://nginx.service.production Then other containers can
send traffic to the destination by just opening a connection using
this DNS name)
API based (Containers can query an API to get the list of IP address
targets available, and then open a connection directly to one of the
other container.)
You can read more about AWS service discovery and use cases amazon-ecs-service-discovery and here
According to the documentation, "Amazon ECS does not support registering services into public DNS namespaces"
In other words, when it registers the DNS, it only uses the service's private IP address which would likely be problematic. The DNS for the "public" services would register to the private IP addresses which would only work, for example, if you were on a VPN to the private network, regardless of what your subnet rules were.
I think a better solution is to attach the services to one of two load balancers... one internet facing, and one internal. I think this works more naturally for scaling the services up anyway. Service discovery is cool, but really more for services talking to each other, not for external clients.
I want to deploy the front-end on AWS ECS as well that can be accessed publicly and can also communicate with other micro-services deployed on AWS ECS.
I would use Service Discovery to wire the services internally and the Elastic Load Balancer integration to make them accessible for the public.
The load balancer can do the load balancing on one side and the DNS SRV records can do the load balancing for your APIs internally.
There is a similar question here on Stack Overflow and the answer [1] to it outlines a possible solution using the load balancer and the service discovery integrations in ECS.
Can I use Elastic Load Balancer to make front-end micro-service accessible to end-users over the internet only via HTTP/HTTPS protocols while keeping it in a private subnet?
Yes, the load balancer can register targets in a private subnet.
References
[1] https://stackoverflow.com/a/57137451/10473469

aws load balancer for non-https microservices

If I have a microservice that does not have http/https endpoints, and its sole purpose is to pull data from an ActiveMQ queue. It is possible to to set up a load balancer that doesn't require a http/https listener on the microservice?
From aws support:
"In this scenario, if you are hosting your services, which are responsible for pulling up data from Active MQ, on EC2 instances, you can make use Auto Scaling with the appropriate scaling policy. This will help you accomplish scaling up and down of the instances according to the load requirement or settings"
This is what I was looking for

How can you launch ECS Fargate containers having a public DNS?

I've built an AWS CodePipeline to build and deploy containers into Fargate managed EC2 instances. Ref AWS CodePipeline
One of the services is a web server and I'm attempting to access it from the public which is possible via a public assigned IP address; however, that's not very useful as each deployed container receives a fresh IP address.
I understand it's possible to setup Elastic IP addresses or point a domain to the container service but I'd think there is an easier way.
EC2 instances can be launched with the option of providing a Public DNS...
Is it possible to launch container services with a static public DNS record? If so, how?
Most Common Choice: ALB
Although it's not free, normally if you want a public DNS name to an ECS service (fargate or EC2) you'd front it with a load balancer (which can also do SSL termination, if you so desire).
Because of that, AWS makes it easy to create a load balancer or add your service to an existing target group when you're setting up a service. I don't think you can change that after the fact, so you may need to recreate the service.
Finally, when you have a load balancer in front of the ECS service, you just need to set up a CNAME or an A ALIAS in Route53 (if you're using Route53) to direct a DNS name to that load balancer.
AWS has a walkthrough from 2016 on the AWS Compute Blog quickly describing how to set up an ECS service and expose it using an Application Load Balancer.
ECS Service Connect
ECS Service Connect was announced at ReInvent 2022, and seems to let you connect to a load-balanced ECS service without using an ALB or an API Gateway.
CloudMap / Service Discovery / API Gateway
With ECS Service Discovery and AWS CloudMap, you can use an API Gateway. Your load balancing options are more limited, but API Gateways are billed based on usage rather than hours, so it can potentially save costs on lower-volume services. You can also use a single API Gateway in front of multiple ECS services, which some people are going to want to do anyway. This approach is less commonly employed, but might be the right path for some uses.
You can use ECS Service Discovery for registering your containers in a private DNS namespace - unfortunately this is not possible with public DNS.
But, what you can do, is to have a script
fetch your containers' public IP after redeployment and
upsert your public Route 53 record set with that IP.
In this article, we describe how to do exactly that by using a generic lambda function.
When I set up an ECS Fargate service for the first time, the setup wizard seems to have automatically (?) created a load balancer for me. I was able to access the web app that I created via the URL at Amazon ECS -> Clusters -> {my cluster} -> {my service} -> Target Group Name (under Load Balancing in the Details tab) -> {my target group} -> Load Balancer -> DNS Name