ECS和应用程序负载均衡器

时间:2016-08-27 21:36:55

标签: amazon-cloudformation amazon-elb amazon-ecs

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

我创建了两个Docker镜像,每个镜头都包含一个侦听端口 3000 4000 的Node.js微服务。如上所述,如何使用 ECS ELB 创建堆栈?我假设应用程序负载均衡器可以配置为侦听这两个端口吗?

示例Cloud Formation模板确实会有所帮助。

3 个答案:

答案 0 :(得分:9)

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

答案 1 :(得分:1)

如果您对此通过https://www.terraform.io/感兴趣,请参阅以下两个共享域名的应用的示例:

此示例支持http& https,并根据网址前缀拆分您的应用之间的流量。

my_app_task.json

"portMappings": [
  {
    "hostPort": 0,
    "containerPort": 8100,
    "protocol": "tcp"
  }
],

my_api_task.json

"portMappings": [
  {
    "hostPort": 0,
    "containerPort": 8080,
    "protocol": "tcp"
  }
],

Terraform代码:

## 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
  }
}

答案 2 :(得分:0)

Are you trying to rebuild the entire ECS stack in CF? If you can live with pre-defined clusters, you can just register the instances with user data when they spin up (I use spot fleet, but this should work anywhere you're starting an instance). Something like this in your 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"
              ]]}}

I know it's not pure Infrastructure as Code, but it gets the job done with minimal effort, and I my cluster configs don't really change a lot.