美文网首页
Spring Cloud on ECS

Spring Cloud on ECS

作者: 魔镜的技术心经 | 来源:发表于2019-02-02 15:06 被阅读65次

    背景

    如果只是在一台主机或者虚拟机上面运行一个容器,那么Docker命令行就足够了,e.g: docker run xxximage。 但是如果需要管理一个100X的容器集群,就比较有挑战了。
    在AWS众多服务中,就有提供集群资源管理和服务调度的服务,比如EKSECS, 由于EKS还没有进入中国区,本篇博客重点介绍在ECS上面运行基于Spring Cloud全家桶的微服务架构。

    ECS的工作原理

    ECS-picture.png

    我们将基于上面的ECS架构图,简单介绍下ECS的一些重要组件和工作原理。

    • ECS agent, 在每一个实例,它都有一个运行的docker进程,它就是ECS agent, 其主要负责接收ECS的命令,并且将这些命令转化为docker对应的命令;所以它能够控制EC2实例,什么时候启动、停止容器并且监控已经使用的和空闲的资源情况。
    • ECS pause, 第一启动的容器,协调以后容器进行协议的分配,防止冲突。
    • Cluster mangement Engine负责协调整个集群的实例,它可以被认为是虚拟的资源池,比如内存、存储、CPU、网络等;所以通过它,能够知道整个集群的资源现状。
    • Scheduler负责调度容器或者tasks的执行;它能知道每个task的运行状态,是否是alive或者dead,是否需要rescheduled等。
    • Kev-Value Store, 负责整个集群状态的管理。
    • API, ECS另一个比较独特的地方,在于它将容器的调度从集群管理中解耦出来,并且提供一些的API,以供使用者使用。

    演示介绍

    基于Spring Cloud全家桶的微服务架构,如何运行在ECS容器云平台上面,本文准备了三个服务,用于演示:

    • 服务一: simple-application, 使用https://start.spring.io/进行创建,主要用于从配置服务器获取动态配置。
    • 服务二: simple-config-server, 主要用于配置服务器,进行微服务配置的管理。
    • 服务三: simple-eureka, 主要用于服务注册与发现。

    每个服务基于docker,需要通过./mvn clean package的方式,进行打包和构建新的docker镜像,然后通过下面类似的命令,将最新的镜像发布到ECR镜像注册服务器上面。

    • 在ECR创建对应的镜像库。
    $(aws ecr get-login --no-include-email --region ap-southeast-1)
    aws ecr create-repository --repository-name simple-cluster/simple-application
    
    • 将最新的镜像,发布到ECR对应的镜像库。
    
    docker tag simple-cluster/simple-application:latest 613175009525.[dkr.ecr.ap-southeast-1.amazonaws.com/simple-cluster/simple-application:latest](http://dkr.ecr.ap-southeast-1.amazonaws.com/simple-cluster/simple-application:latest)
    
    docker push 613175009525.[dkr.ecr.ap-southeast-1.amazonaws.com/simple-cluster/simple-application:latest](http://dkr.ecr.ap-southeast-1.amazonaws.com/simple-cluster/simple-application:latest)
    
    • 发布成功之后,更新Cloudformation对应的镜像仓库地址:
     Sample:
          cpu: 512
          mem: 1024
          javaopt: "-Xms512m -Xmx1024m -Xss512k"
          port: 3000
          hostport: 9050
          name: simple-sample
          context: /simple-application
          taskcount: 1
          minhealthcount: 50
          maxhealthcount: 200
          HealthCheckGracePeriodSeconds: 300
          logPrefix: simple-application
          image: '613175009525.dkr.ecr.ap-southeast-1.amazonaws.com/simple-cluster/simple-application:latest'
          HealthCheckIntervalSeconds: 30
          HealthCheckPath: /simple-application/actuator/info
          HealthCheckPort: traffic-port
          HealthCheckProtocol: HTTP
          HealthCheckTimeoutSeconds: 5
          HealthyThresholdCount: 5
    

    ECS集群:

    可以通过命令行工具ecs-cli up进行创建,或者使用Cloudformation进行创建,本文演示基于Cloudformation的创建方式。

    $ aws cloudformation create-stack --stack-name simple-ecs-cluster-cf-template --template-body file://simple-ecs-cluster-cf.yaml --region ap-southeast-1 --parameters ParameterKey=EcsInstanceType,ParameterValue=t2.medium,ParameterKey=KeyName,ParameterValue=aws-singapore-key,ParameterKey=VpcId,ParameterValue=vpc-0cbbd87895dbbfc5b
    {
        "StackId": "arn:aws:cloudformation:ap-southeast-1:613175009525:stack/simple-ecs-cluster-cf-template/008ff110-2685-11e9-94ea-064b1a6199c8"
    }
    

    创建成功界面如下:


    image.png

    请指定正确的VPC,Subnet,SG和指定EC2的类型,数量,AMI,EBS和key pair,之后ECS会自动创建EC2,并且为其配置如下信息:

     "#!/bin/bash\n","echo ECS_CLUSTER=",!Ref EcsClusterName," >> /etc/ecs/ecs.config\n" 
    

    创建公共的ALB, 并且根据path进行微服务的分发,对外提供接口。

    image.png

    部分相关Cloudformation配置:

    ###############   ALB Default Target-Group ####################
      DefaultALBListener:
        Type: AWS::ElasticLoadBalancingV2::Listener
        Condition: CreateSpringCloud
        Properties:
          DefaultActions:
          - Type: forward
            TargetGroupArn: !Ref DefaultTargetGroup
          LoadBalancerArn: !Ref PublicApplicationLoadBalancer
          Port: 80
          Protocol: HTTP
    
      DefaultTargetGroup:
        Type: AWS::ElasticLoadBalancingV2::TargetGroup
        Condition: CreateSpringCloud
        DependsOn: PublicApplicationLoadBalancer
        Properties:
          HealthCheckIntervalSeconds: !FindInMap [ SpringCloudMiddlewares, Eureka, HealthCheckIntervalSeconds ]
          HealthCheckPath: !FindInMap [ SpringCloudMiddlewares, Eureka, HealthCheckPath ]
          HealthCheckPort: !FindInMap [ SpringCloudMiddlewares, Eureka, HealthCheckPort ]
          HealthCheckProtocol: !FindInMap [ SpringCloudMiddlewares, Eureka, HealthCheckProtocol ]
          HealthCheckTimeoutSeconds: !FindInMap [ SpringCloudMiddlewares, Eureka, HealthCheckTimeoutSeconds ]
          HealthyThresholdCount: !FindInMap [ SpringCloudMiddlewares, Eureka, HealthyThresholdCount ]
          Matcher:
            HttpCode: 200
          Name: default-target-group
          Port: 80
          Protocol: HTTP
          TargetGroupAttributes:
            -
              Key: deregistration_delay.timeout_seconds
              Value: 300
            -
              Key: slow_start.duration_seconds
              Value: 0
            -
              Key: stickiness.enabled
              Value: false
          VpcId: !Ref VpcId
    
    ##############   Spring Cloud Sample Resources start ####################
      SpringCloudSampleECSALBListenerRule:
        Type: AWS::ElasticLoadBalancingV2::ListenerRule
        Condition: CreateSampleTask
        DependsOn: DefaultALBListener
        Properties:
          Actions:
          - Type: forward
            TargetGroupArn: !Ref SpringCloudSampleTargetGroup
          Conditions:
          - Field: path-pattern
            Values: [/simple-application*]
          ListenerArn: !Ref DefaultALBListener
          Priority: 3
    

    指定服务运行环境:

    方法一: 通过ECS task配置环境变量

    environment": [
            {
              "name": "JAVA_OPTS",
              "value": "-Dspring.profiles.active=aws"
            }
          ]
    

    方法二: 通过Cloudformation配置环境变量

     Environment:
                -
                  Name: JAVA_OPTS
                  Value: !FindInMap [ SpringCloudMiddlewares, ConfigServer, javaopt ]
                -
                  Name: EUREKA_URL
                  Value: !Join [ "" , [ "http://", !GetAtt PublicApplicationLoadBalancer.DNSName, "/simple-eureka/eureka"]]
                -
                  Name: SPRING_PROFILES_ACTIVE
                  Value: aws
    

    确保端口动态绑定(非静态绑定),防止端口冲突问题:

    方法一: ECS的task配置,hostPost设置为0.

    "portMappings": [
            {
              "hostPort": 0,
              "protocol": "tcp",
              "containerPort": 8080
            }
          ]
    

    方法二: 通过Cloudformation配置动态端口绑定

     -
       ContainerPort: !FindInMap [ SpringCloudMiddlewares, ConfigServer, port ]
       HostPort: 0
    

    确保SG安全组,允许在动态端口范围内的访问:

    image.png

    创建Task的时候,确保每个task里面都开启了日志记录:

    "logConfiguration": {
            "logDriver": "awslogs",
            "options": {
              "awslogs-group": "simple-ecs-cluster-log",
              "awslogs-region": "cn-northwest-1",
              "awslogs-stream-prefix": "simple-application"
            }
          }
    
    ###############  CloudWatchLog  start ####################
      ECSCloudWatchLogGroup:
        Type: AWS::Logs::LogGroup
        Properties:
          LogGroupName: !Join [ "-" , [ !Ref EcsClusterName, !Ref ECSCloudWatchLogGroupName]]
          RetentionInDays: !Ref ECSCloudWatchLogGroupRetentionInDays
    ###############  CloudWatchLog  end ####################
    

    创建Task的时候,确保每个task里面都拥有足够多的访问权限,比如你的服务需要访问SQS,Redis,S3等。

    集群部署
    部署成功后,可通过下面Eureka界面,查看注册成功的服务:

    ecs-demo-dashbroad.png
    查看ECS集群运行状态:
    ecs-cluster.png

    时区的一致性:

    • EC2上面的时区一致性:
    
    for ec2 in 10.208.195.1xx 10.208.194.xx 10.208.194.1xx 
    do
    echo $ec2;
    ssh -i ~/.ssh/yourkey.pem ec2-user@$ec2  << sshoff
        sudo yum -y erase 'ntp*'
        sudo yum -y install chrony
        sudo service chronyd start
        sudo chkconfig chronyd on
        sudo sed -i 's/ZONE=\"UTC/ZONE=\"Asia\/Shanghai/g' /etc/sysconfig/clock
        sudo ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
        exit
    sshoff
    done
    
    • RDS上面的时区一致性:

      设置Parameter Group,并且重启实例。

    • Docker上面的时区一致性:

      重新构建满足条件的base镜像,并更新响应的配置文件pom.xml或者dockerfile

    • 编码上,保证时区的方法:

    System.setProperty("user.timezone","Asia/Shanghai");
    
    
    • 通过传递参数的方式,保证时区的方法:
    -Duser.timezone=GMT+8 
    

    源代码:

    相关文章

      网友评论

          本文标题:Spring Cloud on ECS

          本文链接:https://www.haomeiwen.com/subject/skjssqtx.html