ECS 和应用程序负载均衡器

ECS and Application Load Balancer

我一直在寻找关于 Cloud Formation 的一些关于使用 ECSELB 创建堆栈的信息( Application Load Balancer) 但无法这样做。

我创建了两个 Docker 图像,每个图像都包含一个 Node.js 微服务,用于侦听端口 30004000.如前所述,如何使用 ECSELB 创建我的堆栈?我假设 Application Load Balancer 可以配置为侦听这两个端口?

一个示例 Cloud Formation 模板真的很有帮助。

您是否尝试在 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"
              ]]}}

我知道它不是纯粹的基础架构即代码,但它可以轻松完成工作,而且我的集群配置并没有真正改变太多。

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" }
      }
    ]
  }
}  

您可以在博客中找到更多详细信息 post 我已经写过关于此的内容,请参阅 Amazon ECS and Application Load Balancer

如果您有兴趣通过 https://www.terraform.io/ 执行此操作,以下是共享域的两个应用程序的示例:

此示例支持 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
  }
}