整个应用程序由两台服务器(RabbitMQ 和 Tomcat)和一个在 ALB 后面运行的数据库组成。目前只有一个 RabbitMQ 实例和一个 Tomcat 实例,但设置应该允许扩展。两台服务器都在自己的 Docker 容器中运行。我使用 ECS 和 CloudFormation 来实现这一点。
问题出在 RabbitMQ 服务器上。此服务器必须侦听两个不同的端口 - 一个用于 WebSocket 连接(端口 15674),另一个用于 Management API 的 HTTP 连接(端口 15672)。WebSocket 连接是从客户端/浏览器建立的。HTTP 连接在 Tomcat 内部与 RabbitMQ 建立,但它们也经过 ALB。我找不到设置 RabbitMQ 容器的方法,因此流量会通过两个端口进入它。我正在共享 CloudFormation 模板中与 RabbitMQ 服务器相关的部分。使用此模板,WebSocket 连接似乎工作正常,但 HTTP 连接失败并显示 404 错误消息。欢迎提供有关如何启用 HTTP 连接(端口 15672)的想法。
ECSAutoScalingGroup:
Type: "AWS::AutoScaling::AutoScalingGroup"
Properties:
VPCZoneIdentifier:
- Ref: "Subnet1"
- Ref: "Subnet2"
LaunchConfigurationName: !Ref "AutoScalingGroupConfig"
MinSize: "1"
MaxSize: "1"
DesiredCapacity: "1"
CreationPolicy:
ResourceSignal:
Timeout: "PT5M"
UpdatePolicy:
AutoScalingReplacingUpdate:
WillReplace: true
...
ECSALB:
Type: "AWS::ElasticLoadBalancingV2::LoadBalancer"
DependsOn: "AttachGateway"
Properties:
Name: "ECSALB"
LoadBalancerAttributes:
- Key: idle_timeout.timeout_seconds
Value: 30
Subnets:
- Ref: "Subnet1"
- Ref: "Subnet2"
SecurityGroups: [!Ref "LoadBalancerSecurityGroup"]
...
ALBRabbitMQManagementListener:
Type: "AWS::ElasticLoadBalancingV2::Listener"
DependsOn: [ "ECSServiceRole", "RabbitMQTargetGroup" ]
Properties:
DefaultActions:
- Type: "forward"
TargetGroupArn: !Ref "RabbitMQTargetGroup"
LoadBalancerArn: !Ref "ECSALB"
Port: 15672
Protocol: "HTTP"
...
ALBListenerHTTPS:
Type: "AWS::ElasticLoadBalancingV2::Listener"
DependsOn: [ "ECSServiceRole", "ECSALB" ]
Properties:
Certificates:
- CertificateArn: “some_certificate”
DefaultActions:
- Type: "redirect"
RedirectConfig:
Protocol: "HTTPS"
Host: "static.domain.com"
Path: "/#{path}"
Query: "#{query}"
StatusCode: "HTTP_301"
LoadBalancerArn: !Ref "ECSALB"
Port: 443
Protocol: "HTTPS"
...
ECSALBListenerRuleWebSocket:
Type: "AWS::ElasticLoadBalancingV2::ListenerRule"
DependsOn: [ "ALBListenerHTTPS", "RabbitMQTargetGroup" ]
Properties:
Actions:
- Type: "forward"
TargetGroupArn: !Ref "RabbitMQTargetGroup"
Conditions:
- Field: "path-pattern"
Values: [ "/ws" ]
ListenerArn: !Ref "ALBListenerHTTPS"
Priority: 2
...
RabbitMQTargetGroup:
Type: "AWS::ElasticLoadBalancingV2::TargetGroup"
DependsOn: "ECSALB"
Properties:
HealthCheckIntervalSeconds: 30
HealthCheckPath: "/"
HealthCheckPort: 15672
HealthCheckProtocol: "HTTP"
HealthCheckTimeoutSeconds: 5
HealthyThresholdCount: 2
Name: "RabbitMQTargetGroup"
Port: 15674
Protocol: "HTTP"
TargetGroupAttributes:
- Key: "stickiness.enabled"
Value: true # Needed to support WebSockets
- Key: "stickiness.lb_cookie.duration_seconds"
Value: 604800 # One week (this is the maximum)
UnhealthyThresholdCount: 3
VpcId: !Ref "Vpc"
...
RabbitMQService:
Type: AWS::ECS::Service
DependsOn: [ "ALBListenerHTTPS", "RabbitMQTargetGroup", "ECSALBListenerRuleWebSocket" ]
Properties:
Cluster: !Ref “MyCluster"
Role: !Ref "ECSServiceRole"
DesiredCount: 1
TaskDefinition: !Ref "RabbitMQTask"
DeploymentConfiguration:
MinimumHealthyPercent: 100
LoadBalancers:
- ContainerName: "rabbitmq-service"
ContainerPort: 15674
TargetGroupArn: !Ref "RabbitMQTargetGroup"
...
RabbitMQTask:
Type: "AWS::ECS::TaskDefinition"
Properties:
Family: "rabbitmq-service"
NetworkMode: "host"
ContainerDefinitions:
- Name: "rabbitmq-service"
Essential: true
Image: “some_docker_image”
MemoryReservation: 1024
PortMappings:
- ContainerPort: 15672
- ContainerPort: 15674
LogConfiguration:
LogDriver: "awslogs"
Options:
awslogs-group: "rabbitmq"
awslogs-region: !Ref "AWS::Region"
awslogs-stream-prefix: “my_prefix”
awslogs-datetime-format: "%Y-%m-%d %H:%M:%S.%L"