AWS ECS:使用任务和服务定义部署容器

时间:2020-02-23 14:30:22  来源:igfitidea点击:

本文是在AWS ECS上运行Docker容器的第4部分教程的第3部分。
ECS代表弹性容器服务。
它是可以运行docker容器的托管容器服务。
尽管AWS还使用Kubernetes(EKS)提供了容器管理,但它也有其专有的解决方案(ECS)。

该教程将涵盖以下内容:创建ECS群集,提供镜像注册表(ECR)并将docker镜像推送到注册表,使用任务和服务定义将容器部署到群集,创建管道以更新ECS群集上运行的服务。

将使用从Docker Hub推送到ECR注册表中的简单hello-world镜像。
我们将创建任务和服务定义,并将其部署到ECS集群中。

要求/准备工作

一个AWS账户。
在该账户上创建一个用户,该账户具有配置该账户上的资源的权限;使用自定义域创建了Route 53托管区域(根据用户要求可以是公共区域,也可以是私有区域)。
ACM(Amazon证书管理器)。
提供了一个AWS ECS集群。
将Docker镜像上传到ECR注册表。

创建AWS Application Load Balancer和目标组

ALB(应用程序负载平衡器)是一个AWS托管的负载平衡器,可根据OSI第7层协议路由流量。
我们将使用负载均衡器公开我们的hello-world服务终结点。
我们已经在下面的链接上提供了有关创建应用程序负载均衡器的AWS教程:使用CloudFormationHence创建和配置AWS应用程序负载均衡器,我不会在ALB上介绍太多细节。
我们将使用下面的CloudFormation模板来创建和配置我们的ECS ALB。
模板将设置; ALB(应用程序负载平衡器).ALB安全组。
目标组.ALB侦听器和侦听器规则.N/B:如果读取器/用户希望在内部公开其服务,则应在以下位置创建负载平衡器专用子网。
否则,负载平衡器应面向互联网并在公共子网中创建。
对于高可用性的负载平衡器,用户应在不同可用性区域的不同子网中进行配置。

AWSTemplateFormatVersion: "2010-09-09"
Description: "Create ALB, Target Groups and ALB security group"
Parameters:
    VPC:
        Type: String
        Description: The vpc to launch the service
        Default: vpc-ID
    PublicSubnet1:
        Type: String
        Description: The subnet where to launch the service
        Default: subnet-ID
    PublicSubnet2:
        Type: String
        Description: the subnet where to Launch the service
        Default: subnet-ID
Resources:            
    ALBSecurityGroup:
        Type: "AWS::EC2::SecurityGroup"
        Properties:
            GroupDescription: "security group for ALB"
            GroupName: "test-prod-ALB-SG"
            Tags: 
              - 
                Key: "Project"
                Value: "test-blog"
              - 
                Key: "createdBy"
                Value: "Maureen Barasa"
              - 
                Key: "Environment"
                Value: "test"
              - 
                Key: "Name"
                Value: "test-ALB-SG"
            VpcId: !Ref VPC
            SecurityGroupIngress: 
              - 
                CidrIp: "0.0.0.0/0"
                FromPort: 80
                IpProtocol: "tcp"
                ToPort: 80
              - 
                CidrIp: "0.0.0.0/0"
                FromPort: 443
                IpProtocol: "tcp"
                ToPort: 443
    
    ApplicationLoadBalancer:
        Type: "AWS::ElasticLoadBalancingV2::LoadBalancer"
        Properties:
            Name: "test-Application-Load-Balancer"
            Scheme: "internet-facing"
            Type: "application"
            Subnets: 
              - !Ref PublicSubnet1
              - !Ref PublicSubnet2
            SecurityGroups: 
              - !Ref ALBSecurityGroup
            IpAddressType: "ipv4"
            LoadBalancerAttributes: 
              - 
                Key: "access_logs.s3.enabled"
                Value: "true"
              - 
                Key: "idle_timeout.timeout_seconds"
                Value: "60"
              - 
                Key: "deletion_protection.enabled"
                Value: "false"
              - 
                Key: "routing.http2.enabled"
                Value: "true"
              - 
                Key: "routing.http.drop_invalid_header_fields.enabled"
                Value: "false"
            Tags: 
              - 
                Key: "Project"
                Value: "test-blog"
              - 
                Key: "createdBy"
                Value: "Maureen Barasa"
              - 
                Key: "Environment"
                Value: "test"
              - 
                Key: "Name"
                Value: "test-Application-Load-Balancer"
    HTTPSListener:
        Type: "AWS::ElasticLoadBalancingV2::Listener"
        Properties:
            LoadBalancerArn: !Ref ApplicationLoadBalancer
            Port: 443
            Protocol: "HTTPS"
            SslPolicy: "ELBSecurityPolicy-2015-08"
            Certificates: 
              - 
                CertificateArn: arn:aws:acm:eu-central-1:** **** **** ***:certificate/** **** **** **
                
            DefaultActions: 
              - 
                Order: 1
                TargetGroupArn: !Ref TestTargetGroup
                Type: "forward"
    HTTPListener:
        Type: "AWS::ElasticLoadBalancingV2::Listener"
        Properties:
            LoadBalancerArn: !Ref ApplicationLoadBalancer
            Port: 80
            Protocol: "HTTP"
            DefaultActions: 
              - 
                Order: 1
                RedirectConfig: 
                    Protocol: "HTTPS"
                    Port: "443"
                    Host: "#{host}"
                    Path: "/#{path}"
                    Query: "#{query}"
                    StatusCode: "HTTP_301"
                Type: "redirect"
                
    TestTargetGroup:
        Type: "AWS::ElasticLoadBalancingV2::TargetGroup"
        Properties:
            HealthCheckIntervalSeconds: 30
            HealthCheckPath: "/"
            Port: 80
            Protocol: "HTTP"
            HealthCheckPort: "traffic-port"
            HealthCheckProtocol: "HTTP"
            HealthCheckTimeoutSeconds: 5
            UnhealthyThresholdCount: 2
            TargetType: "ip"
            Matcher: 
                HttpCode: "200"
            HealthyThresholdCount: 5
            VpcId: !Ref VPC
            Name: "target-group-1"
            HealthCheckEnabled: true
            TargetGroupAttributes: 
              - 
                Key: "stickiness.enabled"
                Value: "false"
              - 
                Key: "deregistration_delay.timeout_seconds"
                Value: "300"
              - 
                Key: "stickiness.type"
                Value: "lb_cookie"
              - 
                Key: "stickiness.lb_cookie.duration_seconds"
                Value: "86400"
              - 
                Key: "slow_start.duration_seconds"
                Value: "0"
              - 
                Key: "load_balancing.algorithm.type"
                Value: "round_robin"
               
    TestListenerRule1:
        Type: "AWS::ElasticLoadBalancingV2::ListenerRule"
        Properties:
            Priority: "1"
            ListenerArn: !Ref HTTPSListener
            Conditions: 
              - 
                Field: "host-header"
                Values: 
                  - "test1.helloworld.com"
            Actions: 
              - 
                Type: "forward"
                TargetGroupArn: !Ref TestTargetGroup
                Order: 1
                ForwardConfig: 
                    TargetGroups: 
                      - 
                        TargetGroupArn: !Ref TestTargetGroup
                        Weight: 1
                    TargetGroupStickinessConfig: 
                        Enabled: false
Outputs:        
    ALB:
        Description: The created loadbalancer
        Value: !Ref ApplicationLoadBalancer
    TargetGroup:
        Description: The created TargetGroup 
        Value: !Ref TestTargetGroup
    LoadBalancerSecurityGroup:
        Description: the securty group for the ALB
        Value: !Ref ALBSecurityGroup

确保在HTTPS侦听器下,用生成的证书ARN替换证书。
同样,根据侦听器规则,我们应该将主机标头替换为用户在Route 53托管区域上创建的记录集。
资源的标签和名称也应根据用户的要求进行自定义。

ECS任务和服务定义

ECS任务定义定义了Docker容器的要求。
它定义要使用的图像,CPU和内存要求等an Service定义定义了如何运行应用程序/服务。
它定义了启动类型,将运行服务的群集,目标组用于ALB,任务定义使用等

创建ECS任务执行角色

n/b:通常已经在AWS帐户上创建了任务执行角色。
一个人可以搜索它 ecsTaskExecutionRole
如果尚未在帐户创建一个,请使用下面的CloudFormation模板创建一个。

AWSTemplateFormatVersion: "2010-09-09"
Description: "Template to create ECS Task Execution Role"
Resources:
  ECSTaskExecutionRole:
    Type: 'AWS::IAM::Role'
    Properties:
      Description: The ECS task execution Role
      RoleName: AWSECSTaskExecutionRole
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
              - ecs-tasks.amazonaws.com
            Action:
              - 'sts:AssumeRole'
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
      Tags: 
        - 
          Key: "Project"
          Value: "test-blog"
        - 
          Key: "Environment"
          Value: "test"
        - 
          Key: "createdBy"
          Value: "Maureen Barasa"
        - 
          Key: "Name"
          Value: "AWSECSTaskExecutionRole"
          
Outputs:
  IAMRole:
    Description: the role created
    Value: !Ref ECSTaskExecutionRole
    Export: 
      Name: !Sub "${AWS::StackName}-rolename"

创建ECS任务和服务定义

使用以下模板创建任务和服务定义.n/b:模板为fargate群集创建任务和服务定义。
此外,对于任务角色和任务执行角色ARN,使用ARN for上面创建的角色,或者如果存在,则使用ARN for EcstAskexecutionRole.to为EC2集群创建任务和服务定义,用EC2替换Service Definition上的LaunchType。
在任务定义上,EC2可以使用任何网络模式; AWSVPC,桥梁或者主机。
FARGATE仅适用于AWSVPC模式。

AWSTemplateFormatVersion: "2010-09-09"
Description: "hello-world task and service definition"
Parameters:
    VPC:
        Type: String
        Description: The vpc to launch the service
        Default: vpc-ID
    Subnet1:
        Type: String
        Description: The subnet where to launch the service
        Default: subnet-ID
    Subnet2:
        Type: String
        Description: The subnet where to launch the service
        Default: subnet-ID
Resources:
    CWLoggroup:
        Type: AWS::Logs::LogGroup
        Properties:
            LogGroupName: ecs-hello-world-Loggroup
    TaskDefinition:
        Type: "AWS::ECS::TaskDefinition"
        Properties:
            ContainerDefinitions: 
              - 
                Essential: true
                Image: 429758582529.dkr.ecr.eu-central-1.amazonaws.com/hello-world:latest
                LogConfiguration: 
                    LogDriver: "awslogs"
                    Options: 
                        awslogs-group: !Ref CWLoggroup
                        awslogs-region: !Ref AWS::Region
                        awslogs-stream-prefix: "ecs"
                Name: "Hello_World"
                PortMappings: 
                  - 
                    ContainerPort: 80
                    HostPort: 80
                    Protocol: "tcp"
            Family: "Hello_World"
            TaskRoleArn: arn:aws:iam::429758582529:role/AWSECSTaskExecutionRole
            ExecutionRoleArn: arn:aws:iam::429758582529:role/AWSECSTaskExecutionRole
            NetworkMode: "awsvpc"
            RequiresCompatibilities: 
              - "FARGATE"
            Cpu: "256"
            Memory: "512"
    ServiceDefinition:
        Type: "AWS::ECS::Service"
        Properties:
            ServiceName: "hello-world"
            Cluster: "arn:aws:ecs:eu-central-1:429758582529:cluster/eu-central-1-test-ECS-Fargate-Cluster"
            LoadBalancers: 
              - 
                TargetGroupArn: "arn:aws:elasticloadbalancing:eu-central-1:** **** **** **:targetgroup/test-fargate-hello/** **** ***"
                ContainerName: "Hello_World"
                ContainerPort: 80
            DesiredCount: 1
            LaunchType: "FARGATE"
            PlatformVersion: "1.4.0"
            TaskDefinition: !Ref TaskDefinition
            DeploymentConfiguration: 
                MaximumPercent: 200
                MinimumHealthyPercent: 100
            NetworkConfiguration: 
                AwsvpcConfiguration: 
                    AssignPublicIp: "ENABLED"
                    SecurityGroups: 
                      - "sg-ID"
                    Subnets: 
                      - !Ref Subnet1
                      - !Ref Subnet2
            HealthCheckGracePeriodSeconds: 300
            SchedulingStrategy: "REPLICA"
Outputs:
  HelloTaskDefinition:
    Description: The created name of the ECS TaskDefinition 
    Value: !Ref TaskDefinition
  HelloService:
    Description: The ECS service
    Value: !Ref Service

N/B:CloudFormation模板应定制到用户的要求。
我们可以自定义:要配置的资源的名称。
对于容器定义,我们可以更改图像名称,端口映射等。
用户/阅读器还应该替换群集和目标组ARN以反映他/她自己的价值。
完成后,我们应该在ECS集群上运行的服务如下。

我们现在可以通过我们创建的域名访问服务。