ECS 和应用负载均衡器
Posted
技术标签:
【中文标题】ECS 和应用负载均衡器【英文标题】:ECS and Application Load Balancer 【发布时间】:2017-01-04 06:53:09 【问题描述】:我一直在寻找有关 Cloud Formation 的一些信息,以使用 ECS 和 ELB(应用程序负载均衡器) 创建堆栈,但无法这样做。
我创建了两个 Docker 映像,每个映像都包含一个侦听端口 3000 和 4000 的 Node.js 微服务。如前所述,如何使用 ECS 和 ELB 创建堆栈?我假设 Application Load Balancer 可以配置为监听这两个端口?
一个示例 Cloud Formation 模板会很有帮助。
【问题讨论】:
cloudformation 目前不支持应用负载均衡。有关如何在经典意义上使用 ECS 和 ELB 的信息there are plenty of examples 【参考方案1】:如果您有兴趣通过https://www.terraform.io/ 执行此操作,以下是共享域的两个应用的示例:
https://ratelim.it => 在容器端口 8100 上运行的 Rails 应用程序 https://ratelim.it/api => 容器端口 8080 上运行的 Java API此示例支持 http 和 https,并根据 url 前缀在您的应用程序之间拆分流量。
my_app_task.json
"portMappings": [
"hostPort": 0,
"containerPort": 8100,
"protocol": "tcp"
],
my_api_task.json
"portMappings": [
"hostPort": 0,
"containerPort": 8080,
"protocol": "tcp"
],
地形代码:
## ALB for both
resource "aws_alb" "app-alb"
name = "app-alb"
security_groups = [
"$aws_security_group.albs.id"]
## ALB target for app
resource "aws_alb_target_group" "my_app"
name = "my_app"
port = 80
protocol = "HTTP"
vpc_id = "$aws_vpc.myvpc.id"
deregistration_delay = 30
health_check
protocol = "HTTP"
path = "/healthcheck"
healthy_threshold = 2
unhealthy_threshold = 2
interval = 90
## ALB Listener for app
resource "aws_alb_listener" "my_app"
load_balancer_arn = "$aws_alb.app-alb.id"
port = "80"
protocol = "HTTP"
default_action
target_group_arn = "$aws_alb_target_group.my_app.id"
type = "forward"
## ALB Listener for app https
resource "aws_alb_listener" "my_app_https"
load_balancer_arn = "$aws_alb.app-alb.id"
port = "443"
protocol = "HTTPS"
ssl_policy = "ELBSecurityPolicy-2015-05"
certificate_arn = "$data.aws_acm_certificate.my_app.arn"
default_action
target_group_arn = "$aws_alb_target_group.my_app.id"
type = "forward"
## ALB Target for API
resource "aws_alb_target_group" "my_api"
name = "myapi"
port = 80
protocol = "HTTP"
vpc_id = "$aws_vpc.myvpc.id"
deregistration_delay = 30
health_check
path = "/api/v1/status"
healthy_threshold = 2
unhealthy_threshold = 2
interval = 90
## ALB Listener Rule for API
resource "aws_alb_listener_rule" "api_rule"
listener_arn = "$aws_alb_listener.my_app.arn"
priority = 100
action
type = "forward"
target_group_arn = "$aws_alb_target_group.my_api.arn"
condition
field = "path-pattern"
values = [
"/api/*"]
## ALB Listener RUle for API HTTPS
resource "aws_alb_listener_rule" "myapi_rule_https"
listener_arn = "$aws_alb_listener.app_https.arn"
priority = 100
action
type = "forward"
target_group_arn = "$aws_alb_target_group.myapi.arn"
condition
field = "path-pattern"
values = [
"/api/*"]
## APP Task
resource "aws_ecs_task_definition" "my_app"
family = "my_app"
container_definitions = "$data.template_file.my_app_task.rendered"
## App Service
resource "aws_ecs_service" "my_app-service"
name = "my_app-service"
cluster = "$aws_ecs_cluster.default.id"
task_definition = "$aws_ecs_task_definition.my_app.arn"
iam_role = "$aws_iam_role.ecs_role.arn"
depends_on = [
"aws_iam_role_policy.ecs_service_role_policy"]
load_balancer
target_group_arn = "$aws_alb_target_group.my_app.id"
container_name = "my_app"
container_port = 8100
## API Task
resource "aws_ecs_task_definition" "myapi"
family = "myapi"
container_definitions = "$data.template_file.myapi_task.rendered"
## API Servcice
resource "aws_ecs_service" "myapi-service"
name = "myapi-service"
cluster = "$aws_ecs_cluster.default.id"
task_definition = "$aws_ecs_task_definition.myapi.arn"
iam_role = "$aws_iam_role.ecs_role.arn"
depends_on = [
"aws_iam_role_policy.ecs_service_role_policy"]
load_balancer
target_group_arn = "$aws_alb_target_group.myapi.id"
container_name = "myapi"
container_port = 8080
【讨论】:
这很有帮助!!!请记住将 ALB 放在公共子网中,并记住提供 ecs 角色权限以注册和注销容器(查看 ecs 事件以获取此类信息)。如果它不起作用,我会说总是先检查事件选项卡!【参考方案2】:Application Load Balancer 可用于跨服务中的 ECS 任务加载流量。 Application Load Balancer 有两个很酷的功能可供您利用; 动态端口映射(主机上的端口由 ECS/Docker 自动分配)允许您在单个 EC2 实例上为同一服务运行多个任务以及基于路径的路由允许您根据 URL 路径中的模式将传入请求路由到不同的服务。
要连接它,您首先需要像这样定义一个 TargetGroup
"TargetGroupService1" :
"Type" : "AWS::ElasticLoadBalancingV2::TargetGroup",
"Properties" :
"Port": 10,
"Protocol": "HTTP",
"HealthCheckPath": "/service1",
"VpcId": "Ref" : "Vpc"
如果您使用动态端口映射,则目标组中指定的端口无关紧要,因为它将被每个目标的动态分配端口覆盖。
接下来,您定义一个 ListenerRule,该规则定义应路由到 TargetGroup 的路径:
"ListenerRuleService1":
"Type" : "AWS::ElasticLoadBalancingV2::ListenerRule",
"Properties" :
"Actions" : [
"TargetGroupArn" : "Ref": "TargetGroupService1",
"Type" : "forward"
],
"Conditions" : [
"Field" : "path-pattern",
"Values" : [ "/service1" ]
],
"ListenerArn" : "Ref": "Listener",
"Priority" : 1
最后,您将您的 ECS 服务与 TargetGroup 相关联。这使 ECS 能够自动将您的任务容器注册为目标组中的目标(使用您在 TaskDefinition 中配置的主机端口)
"Service1":
"Type" : "AWS::ECS::Service",
"DependsOn": [
"ListenerRuleService1"
],
"Properties" :
"Cluster" : "Ref" : "ClusterName" ,
"DesiredCount" : 2,
"Role" : "/ecsServiceRole",
"TaskDefinition" : "Ref":"Task1",
"LoadBalancers": [
"ContainerName": "Task1",
"ContainerPort": "8080",
"TargetGroupArn" : "Ref" : "TargetGroupService1"
]
你可以在我写的一篇博文中找到更多细节,见Amazon ECS and Application Load Balancer
【讨论】:
有没有办法简单地用我们稍后创建的新目标组替换初始目标组?我一直在尝试根据我在这里找到的示例github.com/aws-samples/ecs-refarch-cloudformation 执行此操作,但它不起作用,默认目标组保持分配状态【参考方案3】:您是否尝试在 CF 中重建整个 ECS 堆栈?如果您可以使用预定义的集群,则只需在实例启动时使用用户数据注册实例(我使用的是 Spot Fleet,但这应该可以在您启动实例的任何地方使用)。在您的 LaunchSpecifications 中有这样的内容:
"UserData":
"Fn::Base64" : "Fn::Join" : [ "", [
"#!/bin/bash\n",
"yum update -y\n",
"echo ECS_CLUSTER=YOUR_CLUSTER_NAME >> /etc/ecs/ecs.config\n",
"yum install -y aws-cli\n",
"aws ec2 create-tags --region YOUR_REGION --resources $(curl http://169.254.169.254/latest/meta-data/instance-id) --tags Key=Name,Value=YOUR_INSTANCE_NAME\n"
]]
我知道它不是纯粹的基础架构即代码,但它可以轻松完成工作,而且我的集群配置并没有真正改变太多。
【讨论】:
以上是关于ECS 和应用负载均衡器的主要内容,如果未能解决你的问题,请参考以下文章
如何为 ECS 添加带有应用程序负载均衡器的 AWS API 网关?