Saving on AWS LBs with API GW

Let's say you run a k8s cluster (or ECS if you are old school), and naturally you want to expose something to the outside: some bits to the internal network, some bits to the public internet. If you carelessly create ingresses left and right, you'll likely end up with all combinations of (public or private) x (NLB or ALB).

Each of these LBs incurs hourly costs, for Frankfurt region it's $0.027 / hour for an ALB, and $0.0225 / hour for an NLB, that is $16-$20 per month. Not much, but it adds up quickly once you start adding more environments and applications.

Given we have a reasonable router inside the cluster (Nginx/Envoy/HAProxy/...), does an ALB bring much value? Maybe - but if the whole point of having it is integrations with other AWS services, let me pitch you AWS API Gateway instead.

API GW is the magic sauce that a) doesn't incur hourly charges; b) allows you to turn a private API into a public one. This feature is called private integrations: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-private-integration.html

API GW has two flavors: REST and HTTP, the former significantly more expensive than the latter but also having a lot more features. However, REST API GW only supports private integrations with NLBs, whereas HTTP API GW works with both NLBs and ALBs. So if you are unsure which option suits you better long-term, the safest bet is to go with an NLB - and it's generally more versatile.

Let's run the numbers: when would it make sense to create a public NLB instead of using an API GW to proxy HTTP traffic? If HTTP API GW satisfies your requirements, you'll pay $1.20/million requests, so you need ($1.20/1e6) / ($0.0225/3600) = 0.192 req/s on average to justify an additional NLB. That's hopefully the case for your production environment, but the rest gets much less traffic. You wouldn't want the prod setup different from the rest though, first, because of the misconfiguration risk, and second, because API GW is worthwhile to have - that'd be the point of integration with other AWS services, e.g. Cognito.

There are a few gotchas, though: non-adjustable 29 seconds timeout (30 for HTTP API GW) and 10 MB maximum payload size. For a sanely designed HTTP API this shouldn't be a deal breaker (e.g. you'd use presigned URLs to upload to S3 instead of directly), but it's something to be aware of.