See vars.tf for all the variables you can set on this module.
ALB Terminology
Amazon has its own vocabulary for the ALB that can be confusing. Here's a helpful guide:
Listener: Represents a port open on the ALB that receives incoming traffic (e.g., port 80 for HTTP, 443 for
HTTPs).
Target Group: Represents one or more servers that are listening for requests. You can configure what port(s)
those servers listen on and how to perform health checks on the servers.
Listener Rules: Represents a mapping between Listeners and Target Groups. For each of your Listeners, you can
specify which paths and/or domain names should be routed to which Target Groups. For example, you could configure
path /foo to go to the Target Group foo and /bar to go to bar; or, you could configure foo.my-domain.com to
go to foo and bar.my-domain.com to go to bar; or any combination/permutation of these rules.
Background
What's the difference between an ALB and ELB?
The ELB, now known as the Classic Load Balancer,
is a Layer 4 load balancer, which means that the ELB will accept both
HTTP traffic and TCP traffic. By asking the ELB to simply forward TCP traffic, Amazon users gained the benefit of a
high-availability load balancer with the flexibility of handling any kind of TCP traffic they wanted on their backend
instances.
But over time, it became clear that many customers were running HTTP microservices that needed more "opinionated" functionality
like built-in support for WebSockets, built-in support for HTTP/2, and routing to different backend services depending
on the particular URL requested in the HTTP request. Because these requests are all HTTP-specific, the "flexible" Layer 4
ELB could not be updated to handle these use cases.
In addition, when Amazon released the EC2 Container Service for easily running a Docker cluster, they needed some way
to allow a load balancer to route requests to containers that just launched somewhere in the cluster. The ELB was originally
designed in a pre-container world and was able to route only to a single port across many different EC2 Instances.
This imposed an awkward restriction on the ECS Cluster where you had to run each ECS Task (Docker container) so that it
listened on the same host port. This, in turn, meant you couldn't run two instances of the same Docker container on the
same host, which was one of the main benefits of Docker in the first place.
The ALB was meant to solve both of these problems:
Offer HTTP-specific functionality (known as "Layer 7" functionality)
Allow Docker containers to launch on a dynamic port
ALB Functionality
The ALB gives us the following HTTP-specific functionality compared to the ELB:
Route requests via HTTP or HTTPS
Native support for WebSockets
Native support for HTTP/2
Path-based routing
Hostname-based routing
Ability to route to a Target,
which incorporates both an endpoint and a port and therefore allows different instances of an ECS Service to receive
traffic on different ports.
Better metrics
Support for sticky sessions using load-balancer-generated cookies
The Classic Load Balancer, or ELB, gives us the following unique functionality compared to the ALB:
Route requests via HTTP, HTTPS or TCP
Support for sticky sessions using application-generated cookies
When should I use an ALB vs. ELB?
Based on the above analysis, you should generally prefer the ALB when selecting a load balancer for an HTTP-based service.
There are, of course, still times when the ELB makes sense:
If your service listens on a non-HTTP protocol, such as ZeroMQ.
If you wish to terminate a TLS connection at your service, instead of at the load balancer, only the ELB will support
this. That is, an ALB will accept TLS connections, but it will then open a second HTTP or HTTPS connection to your
backend service. If you want end-to-end encryption, only the ELB can forward the TCP request directly to your backend
service so that the backend service terminates the TLS connection.
If you need the power of Nginx, or HAProxy, but don't want to bother setting these up as a High Availability cluster.
When you use an Application Load Balancer, you will be billed by the hour and for the use of Load Balancer Capacity Units,
also known as LCU’s. An LCU measures the number of new connections per second, the number of active connections, and
data transfer. We measure on all three dimensions, but bill based on the highest one. One LCU is enough to support either:
25 connections/second with a 2 KB certificate, 3,000 active connections, and 2.22 Mbps of data transfer or
5 connections/second with a 4 KB certificate, 3,000 active connections, and 2.22 Mbps of data transfer.
Billing for LCU usage is fractional, and is charged at $0.008 per LCU per hour. Based on our calculations, we believe
that virtually all of our customers can obtain a net reduction in their load balancer costs by switching from a Classic
Load Balancer to an Application Load Balancer.
You may note that if you have 1,000,000 idle WebSocket connections (an "active connection"), this would cost ALB users
$1,920/month! Whereas with the original ELB, your costs will not scale with the number of idle WebSocket connections
(credit to this Hacker News thread for the observation).
Given all the benefits of the ALB, even if you plan to get to massive scale eventually, you may as well start with the
ALB. You can always re-assess at any time.
Using the ALB with ECS
When should I use this module with Amazon ECS?
With the ELB, now known as a Classic Load Balancer,
each ECS Service was fronted by a unique ELB. As a result, each ECS Service module eventually created its own ELB. This
gave us good isolation and made it easy to give each ECS Service a unique DNS name on the same port (e.g. api.acme.com and
stats.acme.com, both on port 443). But it also led to low utilization among all the ELBs, little resource sharing, and
consequently higher costs.
With the ALB, a single ALB is shared among multiple ECS Services. For that reason, after you've created an ALB using this
module, you may wish to create an ECS Cluster using the ecs-cluster module, where you'll pass in the Security
Group ID of the newly created ALB to permit the ALB to forward traffic to the ECS Cluster.
With an ECS Cluster and ALB in place, you can now use the [ecs-service-with-alb]
(https://github.com/gruntwork-io/module-ecs/tree/master/modules/ecs-service-with-alb) module to create a new ECS Service
that contains an ALB Target Group you can configure to receive traffic from an ALB. To do that, you need to add one
or more aws_alb_listener_rule resources to
map which of the ALB listeners should send their traffic to the ECS service's Target Group.
How should I use the ALB with multiple microservices?
To use the ALB with multiple services, you each service should create
aws_alb_listener_rule resources to specify
which paths or domain names should be routed to that service. For working sample code, check out the
docker-service-with-alb example.
Gotcha's
Make sure your Listeners handle all possible request paths
An ALB Listener
represents an open port on your ALB, waiting to receive requests and route them to a Target
Group.
Suppose you want to have this ALB Listener route requests for /foo to ServiceFoo and requests for /bar to ServiceBar.
You'd accomplish this creating two ALB Listener
Rules as follows:
Route /foo traffic to Target Group ServiceFoo
Route /bar traffic to Target Group ServiceBar
So far so good. But what if the Listener receives a request for /hello? Since no Listener Rule handles that path, the
ALB will handle it with its default_action. The default_action in this module is to return a fixed response, which
by default is a blank 404 page.
There are two ways for you to override this behavior:
You can override the default fixed response via the default_action_content_type, default_action_body, and
default_action_status_code parameters.
You can add an ALB Listener Rule that catches ALL requests (i.e., *) and have that rule forward to a custom Target
Group so your own apps can respond in any way you wish.
Make sure your Listener Rules each have a unique "priority"
See the prior section understand what Listener Rules are.
When defining a Listener Rule, you must specify both a priority and a path. The priority tells the ALB in what priority
a particular Listener Rule should be evaluated. For example, suppose you have the following Listener Rules defined on
your ALB:
Route /foo traffic to Target Group ServiceFoo
Route /foo* traffic to Target Group ServiceBar
To which Target Group should a request for /foo be routed? Based on the above, it's non-determinate. For this reason,
you must include a "priority" in the Listener Rule. A priority is an integer value where the lower the number the higher
the priority. For example, if we add in priorities to our Listener Rules:
Priority: 100. Route /foo traffic to Target Group ServiceFoo
Priority: 200. Route /foo* traffic to Target Group ServiceBar
Now we know that the first Listener Rule has a higher priority. That means that requests for /foo will be routed to
ServiceFoo, while all other requests will be routed to ServiceBar.
The gotcha here is that, because you define the Listener Rules for a single Listener across potentially many different
ECS Services or Auto Scaling Groups, take care to make sure that each Listener Rule uses a globally unique priority number.
Note that in most cases, your path definitions should be mutually exclusive and the actual priority value won't matter.
Questions? Ask away.
We're here to talk about our services, answer any questions, give advice, or just to chat.
{"treedata":{"name":"root","toggled":true,"children":[{"name":".circleci","children":[{"name":"config.yml","path":".circleci/config.yml","sha":"b5e1291ae1401db97210b139665cb59a39817d65"}]},{"name":".gitignore","path":".gitignore","sha":"be548d345e99887d4ccc3163bf552ee9c337b48d"},{"name":"CODEOWNERS","path":"CODEOWNERS","sha":"643742985da88d2f6805e0db41d0794232a8bd1a"},{"name":"LICENSE.txt","path":"LICENSE.txt","sha":"154ea4429924fda533b20544c7a19d8949fc82cf"},{"name":"README.md","path":"README.md","sha":"c0b8bcd48e3b5dd33f77e9191c82e1a4ea64a84f"},{"name":"_docs","children":[{"name":"migration_guides","children":[{"name":"nlb_to_0.15.0","children":[{"name":"README.md","path":"_docs/migration_guides/nlb_to_0.15.0/README.md","sha":"2a86c02a985b27782134cc30539455ecbd81046d"},{"name":"after_migration","children":[{"name":"main.tf","path":"_docs/migration_guides/nlb_to_0.15.0/after_migration/main.tf","sha":"9afc43a772b630798ab7d0b7a58fdbff9b0379b8"},{"name":"outputs.tf","path":"_docs/migration_guides/nlb_to_0.15.0/after_migration/outputs.tf","sha":"d967d0daa27477b626b7b28911d10b2f18fe6f76"},{"name":"vars.tf","path":"_docs/migration_guides/nlb_to_0.15.0/after_migration/vars.tf","sha":"b8c8af94a7ed9e5db9bd522bf69e0fe304efddee"}]},{"name":"before_migration","children":[{"name":"main.tf","path":"_docs/migration_guides/nlb_to_0.15.0/before_migration/main.tf","sha":"69345f63220752b9d3c83418ea9e31b1c91530a4"},{"name":"outputs.tf","path":"_docs/migration_guides/nlb_to_0.15.0/before_migration/outputs.tf","sha":"dc162b85fc673c12a9d166a1f58021eb142ac447"},{"name":"vars.tf","path":"_docs/migration_guides/nlb_to_0.15.0/before_migration/vars.tf","sha":"b8c8af94a7ed9e5db9bd522bf69e0fe304efddee"}]}]}]}]},{"name":"examples","children":[{"name":"acm-tls-certificate","children":[{"name":"README.md","path":"examples/acm-tls-certificate/README.md","sha":"0a7892a8b5d327254c91a96276273fcc975821ca"},{"name":"dependencies.tf","path":"examples/acm-tls-certificate/dependencies.tf","sha":"1ee97179c136a9e1c895a0ffcf6cda27cbc3171a"},{"name":"main.tf","path":"examples/acm-tls-certificate/main.tf","sha":"fe57e29d748ae0fdf206cc35c5e5209f02013d22"},{"name":"outputs.tf","path":"examples/acm-tls-certificate/outputs.tf","sha":"30ed2e66238dd38df2c80171079dd2de400efe33"},{"name":"vars.tf","path":"examples/acm-tls-certificate/vars.tf","sha":"94bef46856306d7823e1acb28307c45a3bed9a52"}]},{"name":"alb-with-logs","children":[{"name":"README.md","path":"examples/alb-with-logs/README.md","sha":"b46a1aef114340b80c6742b9344c52f1a952a7a4"},{"name":"main.tf","path":"examples/alb-with-logs/main.tf","sha":"fda10cfbaff280954eea67815fc9ecf82a8a6561"},{"name":"outputs.tf","path":"examples/alb-with-logs/outputs.tf","sha":"518914d6b608ea2d2996cbaa9361c370bd9c9fa1"},{"name":"vars.tf","path":"examples/alb-with-logs/vars.tf","sha":"a11d7589f3fb838585e7035023e8b6a90e8b0fd4"}]},{"name":"alb","children":[{"name":"README.md","path":"examples/alb/README.md","sha":"202d51dd9238a27061a6277a4632dce37706a3f9"},{"name":"main.tf","path":"examples/alb/main.tf","sha":"8f9fc9db2bf91716e2e9814018841cd97751622f"},{"name":"outputs.tf","path":"examples/alb/outputs.tf","sha":"3ab937d31bc4423aa1e17150a40e966fc6cd81da"},{"name":"vars.tf","path":"examples/alb/vars.tf","sha":"df7382a9da55c16fc34fd396653fafd9250679af"}]}]},{"name":"modules","children":[{"name":"acm-tls-certificate","children":[{"name":"README.md","path":"modules/acm-tls-certificate/README.md","sha":"b9c612bd69247dfce080057a3838f13c7ebb04ce"},{"name":"dependencies.tf","path":"modules/acm-tls-certificate/dependencies.tf","sha":"897b000a07205676c96c6bcf19d7a736383ac737"},{"name":"main.tf","path":"modules/acm-tls-certificate/main.tf","sha":"12e26a93d8c6c7c072d286469825af4285458e1d"},{"name":"outputs.tf","path":"modules/acm-tls-certificate/outputs.tf","sha":"89948a85af1e9ed87be4a5cb7124677634cbc249"},{"name":"vars.tf","path":"modules/acm-tls-certificate/vars.tf","sha":"1243bd0da4c6bb3b0a012b1300aa5798e121e0d2"},{"name":"wait-until-tls-cert-not-in-use.sh","path":"modules/acm-tls-certificate/wait-until-tls-cert-not-in-use.sh","sha":"705efd62d0ba101b7fdc32dd24a505825cf56400"}]},{"name":"alb","children":[{"name":"README.md","path":"modules/alb/README.md","sha":"4e01a3a6bde17643eb77b4c2a5c0268f68bb684d","toggled":true},{"name":"main.tf","path":"modules/alb/main.tf","sha":"caf8cdfab632760b46dbd005fec2fbd5d1b618c1"},{"name":"outputs.tf","path":"modules/alb/outputs.tf","sha":"e09679db5915f4de6fbe4c639de0ef9ac058ac28"},{"name":"vars.tf","path":"modules/alb/vars.tf","sha":"d5aee0ed653986b6d18e290694d16d1aa7dcb394"}],"toggled":true},{"name":"nlb","children":[{"name":"README.md","path":"modules/nlb/README.md","sha":"76f6d2c4608d3270a5de8d4e633b0501803d21b0"}]}],"toggled":true},{"name":"test","children":[{"name":"README.md","path":"test/README.md","sha":"ded6aae1d95e6fca858a0ef196d3ecf30d4bf5f2"},{"name":"acm_tls_certificate_test.go","path":"test/acm_tls_certificate_test.go","sha":"61b423bab92ef2f9bc04e1e6d066d1f7b9e05dee"},{"name":"go.mod","path":"test/go.mod","sha":"bdd5ccc0d7f206398ef3101af0acf957f827e457"},{"name":"go.sum","path":"test/go.sum","sha":"743b71888b540b16983df40982433e2a306606a0"},{"name":"lb_test.go","path":"test/lb_test.go","sha":"a1847684d9e0478301d513902b2cdd772736fc8f"}]}]},"detailsContent":"<h1 class=\"preview__body--title\" id=\"application-load-balancer-alb-module\">Application Load Balancer (ALB) Module</h1><div class=\"preview__body--border\"></div><p>This Terraform Module creates an <a href=\"http://docs.aws.amazon.com/elasticloadbalancing/latest/application/introduction.html\" class=\"preview__body--description--blue\" target=\"_blank\">Application Load Balancer</a>\nthat you can use as a load balancer for any <a href=\"http://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-target-groups.html\" class=\"preview__body--description--blue\" target=\"_blank\">ALB Target Group</a>.\nIn practice, a Target Group is usually an <a href=\"http://docs.aws.amazon.com/AmazonECS/latest/developerguide/Welcome.html\" class=\"preview__body--description--blue\" target=\"_blank\">ECS Service</a>\nor an <a href=\"http://docs.aws.amazon.com/autoscaling/latest/userguide/WhatIsAutoScaling.html\" class=\"preview__body--description--blue\" target=\"_blank\">Auto Scaling Group</a>.</p>\n<p>See the <a href=\"#background\" class=\"preview__body--description--blue\">Background</a> section below for more information on the ALB.</p>\n<h2 class=\"preview__body--subtitle\" id=\"how-do-you-use-this-module\">How do you use this module?</h2>\n<ul>\n<li>See the <a href=\"/repos/v0.16.2/module-load-balancer/README.md\" class=\"preview__body--description--blue\">root README</a> for instructions on using Terraform modules.</li>\n<li>See the <a href=\"/repos/v0.16.2/module-load-balancer/examples\" class=\"preview__body--description--blue\">examples</a> folder for example usage.</li>\n<li>See <a href=\"/repos/v0.16.2/module-load-balancer/modules/alb/vars.tf\" class=\"preview__body--description--blue\">vars.tf</a> for all the variables you can set on this module.</li>\n</ul>\n<h2 class=\"preview__body--subtitle\" id=\"alb-terminology\">ALB Terminology</h2>\n<p>Amazon has its own vocabulary for the ALB that can be confusing. Here's a helpful guide:</p>\n<ul>\n<li>\n<p><strong>Listener:</strong> Represents a port open on the ALB that receives incoming traffic (e.g., port 80 for HTTP, 443 for\nHTTPs).</p>\n</li>\n<li>\n<p><strong>Target Group:</strong> Represents one or more servers that are listening for requests. You can configure what port(s)\nthose servers listen on and how to perform health checks on the servers.</p>\n</li>\n<li>\n<p><strong>Listener Rules:</strong> Represents a mapping between Listeners and Target Groups. For each of your Listeners, you can\nspecify which paths and/or domain names should be routed to which Target Groups. For example, you could configure\npath <code>/foo</code> to go to the Target Group <code>foo</code> and <code>/bar</code> to go to <code>bar</code>; or, you could configure <code>foo.my-domain.com</code> to\ngo to <code>foo</code> and <code>bar.my-domain.com</code> to go to <code>bar</code>; or any combination/permutation of these rules.</p>\n</li>\n</ul>\n<h2 class=\"preview__body--subtitle\" id=\"background\">Background</h2>\n<h3 class=\"preview__body--subtitle\" id=\"whats-the-difference-between-an-alb-and-elb\">What's the difference between an ALB and ELB?</h3>\n<p>The ELB, now known as the <a href=\"http://docs.aws.amazon.com/elasticloadbalancing/latest/classic/introduction.html\" class=\"preview__body--description--blue\" target=\"_blank\">Classic Load Balancer</a>,\nis a <a href=\"https://en.wikipedia.org/wiki/Transport_layer\" class=\"preview__body--description--blue\" target=\"_blank\">Layer 4</a> load balancer, which means that the ELB will accept both\nHTTP traffic <em>and</em> TCP traffic. By asking the ELB to simply forward TCP traffic, Amazon users gained the benefit of a\nhigh-availability load balancer with the flexibility of handling any kind of TCP traffic they wanted on their backend\ninstances.</p>\n<p>But over time, it became clear that many customers were running HTTP microservices that needed more "opinionated" functionality\nlike built-in support for WebSockets, built-in support for HTTP/2, and routing to different backend services depending\non the particular URL requested in the HTTP request. Because these requests are all HTTP-specific, the "flexible" Layer 4\nELB could not be updated to handle these use cases.</p>\n<p>In addition, when Amazon released the EC2 Container Service for easily running a Docker cluster, they needed some way\nto allow a load balancer to route requests to containers that just launched somewhere in the cluster. The ELB was originally\ndesigned in a pre-container world and was able to route only to a <em>single</em> port across many different EC2 Instances.</p>\n<p>This imposed an awkward restriction on the ECS Cluster where you had to run each ECS Task (Docker container) so that it\nlistened on the same host port. This, in turn, meant you couldn't run two instances of the same Docker container on the\nsame host, which was one of the main benefits of Docker in the first place.</p>\n<p>The ALB was meant to solve both of these problems:</p>\n<ol>\n<li>Offer HTTP-specific functionality (known as "Layer 7" functionality)</li>\n<li>Allow Docker containers to launch on a dynamic port</li>\n</ol>\n<h4 id=\"alb-functionality\">ALB Functionality</h4>\n<p>The ALB gives us the following HTTP-specific functionality compared to the ELB:</p>\n<ul>\n<li>Route requests via HTTP or HTTPS</li>\n<li>Native support for WebSockets</li>\n<li>Native support for HTTP/2</li>\n<li>Path-based routing</li>\n<li>Hostname-based routing</li>\n<li>Ability to route to a <a href=\"http://docs.aws.amazon.com/elasticloadbalancing/latest/application/target-group-register-targets.html\" class=\"preview__body--description--blue\" target=\"_blank\">Target</a>,\nwhich incorporates both an endpoint and a port and therefore allows different instances of an ECS Service to receive\ntraffic on different ports.</li>\n<li>Better metrics</li>\n<li>Support for sticky sessions using load-balancer-generated cookies</li>\n</ul>\n<p>For a visual explanation of the ALB's features, check out <a href=\"https://blog.gruntwork.io/a-talk-on-the-new-aws-application-load-balancer-updates-to-ecs-and-kinesis-analytics-abb599cb3cb8#.qww1to10q\" class=\"preview__body--description--blue\" target=\"_blank\">A Talk on the New AWS Application Load Balancer, Updates to\nECS, and Kinesis Analytics</a>.</p>\n<h4 id=\"elb-functionality\">ELB Functionality</h4>\n<p>The Classic Load Balancer, or ELB, gives us the following unique functionality compared to the ALB:</p>\n<ul>\n<li>Route requests via HTTP, HTTPS or TCP</li>\n<li>Support for sticky sessions using application-generated cookies</li>\n</ul>\n<h3 class=\"preview__body--subtitle\" id=\"when-should-i-use-an-alb-vs-elb\">When should I use an ALB vs. ELB?</h3>\n<p>Based on the above analysis, you should generally prefer the ALB when selecting a load balancer for an HTTP-based service.\nThere are, of course, still times when the ELB makes sense:</p>\n<ul>\n<li>If your service listens on a non-HTTP protocol, such as ZeroMQ.</li>\n<li>If you wish to terminate a TLS connection at your service, instead of at the load balancer, only the ELB will support\nthis. That is, an ALB will accept TLS connections, but it will then open a <em>second</em> HTTP or HTTPS connection to your\nbackend service. If you want end-to-end encryption, only the ELB can forward the TCP request directly to your backend\nservice so that the backend service terminates the TLS connection.</li>\n<li>If you need the power of Nginx, or HAProxy, but don't want to bother setting these up as a High Availability cluster.</li>\n</ul>\n<p>Finally, the ALB uses a different pricing model than the ELB. Here's an excerpt from the <a href=\"https://aws.amazon.com/blogs/aws/new-aws-application-load-balancer/\" class=\"preview__body--description--blue\" target=\"_blank\">Blog Post that introduced the\nALB</a>:</p>\n<blockquote>\n<p>When you use an Application Load Balancer, you will be billed by the hour and for the use of Load Balancer Capacity Units,\nalso known as LCU’s. An LCU measures the number of new connections per second, the number of active connections, and\ndata transfer. We measure on all three dimensions, but bill based on the highest one. One LCU is enough to support either:</p>\n<ul>\n<li>25 connections/second with a 2 KB certificate, 3,000 active connections, and 2.22 Mbps of data transfer or</li>\n<li>5 connections/second with a 4 KB certificate, 3,000 active connections, and 2.22 Mbps of data transfer.</li>\n</ul>\n</blockquote>\n<blockquote>\n<p>Billing for LCU usage is fractional, and is charged at $0.008 per LCU per hour. Based on our calculations, we believe\nthat virtually all of our customers can obtain a net reduction in their load balancer costs by switching from a Classic\nLoad Balancer to an Application Load Balancer.</p>\n</blockquote>\n<p>You may note that if you have 1,000,000 idle WebSocket connections (an "active connection"), this would cost ALB users\n$1,920/month! Whereas with the original ELB, your costs will not scale with the number of idle WebSocket connections\n(credit to <a href=\"https://news.ycombinator.com/item?id=12269453\" class=\"preview__body--description--blue\" target=\"_blank\">this Hacker News thread</a> for the observation).</p>\n<p>Given all the benefits of the ALB, even if you plan to get to massive scale eventually, you may as well start with the\nALB. You can always re-assess at any time.</p>\n<h2 class=\"preview__body--subtitle\" id=\"using-the-alb-with-ecs\">Using the ALB with ECS</h2>\n<h3 class=\"preview__body--subtitle\" id=\"when-should-i-use-this-module-with-amazon-ecs\">When should I use this module with Amazon ECS?</h3>\n<p>With the ELB, now known as a <a href=\"http://docs.aws.amazon.com/elasticloadbalancing/latest/classic/introduction.html\" class=\"preview__body--description--blue\" target=\"_blank\">Classic Load Balancer</a>,\neach ECS Service was fronted by a unique ELB. As a result, each ECS Service module eventually created its own ELB. This\ngave us good isolation and made it easy to give each ECS Service a unique DNS name on the same port (e.g. api.acme.com and\nstats.acme.com, both on port 443). But it also led to low utilization among all the ELBs, little resource sharing, and\nconsequently higher costs.</p>\n<p>With the ALB, a single ALB is shared among multiple ECS Services. For that reason, after you've created an ALB using this\nmodule, you may wish to create an ECS Cluster using the <a href=\"/repos/module-ecs/modules/ecs-cluster\" class=\"preview__body--description--blue\">ecs-cluster</a> module, where you'll pass in the Security\nGroup ID of the newly created ALB to permit the ALB to forward traffic to the ECS Cluster.</p>\n<p>With an ECS Cluster and ALB in place, you can now use the [ecs-service-with-alb]\n(https://github.com/gruntwork-io/module-ecs/tree/master/modules/ecs-service-with-alb) module to create a new ECS Service\nthat contains an ALB Target Group you can configure to receive traffic from an ALB. To do that, you need to add one\nor more <a href=\"https://www.terraform.io/docs/providers/aws/r/alb_listener_rule.html\" class=\"preview__body--description--blue\" target=\"_blank\">aws_alb_listener_rule</a> resources to\nmap which of the ALB listeners should send their traffic to the ECS service's Target Group.</p>\n<h3 class=\"preview__body--subtitle\" id=\"how-should-i-use-the-alb-with-multiple-microservices\">How should I use the ALB with multiple microservices?</h3>\n<p>To use the ALB with multiple services, you each service should create\n<a href=\"https://www.terraform.io/docs/providers/aws/r/alb_listener_rule.html\" class=\"preview__body--description--blue\" target=\"_blank\">aws_alb_listener_rule</a> resources to specify\nwhich paths or domain names should be routed to that service. For working sample code, check out the\n<a href=\"/repos/module-ecs/examples/docker-service-with-alb\" class=\"preview__body--description--blue\">docker-service-with-alb example</a>.</p>\n<h2 class=\"preview__body--subtitle\" id=\"gotchas\">Gotcha's</h2>\n<h3 class=\"preview__body--subtitle\" id=\"make-sure-your-listeners-handle-all-possible-request-paths\">Make sure your Listeners handle all possible request paths</h3>\n<p>An <a href=\"http://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-listeners.html\" class=\"preview__body--description--blue\" target=\"_blank\">ALB Listener</a>\nrepresents an open port on your ALB, waiting to receive requests and route them to a <a href=\"http://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-target-groups.html\" class=\"preview__body--description--blue\" target=\"_blank\">Target\nGroup</a>.</p>\n<p>Suppose you want to have this ALB Listener route requests for <code>/foo</code> to ServiceFoo and requests for <code>/bar</code> to ServiceBar.\nYou'd accomplish this creating two <a href=\"http://docs.aws.amazon.com/elasticloadbalancing/latest/application/listener-update-rules.html\" class=\"preview__body--description--blue\" target=\"_blank\">ALB Listener\nRules</a> as follows:</p>\n<ul>\n<li>Route <code>/foo</code> traffic to Target Group ServiceFoo</li>\n<li>Route <code>/bar</code> traffic to Target Group ServiceBar</li>\n</ul>\n<p>So far so good. But what if the Listener receives a request for <code>/hello</code>? Since no Listener Rule handles that path, the\nALB will handle it with its <code>default_action</code>. The <code>default_action</code> in this module is to return a fixed response, which\nby default is a blank 404 page.</p>\n<p>There are two ways for you to override this behavior:</p>\n<ul>\n<li>You can override the default fixed response via the <code>default_action_content_type</code>, <code>default_action_body</code>, and\n<code>default_action_status_code</code> parameters.</li>\n<li>You can add an ALB Listener Rule that catches ALL requests (i.e., <code>*</code>) and have that rule forward to a custom Target\nGroup so your own apps can respond in any way you wish.</li>\n</ul>\n<h3 class=\"preview__body--subtitle\" id=\"make-sure-your-listener-rules-each-have-a-unique-priority\">Make sure your Listener Rules each have a unique "priority"</h3>\n<p>See the <a href=\"/repos/v0.16.2/module-load-balancer/modules/alb/make-sure-your-listeners-handle-all-possible-request-paths\" class=\"preview__body--description--blue\">prior section</a> understand what Listener Rules are.</p>\n<p>When defining a Listener Rule, you must specify both a priority and a path. The priority tells the ALB in what priority\na particular Listener Rule should be evaluated. For example, suppose you have the following Listener Rules defined on\nyour ALB:</p>\n<ul>\n<li>Route <code>/foo</code> traffic to Target Group ServiceFoo</li>\n<li>Route <code>/foo*</code> traffic to Target Group ServiceBar</li>\n</ul>\n<p>To which Target Group should a request for <code>/foo</code> be routed? Based on the above, it's non-determinate. For this reason,\nyou must include a "priority" in the Listener Rule. A priority is an integer value where the lower the number the higher\nthe priority. For example, if we add in priorities to our Listener Rules:</p>\n<ul>\n<li>Priority: 100. Route <code>/foo</code> traffic to Target Group ServiceFoo</li>\n<li>Priority: 200. Route <code>/foo*</code> traffic to Target Group ServiceBar</li>\n</ul>\n<p>Now we know that the first Listener Rule has a higher priority. That means that requests for <code>/foo</code> will be routed to\nServiceFoo, while all other requests will be routed to ServiceBar.</p>\n<p>The gotcha here is that, because you define the Listener Rules for a single Listener across potentially many different\nECS Services or Auto Scaling Groups, take care to make sure that each Listener Rule uses a globally unique priority number.</p>\n<p>Note that in most cases, your path definitions should be mutually exclusive and the actual priority value won't matter.</p>\n","repoName":"module-load-balancer","repoRef":"v0.16.2","serviceDescriptor":{"serviceName":"Elastic Load Balancer (ELB)","serviceRepoName":"module-load-balancer","serviceRepoOrg":"gruntwork-io","cloudProviders":["aws"],"description":"Deploy the Application Load Balancer (ALB) for load balancing HTTP and HTTPS, with support for routing rules and WebSockets.","imageUrl":"elastic.png","licenseType":"subscriber","technologies":["Terraform"],"compliance":[],"tags":[""]},"serviceCategoryName":"Networking","fileName":"README.md","filePath":"/modules/alb","title":"Repo Browser: Elastic Load Balancer (ELB)","description":"Browse the repos in the Gruntwork Infrastructure as Code Library."}