AWS ELB:503服务暂时不可用

时间:2020-03-24 22:05:13

标签: amazon-web-services amazon-ec2 amazon-ecs amazon-elb

我正在按照此示例repo尝试将微服务部署到AWS ECS。在这里,负载均衡器用于不同docker服务之间的联网。我已经根据需要调整了cloudformation模板,并且只部署了一项服务,即Web服务器。我希望公众访问Web界面,并添加此服务随后要与之交谈的其他服务。但是,我目前很难使Web服务器使用负载平衡器的URL。如果使用公共IP直接转到EC2实例,则可以访问该接口。但是,如果我转到负载平衡器DNS,则会得到503 Service Temporarily Unavailable。我已经检查了AWS docs,但是Web服务目标组显示了状态为healthy的已注册目标(EC2实例)。我想念什么?

Parameters:
  EnvironmentName:
    Description: An environment name that will be prefixed to resource names
    Type: String

  VPC:
    Type: AWS::EC2::VPC::Id
    Description: Choose which VPC the Application Load Balancer should be deployed to

  Subnets:
    Description: Choose which subnets the Application Load Balancer should be deployed to
    Type: AWS::EC2::Subnet::Id

  PublicSubnet:
    Description: Choose which public subnet the EC2 instance should be deployed to
    Type: AWS::EC2::Subnet::Id

Resources:

  LoadBalancerSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: !Sub ${EnvironmentName}-loadbalancer
      GroupDescription: Access to the load balancer that sits in front of ECS
      VpcId: !Ref VPC
      SecurityGroupIngress:
        # Allow access from anywhere to our ECS services
        - CidrIp: 0.0.0.0/0
          IpProtocol: -1
      Tags:
        - Key: Name
          Value: !Sub ${EnvironmentName}-LoadBalancers

  LoadBalancer:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Name: !Ref EnvironmentName
      Subnets:
        - !Ref Subnets
      SecurityGroups:
        - !Ref LoadBalancerSecurityGroup
      Tags:
        - Key: Name
          Value: !Ref EnvironmentName

  LoadBalancerListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      LoadBalancerArn: !Ref LoadBalancer
      Port: 80
      Protocol: HTTP
      DefaultActions:
        - Type: forward
          TargetGroupArn: !Ref DefaultTargetGroup

  DefaultTargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      Name: !Sub ${EnvironmentName}-default
      VpcId: !Ref VPC
      Port: 80
      Protocol: HTTP

  ECSHostSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: !Sub ${EnvironmentName}-ecs-hosts
      GroupDescription: Access to the ECS hosts and the tasks/containers that run on them
      VpcId: !Ref VPC
      SecurityGroupIngress:
        # Only allow inbound access to ECS from the ELB
        - SourceSecurityGroupId: !Ref LoadBalancerSecurityGroup
          IpProtocol: -1
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: 0.0.0.0/0
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0
      Tags:
        - Key: Name
          Value: !Sub ${EnvironmentName}-ECS-Hosts

  ECSCluster:
    Type: AWS::ECS::Cluster
    Properties:
      ClusterName: !Ref EnvironmentName

  ECSRole:
    Type: AWS::IAM::Role
    Properties:
      Path: /
      RoleName: !Sub ${EnvironmentName}-ecs-role
      AssumeRolePolicyDocument:
        Statement:
          - Effect: Allow
            Principal:
              Service: ec2.amazonaws.com
            Action: 'sts:AssumeRole'
      ManagedPolicyArns:
        - 'arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role'
        - 'arn:aws:iam::aws:policy/service-role/AmazonEC2RoleforSSM'
        - 'arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy'

  ECSInstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Path: /
      Roles:
        - !Ref ECSRole

  EC2Webserver:
    Type: AWS::EC2::Instance
    Properties:
      AvailabilityZone: eu-central-1a
      ImageId: !Ref ECSAMI
      InstanceType: !Ref InstanceType
      IamInstanceProfile: !Ref ECSInstanceProfile
      UserData:
        Fn::Base64:
          !Sub |
          #!/bin/bash
          # Add to cluster:
          echo ECS_CLUSTER=${ECSCluster} >> /etc/ecs/ecs.config
          echo ECS_ENABLE_AWSLOGS_EXECUTIONROLE_OVERRIDE=true >> /etc/ecs/ecs.config
      SecurityGroupIds:
        - !Ref ECSHostSecurityGroup
      SubnetId: !Ref PublicSubnet
      Tags:
        - Key: Name
          Value: !Sub ${EnvironmentName}

  Service:
    Type: AWS::ECS::Service
    DependsOn: ListenerRule
    Properties:
      Cluster: !Ref Cluster
      Role: !Ref ServiceRole
      DesiredCount: !Ref DesiredCount
      TaskDefinition: !Ref TaskDefinitionWebserver
      LoadBalancers:
        - ContainerName: !Sub ${EnvironmentName}-webserver
          ContainerPort: 8080
          TargetGroupArn: !Ref TargetGroup

  TaskDefinitionWebserver:
    Type: AWS::ECS::TaskDefinition
    Properties:
      Family: !Sub ${EnvironmentName}-webserver
      ContainerDefinitions:
        - Name: !Sub ${EnvironmentName}-webserver
          Essential: true
          Image: !Ref Image
          Memory: 512
          PortMappings:
            - ContainerPort: 8080
              HostPort: 80

  TargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      Name: !Sub ${EnvironmentName}-webserver
      VpcId: !Ref VPC
      Port: 80
      Protocol: HTTP
      Matcher:
        HttpCode: 200-299
      HealthCheckIntervalSeconds: 30
      HealthCheckPath: /health
      HealthCheckProtocol: HTTP
      HealthCheckTimeoutSeconds: 10
      HealthyThresholdCount: 5

  ListenerRule:
    Type: AWS::ElasticLoadBalancingV2::ListenerRule
    Properties:
      ListenerArn: !Ref LoadBalancerListener
      Priority: 1
      Conditions:
        - Field: path-pattern
          Values:
            - /
      Actions:
        - TargetGroupArn: !Ref TargetGroup
          Type: forward

  ServiceRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub ecs-service-${AWS::StackName}
      Path: /
      AssumeRolePolicyDocument: |
        {
            "Statement": [{
                "Effect": "Allow",
                "Principal": { "Service": [ "ecs.amazonaws.com" ]},
                "Action": [ "sts:AssumeRole" ]
            }]
        }
      Policies:
        - PolicyName: !Sub ecs-service-${AWS::StackName}
          PolicyDocument:
            {
              "Version": "2012-10-17",
              "Statement":
                [
                {
                  "Effect": "Allow",
                  "Action":
                    [
                      "ec2:AuthorizeSecurityGroupIngress",
                      "ec2:Describe*",
                      "elasticloadbalancing:DeregisterInstancesFromLoadBalancer",
                      "elasticloadbalancing:Describe*",
                      "elasticloadbalancing:RegisterInstancesWithLoadBalancer",
                      "elasticloadbalancing:DeregisterTargets",
                      "elasticloadbalancing:DescribeTargetGroups",
                      "elasticloadbalancing:DescribeTargetHealth",
                      "elasticloadbalancing:RegisterTargets"
                    ],
                  "Resource": "*"
                }
                ]
            }

Outputs:

  WebsiteServiceUrl:
    Description: The URL endpoint for the website service
    Value: !Join ["", [!GetAtt LoadBalancer.DNSName, "/"]]

2 个答案:

答案 0 :(得分:1)

SG出口规则

看起来安全组(SG)尚未定义出口规则。 ALB和EC2。

  LoadBalancerSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: !Sub ${EnvironmentName}-loadbalancer
      GroupDescription: Access to the load balancer that sits in front of ECS
      VpcId: !Ref VPC
      SecurityGroupIngress:
        # Allow access from anywhere to our ECS services
        - CidrIp: 0.0.0.0/0
          IpProtocol: -1

我相信,当您在EC2控制台中查看SG的出站规则时,将没有规则。如果是这样,则原因可能是流量可以进入ALB的端口80,但不能从ALB流出,

这是我的理论。因此,请添加出口规则进行验证?

  LoadBalancerSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: !Sub ${EnvironmentName}-loadbalancer
      GroupDescription: Access to the load balancer that sits in front of ECS
      VpcId: !Ref VPC
      SecurityGroupIngress:
        # Allow access from anywhere to our ECS services
        - CidrIp: 0.0.0.0/0
          IpProtocol: -1
      SecurityGroupEgress:
      - IpProtocol: tcp
        FromPort: 80
        ToPort: 80
        CidrIp: 0.0.0.0/0   # <--- Maybe better change to VPC CIDR or ECS/EC2 subnet CIDR rather than any IP.

关于EC2,由于SG是有状态的,因此流量可以通过端口80到达docker容器的端口8080,并且响应可以通过SG返回,因为SG知道它是传入连接的响应。 / p>

对于ALB,来自Internet的传入连接在ALB端口80处终止,然后需要建立与EC2实例端口80的新出站连接,因此,如果我是正确的,则需要定义一个出口规则。

  ECSHostSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: !Sub ${EnvironmentName}-ecs-hosts
      GroupDescription: Access to the ECS hosts and the tasks/containers that run on them
      VpcId: !Ref VPC
      SecurityGroupIngress:
        # Only allow inbound access to ECS from the ELB
        - SourceSecurityGroupId: !Ref LoadBalancerSecurityGroup
          IpProtocol: -1
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: 0.0.0.0/0
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0

但是,如果EC2实例需要安装软件包或创建出站连接,则EC2 SG也需要出口规则。

IAM

关于ECS服务的IAM角色,有预定义的AWS托管角色,所以我想更好地使用它们?

    "Role": {
      "Type": "AWS::IAM::Role",
      "Properties": {
        "AssumeRolePolicyDocument": {
          "Version": "2008-10-17",
          "Statement": [
            {
              "Sid": "",
              "Effect": "Allow",
              "Principal": {
                "Service": "ecs.amazonaws.com"
              },
              "Action": "sts:AssumeRole"
            }
          ]
        },
        "ManagedPolicyArns": ["arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceRole"]
      }
    }

由于AWS现在引入了服务链接角色,因此使用它应该更好。

  • Service-Linked Role for Amazon ECS

    在为Amazon ECS引入服务链接角色之前,您需要为Amazon ECS服务创建IAM角色,该角色向Amazon ECS授予了所需的权限。不再需要此角色,但是如果需要,它可以使用。有关更多信息,请参阅Amazon ECS的旧版IAM角色。

"arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/aws-service-role/ecs.amazonaws.com/AWSServiceRoleForECS"

答案 1 :(得分:0)

谢谢大家!我终于弄清楚了,我必须做的是在服务重定向到/时调整路径。因此,我仅使用通配符更改了侦听器规则:

ListenerRule:
    Type: AWS::ElasticLoadBalancingV2::ListenerRule
    Properties:
      ListenerArn: !Ref LoadBalancerListener
      Priority: 1
      Conditions:
        - Field: path-pattern
          Values:
            - [/*]
      Actions:
        - TargetGroupArn: !Ref TargetGroup
          Type: forward