Spring Cloud on ECS

背景

如果只是在一台主机或者虚拟机上面运行一个容器,那么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 

源代码:

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,258评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,335评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,225评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,126评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,140评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,098评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,018评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,857评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,298评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,518评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,400评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,993评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,638评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,661评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352

推荐阅读更多精彩内容