Docker Swarm x AWS ALB x Traefik - HTTP 504 error being returned - amazon-web-services

We have a Docker Swarm cluster that utilizes Traefik to take care of routing requests to the correct service in the cluster. Out of the box, this works properly. However, when an AWS Application Load Balancer was integrated into the infrastructure (to prepare for AWS Web Application Firewall implementation), services became unreachable. See below:
The idea is that ALB requests go through one of the nodes and then goes to Traefik (port 80) and it routes to the correct Docker container.
Security group misconfiguration is not the issue because when running Nginx as a stand-alone container (docker run -p 80:80 nginx) and accessible through port 80, the ALB is able to access the service successfully.
At first we thought it was an IPv6 issue but disabling IPv6 in the host did not solve anything.
Update: Changing the configuration of Traefik like the one below made it work. I'm not quite sure why this is needed when using ALB.
ports:
- target: 80
published: 80
protocol: tcp
mode: host

hey #jackeblagare do you mind share your entire traefik configuration? we are trying to have the same setup
Route53 entry which point to the ALB DNS + Docker Swarm cluster + traefik / services but it seems that we need to change something because with this current setup the traefik dont receive any traffic and we got time out
if we use NLB with just TCP Listener/HC's work perfect.
I dont think that we need to open any ports because as test purposes we are using a security group that has all ports open ( i know that's not recommended but it's on a sandbox environment )
thanks,

Related

amqplib & AWS MQ: Socket closed abruptly during opening handshake

So the current issue I have is that before I was able to connect properly to my rabbitMQ cluster that was hosted on AWS MQ. After I changed its IP visibility to private I had to create some configuration to access the cluster from outside the VPC.
Current example of how the cluster is accessed:
mq.example.com -> Load balancer (w/target group to cluster host IP & TLS port 5671) in public VPC -> Cluster in private VPC.
I've done the same thing for the web console. Now the web console works perfectly, so the issue isn't necessarily with the load balancing or a certificate issue. I then checked out if the issue could be with the code I wrote, but that is also not the case since sometimes from inside the services it connects, but sometimes it then doesn't. It throws the error: "Socket closed abruptly during opening handshake".
I think I believe where the issue may arise from, however I don't really have a proper view on how to solve it. I believe the issue has to do with the fact that the service has go through the load balancer first before it can connect to the rabbit cluster. I just don't know what to do about it and most documentation on amqplib is obscure as it is. I haven't found any (documented) similar issue with AWS MQ & a load balancer.
So my question, specifically is: How would I be able to resolve the fact that sometimes my services connect and don't connect to the cluster when they go through the load balancer?
Good to know: I use AWS MQ for rabbit, amqplib for the client connection, amqps as the protocol, web console works with the same setup but services don't.
For people who run into this issue later on I have found a solution:
When creating a Network Load Balancer to route traffic to your cluster you have to assign it a target group. Make sure to NOT DO THIS: Do not register both port 5671 (amqps) and 443 (web console) to the same target group. During routing issues will arise like this.
Instead do the following:
Create two target groups on aws EC2:
TG1: Register: TLS - 443 (web console)
TG2: Register: TLS - 5671 (amqps)
Your NLB that is configured to simple routing & alias for IPV4 connections then needs the following listeners:
Listener 1: TLS - 443 and assign it to TG1
Listener 2: TLS - 5671 and assign it to TG2
This should then make sure whenever you connect there is no confusion for the microservice you're trying to connect to the cluster.
You can then connect to your web console with your subdomain:
eg. webconsole.example.com
and to your services: eg. amqps://cluster.example.com:5671 as host (how your host is formatted depends on the library you're using for the clientside)

AWS Elastic Beanstalk load balancer is redirecting to HTTPS - does my app still need UseHttpsRedirection() and UseHsts()?

First, let me say that this is the first time I have written an ASP.NET Core 3.1 web app and first time learning AWS with Elastic Beanstalk. So if it seems like I'm confused... it's because I am. ;-)
I have two AWS environments - one is Staging and one is Production. The Staging environment has no SSL certificate and no load balancer. It only listens on port 80.
Production has a load balancer set up with my SSL certificate, and is set up to redirect all port 80 traffic to port 443.
Port 80 = Redirect to https://#{host}:443/#{path}?#{query}
Status code:HTTP_301
Port 443 = Forward to my-target-group: 1 (100%)
Group-level stickiness: Off
When I generated the new web app in VS 2019, I opted in on HTTPS/HSTS by checking "Configure for HTTPS". So it has this in Startup.cs:
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
I am getting this error in my Windows event log in Staging and Production: “Failed to determine the https port for redirect”
I tried the suggestion from Enforce HTTPS in ASP.NET Core
services.AddHttpsRedirection(options =>
{
options.HttpsPort = 443;
});
But that messed up the Staging environment because there's nothing listening on port 443.
Since Staging is only using HTTP, and Production is redirecting to HTTPS at the load balancer, should I just remove the UseHsts() and UseHttpsRedirection() altogether from my Startup? Will that pose any security problems - I do want traffic encrypted over the internet but I don't think it's necessary between the load balancer and the EC2 instance, correct?
Or do I need Forwarded headers, as suggested at Configure ASP.NET Core to work with proxy servers and load balancers?
I do want traffic encrypted over the internet but I don't think it's necessary between the load balancer and the EC2 instance, correct?
Correct. That's how it is usually setup. So you usually would have SSL termination on your load balancer (LB), and then from LB to your instance it would be regular http traffic:
Client----(https)---->LB----(http)---->instances
does my app still need UseHttpsRedirection() and UseHsts()?
No, as your app is just recieving http traffic only from the LB.

Is it possible to run multiple web instance in the same AWS EC2?

Background
I have followed this tutorial https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-cli-tutorial-ec2.html, composed a docker compose file, made a website A (compose of 4 containers) up and run serving 1 of my client.
However, now I have another client which I need to host another web site website B using similar strategies as above.
Here is the current running service of ECS / EC2
and here are the containers up and running, serving website A now
Questions & concerns
The website A is now situated as 1 of a service in the EC2 under my only cluster, can I use the same EC2 instance and run website B (as another service of the EC2)?
If so, how are the ports / inbound / outbound traffic being managed? Now website A already occupies port 80, 443, 27017 and 3002 of the EC2 instance for inbound traffic, if website B's containers also run in the same EC2 instances, can I still use port 80, 443, 27017 and 3002 for website B. I have read the docs of ALB (Amazon Load Balancer), seems it can fulfill the requirement, am I at the right track?
And the domain name, through route 53, I have registered a domain www.websiteA.com to serve the 1st website, I have also registered another www.websiteB.com preparing to serve website B, in my case, I guess I need to configure the new domain B pointing to the same EC2 IP?
During my deployment of website B, I do not want to affect the availability of website A, can it be maintained during the process of deploying website B's containers?
I want to clear all the concepts before kick-starting to deploy the website B, appreciate for any help, thank you
Follow-up actions
I come up decided to use AWS application load balancer to solve my issue, and have the following configurations setup.
I first look into load balancer
And configured as follows
I setup a load balancer which listens for requests using HTTP protocol with incoming port 80, whenever there are users access the web server (i.e.: the frontend container), listener will forward that request to the target group (i.e.: http-port-80-access)
And here is the target group (http-port-80-access) which contains a registered target (currently my ec2 instance running the containers), the host port of the container is 32849 which in turn made used by the associated load balancer (web-access-load-balancer) for dynamic port mapping.
I have also configured 1 more rule on top of the default rule, whenever user access url of websiteA, load balancer will forward the request to the target group (http-port-80-access).
All things set, and the healthy test also passed. I then used the following ecs-cli compose service up command to wire up the load balancer with the service
ecs-cli compose --file ./docker-compose-aws-prod.yml --cluster my-ecs-cluster-name --ecs-profile my-ecs-profile --cluster-config my-cluster --project-name my-project --ecs-params ./ecs-params.yml service up --target-group-arn arn:aws:elasticloadbalancing:us-east-2:xxxxxxxxx:targetgroup/http-port-80-access/xxxxxxxx --container-name frontend --container-port 80
where frontend is the service name of the frontend container of website A
However, turn out when I access www.websiteA.com through browser, nothing but ERR_CONNECTION_REFUSED, accessing www.websiteA.com:32849 did accessible, but is not what I desired.
I am wondering which part I configured wrongly
If you are sending traffic directly to the instance then you would have to host on a different port. You should consider using an ALB, which would allow you to use dynamic ports in ECS. The ALB can accept traffic from ports 80 and 443 for different domains and route the traffic to different containers based on things like the domain.
The website A is now situated as 1 of a service in the EC2 under my only cluster, can I use the same EC2 instance and run website B (as another service of the EC2)?
Indeed. However - as you already found out, you have to split the traffic based on something (hostname, path,..). That's where the reverse-proxy comes in play (either managed - ALB, NLB or your own - nginx, haproxy,.. ) .
It's simple for the http traffic (based on the host)
If so, how are the ports / inbound / outbound traffic being managed? Now website A already occupies port 80, 443, 27017 and 3002 of the EC2 instance for inbound traffic, if website B's containers also run in the same EC2 instances, can I still use port 80, 443, 27017 and 3002 for website B.
assuming the ports 27017 and the 3002 are using own binary protocol (not http). You will have handle that.
You can in theory define the port mapping (map different public listening port to these custom ports), but then you need to either use NLB (network load balancer) or expose the ports on hosts public IP. In the latter case I'm not sure with ECS you can guarantee which IP is used (e.g. having multiple worker nodes)
I have read the docs of ALB (Amazon Load Balancer), seems it can fulfill the requirement, am I at the right track?
ALB is layer 7 reverse proxy (http), it is imho the best option for the web access, not for binary protocols.
, I guess I need to configure the new domain B pointing to the same EC2 IP?
that's the plan
During my deployment of website B, I do not want to affect the availability of website A, can it be maintained during the process of deploying website B's containers?
shouldn't be a problem
Run website B on different ports. To allow end users to interact with website B without specify port numbers use a reverse-proxy. See AWS CloudFront.

How to bind Docker Container Running Apache to domain

I deployed application based on this stack on AWS where under Rout 53 DNS is set. I want to point my domain (exampl.com) to web server (any apache/nginx) running in docker container. I want to know how can i bind domain to that web server?
I am not sure it's good or bad way to deploy an application on production but it will help me to understand.
as #mipnw suggested, you can easily run your Docker containers in Amazon ECS.
Since you are not using ECS, here is how you can point the domain to the ec2 instance.
Assign an elastic IP address to the ec2 instance
Reference: https://aws.amazon.com/premiumsupport/knowledge-center/ec2-associate-static-public-ip/
Create an A record in AWS Route53 to point to the elastic IP address.
Reference: https://aws.amazon.com/premiumsupport/knowledge-center/route-53-create-alias-records/
if your docker is exposing for e.g port 80 to the host machine.
Now you can access your application via http://example.com (since http default port is 80), for that you should enable port 80 in your instance's security group
Reference: https://aws.amazon.com/premiumsupport/knowledge-center/connect-http-https-ec2/
If your docker is exposing port for e.g 8080 and you want to access the website via http://example.com, you will need to configure apache/nginx proxy to accept the traffic via port 80 or 443 and forward the request to the port exposed by docker (8080 in this example)
Reference: https://dev.to/kevbradwick/how-to-setup-a-reverse-proxy-to-your-host-machine-using-docker-mii
The most difficult part of your setup is setting up SSL, you would need to configure the SSL certificate inside the nginx proxy.
Hope this helps.
You need to host your docker container somewhere. Since you're already using AWS I'd suggest running your container inside AWS ECS.
Then you'll have expose a port on the container, and configure Route53 to point to your container etc... It looks like ECS Service Discovery makes it easier to register your service running inside ECS with Route53.

Load balancing in GCE to cluster

I'm trying to set up Load balancing to my cluster that I created via container engine but I keep getting 502 Server Error.
Here is what I do.
I make sure that my service really runs taking this ip in kubernetes dashboard
I have only one instance group. So this belongs cluster
80 port is open for every instance in Firewall rules
I created a load balancer with this configuration. As you can see I set the only instance group I got, also I set up health check. The health check is http endoint /api/ping/ that returns HTTP 200 with body "pong". But I keep getting 502 ERROR. I understand it happens because health check doesn't pass. Apperently it's because when load balancer is sending request it's sending directly to instances, instead of to docker containers. If I go by ip of vm isntance where I host my cluster I will get nothing as well.
I want to do it so I could switch traffic between different clusters If I decide to create a new one, also I would be able to balance https traffic.
Maybe it will help someone so I will post the answer.
I created my pods via UI kubernetes using their consructor-form. When I used this form ports were not exposed to the host machine(Even I marked them as External ports). I wrote an yaml config and exposed ports there to host machine. After this balancer started working.
I used this block to expose 80 port to host machine
ports:
- containerPort: 80
hostPort: 80
protocol: TCP