ECS 和应用程序负载均衡器
ECS and Application Load Balancer
我一直在寻找关于 Cloud Formation 的一些关于使用 ECS 和 ELB 创建堆栈的信息( Application Load Balancer) 但无法这样做。
我创建了两个 Docker 图像,每个图像都包含一个 Node.js 微服务,用于侦听端口 3000 和 4000.如前所述,如何使用 ECS 和 ELB 创建我的堆栈?我假设 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/ 执行此操作,以下是共享域的两个应用程序的示例:
- https://ratelim.it => 容器端口 8100
上的 Rails 应用 运行
- https://ratelim.it/api => Java API 运行 在容器端口 8080
此示例支持 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
}
}
我一直在寻找关于 Cloud Formation 的一些关于使用 ECS 和 ELB 创建堆栈的信息( Application Load Balancer) 但无法这样做。
我创建了两个 Docker 图像,每个图像都包含一个 Node.js 微服务,用于侦听端口 3000 和 4000.如前所述,如何使用 ECS 和 ELB 创建我的堆栈?我假设 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/ 执行此操作,以下是共享域的两个应用程序的示例:
- https://ratelim.it => 容器端口 8100 上的 Rails 应用 运行
- https://ratelim.it/api => Java API 运行 在容器端口 8080
此示例支持 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
}
}