ECS 和应用负载均衡器

Posted

技术标签:

【中文标题】ECS 和应用负载均衡器【英文标题】:ECS and Application Load Balancer 【发布时间】:2017-01-04 06:53:09 【问题描述】:

我一直在寻找有关 Cloud Formation 的一些信息,以使用 ECSELB(应用程序负载均衡器) 创建堆栈,但无法这样做。

我创建了两个 Docker 映像,每个映像都包含一个侦听端口 30004000 的 Node.js 微服务。如前所述,如何使用 ECSELB 创建堆栈?我假设 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 网关?

负载均衡SLB

ECS 服务的 AWS 网络负载均衡器运行状况检查失败

阿里云负载均衡产品简介

有没有办法在没有负载均衡器的情况下为 ECS 服务配置健康检查?

AWS ECS Fargate:应用程序负载均衡器返回 503 并带有奇怪的模式