亚马逊AWS官方博客

Spring Cloud 的云原生迁移 – AWS 上的混合部署架构(上篇)

简介

微服务是一种软件开发的组织和架构方法,它可以加快软件交付周期、增强创新和自主性,提高软件的可维护性和可伸缩、可扩展性,同时也提高了企业开发和发布软件服务的能力。使用微服务架构,软件产品将由多个独立的、可通过API进行交互的服务组成。这些服务将由各个小团队独自负责。

 

Spring Cloud是一个基于Spring Boot实现的微服务架构开发工具。它为微服务架构中涉及的配置管理、服务治理、断路器、智能路由、微代理、控制总线、全局锁、决策竞选、分布式会话和集群状态管理等操作提供了一种简单的开发方式。

 

由于Spring生态在Java开发者中具有广泛的影响力,Spring Cloud基于Spring Boot对大型项目开发难度的简化,对开发微服务所需的组件进行了简单高效的封装,Spring Cloud已成为Java领域开发微服务的实际标准。由于Spring Cloud技术已有较长的应用时间,用户把原有的虚拟机部署应用往更云原生的技术(如:容器)迁移可能会遇到各种问题,本系列将使用AWS EC2及EKS服务作为混合架构的样例基础设施(即虚拟机与容器混合),在AWS上部署Spring Cloud应用,以给在AWS上部署及迁移Spring Cloud应用遇到难题的开发者提供参考。

 

架构设计

  • 注册发现中心Eureka的高可用为软件实现,需要在配置文件里配置所有Eureka server信息,Eureka server间进行信息同步。因此,架构方案选择在每个可用区创建独立的EC2部署Eureka server,同时使用独立的ELB以固定每个Eureka server的DNS,及独立的Auto scaling group以保证每个可用区内Eureka server的正常工作。
  • API gateway是微服务架构中另一个重要设施。API gateway本身为无状态服务,有了Eureka注册发现中心的保障,每个API gateway server都可以自动发现需要调用的服务。在架构方案中,使用一个统一的ELB,以暴露对外服务的URL;同时使用一个Auto scaling group保证API gateway的高可用及可扩展性。示例架构中,使用Spring Cloud 中的Zuul作为示例API gateway组件。
  • 使用AWS托管的Kubernetes服务EKS部署实际业务的工作负载,可实现业务负载的快速扩展、灵活调度,同时降低Kubernetes群集的运维难度。
  • S3和ECR作为应用部署包以及Docker镜像的仓库,可方便地对接微服务架构中CI/CD各种不同方案。
  • 对于系统中各种公共变量,使用System Manager中的Parameter Store进行存储。可实现公共变量的动态调整,和应用部署时进行动态注入。

 

为什么使用混合架构进行部署

虚拟化技术特点考量

随着虚拟化技术的演进,计算服务经历了从物理服务器,到虚拟机、容器化,最后到无服务器服务的过程。随着抽象级别的提高,除了用户可以更专注于业务逻辑以外;不同级别的虚拟化技术带来的,是应用启动及期望持续运行时间量级的不同;用户可以根据具体应用的特征,选择合适的虚拟化技术层级。通常,虚拟机(如:EC2)的启动时间为分钟级,期望持续运行时间为数周至数月;容器化(如:Docker)的启动时间为秒级,期望持续运行时间为数十分钟至数周;无服务器服务(如:Lambda)的启动时间为毫秒级,期望持续运行时间为数秒至最多15分钟。

在Spring Cloud的使用场景中,Eureka、API gateway等微服务基础设施需要长久不间断地运行,通常还希望能独占计算资源,以保障其高可靠性。虚拟机技术满足以上要求,同时为保障技术前后兼容性,示例架构中仍使用EC2部署相关工作负载。而具体业务功能模块,通常需要更灵活的调度,以及更快的启动速度以应对突发流量。因此,选择容器化技术率先对相关工作负载进行迁移。

系统技术兼容性考量

由于Spring Cloud已经流行多年,在实际项目中,会有更多兼容性的考虑。如:已有的项目都是使用EC2进行应用部署,由于容器技术带来的好处,新的业务模块使用容器化部署,或旧的模块需要进行容器化改造,甚至在一个微服务系统中,存在多个群集,多种容器管理平台。这些情况下,把微服务的基础设施进行独立部署,不依赖于特定的容器管理平台,将使新旧项目的衔接更平滑,带来更好的向前兼容和向后扩展性。

 

部署Spring Cloud的基础服务模块

前置条件

  • 熟悉AWS网络知识。能搭建功能完备的VPC,创建修改公有/私有子网、安全组。参考文档:

https://docs.aws.amazon.com/zh_cn/vpc/latest/userguide/VPC_Scenarios.html

  • 熟悉AWS EC2。能通过启动模板与auto scaling组结合,创建动态伸缩的EC2群集。通过ELB为群发分发访问流量。参考文档:

https://docs.aws.amazon.com/zh_cn/AWSEC2/latest/UserGuide/EC2_GetStarted.html

https://docs.aws.amazon.com/zh_cn/elasticloadbalancing/latest/network/network-load-balancer-getting-started.html

https://docs.aws.amazon.com/zh_cn/autoscaling/ec2/userguide/create-launch-template.html

  • 熟悉AWS S3。能在S3桶中上传下载文件。参考文档:

https://docs.aws.amazon.com/zh_cn/AmazonS3/latest/gsg/GetStartedWithS3.html

  • 熟悉AWS IAM。能通过IAM配置访问各种服务所需权限的角色(Role),并把Role附加在EC2上。参考文档:

https://docs.aws.amazon.com/zh_cn/IAM/latest/UserGuide/id_roles.html

  • 了解AWS Systems Manager,能使用Parameter Store功能。参考文档:

https://docs.aws.amazon.com/zh_cn/systems-manager/latest/userguide/systems-manager-parameter-store.html

 

部署Eureka server

1.创建NLB for Eureka server

 

分别为Eureka server创建位于三个不同可用区的ELB。示例中,使用Network Load Balancer作为组件。记录相应的DNS,后续存储于Parameter Store中,各个微服务模块进行读取,作为环境变量注入。

2.使用Parameter Store存储系统的公共变量

 

打开AWS Systems Manager服务,选择Parameter Store。

创建参数,分别存储Eureka server的三个DNS。示例如下:

创建Eureka server服务端口参数:


3.Eureka server应用中的配置

 

如下为Eureka server的Spring Cloud项目application.properties文件的配置示例。

spring.application.name=eureka-server
server.port=${eureka_server_port}

eureka.instance.hostname=${eureka_server_1}
eureka.client.service-url.defaultZone=http://${eureka_server_2}:${eureka_server_port}/eureka,http://${eureka_server_3}:${eureka_server_port}/eureka

 

4.应用Jar包的存放

 

创建S3桶作为应用Jar包的存放地,并上传应用Jar包。

 

5.创建IAM角色

 

创建IAM角色,附加托管策略AmazonS3ReadOnlyAccess及AmazonSSMReadOnlyAccess,使附加该角色的server可以访问S3及Parameter Store中的资源。

 

6.创建启动模板

 

选择所需的AMI及实例类型

配置网络及安全组

配置IAM实例配置文件(重要),选择步骤5中创建的AMI角色配置文件。

配置用户数据(重要),以在EC2实例启动时配置所需的环境变量及启动Java应用。如下为配置示例:

#!/bin/bash
yum update -y
yum install -y java-1.8.0-openjdk.x86_64 jq.x86_64
mkdir /opt/spring_cloud
mkdir /var/log/spring_cloud

aws configure set region us-east-2

# Download Java package from S3
aws s3 cp s3://spring-cloud-test/test-eureka-server-0.0.1-SNAPSHOT.jar /opt/spring_cloud/

# Set env variable
export eureka_server_port=$(aws ssm get-parameter --name='/Spring/Eureka/Server/port' --region us-east-2 | jq '.Parameter | .Value ' | sed 's/\"//g' )
export eureka_server_1=$(aws ssm get-parameter --name='/Spring/Eureka/Server/URL_1' --region us-east-2 | jq '.Parameter | .Value ' | sed 's/\"//g' )
export eureka_server_2=$(aws ssm get-parameter --name='/Spring/Eureka/Server/URL_2' --region us-east-2 | jq '.Parameter | .Value ' | sed 's/\"//g' )
export eureka_server_3=$(aws ssm get-parameter --name='/Spring/Eureka/Server/URL_3' --region us-east-2 | jq '.Parameter | .Value ' | sed 's/\"//g' )

# Start Eureka server
java -jar /opt/spring_cloud/test-eureka-server-0.0.1-SNAPSHOT.jar --spring.profiles.active=peer1 &

 

 

 

7.创建Auto Scaling Group

 

选择步骤6中创建的启动模板

网络配置。选择只在单一可用区启动。

启用负载均衡器及目标组

配置组大小和扩展策略。3个Eureka server的Auto scaling group作用为保持每一个可用区中都只有一个Eureka server,无需扩展。配置如下。

 

8.确认Eureka server配置及工作正常

 

在Auto Scaling Group正确设置后,位于三个不同可用区的EC2实例将被自动创建。

访问Eureka Serve的ELB DNS,显示三个Eureka Serve已经相互注册则表示功能运行正常。

部署API Gateway (Zuul)

1.创建NLB for API Gateway

 

为API Gateway创建一个跨3可用区的ELB,作为对外服务的唯一入口。示例中,使用Network Load Balancer作为组件。分布于3个可用区的无状态API Gateway server将均匀接受访问流量。

 

2.API Gateway应用中的配置

 

如下为API Gateway的Spring Cloud项目application.properties文件的配置示例。

spring.application.name=api-gateway
server.port=8081

eureka.client.service-url.defaultZone=http://${eureka_server_1}:${eureka_server_port}/eureka,http://${eureka_server_2}:${eureka_server_port}/eureka,http://${eureka_server_3}:${eureka_server_port}/eureka

zuul.routes.api-hello-service.path=/api-hello-service/**
zuul.routes.api-hello-service.service-id=hello-service

 

 

 

3.应用Jar包上传至S3桶

 

4.创建启动模板

 

选择所需的AMI及实例类型

 

配置网络及安全组

 

配置IAM实例配置文件(重要),选择Eureka部署中创建的公用AMI角色配置文件。

 

配置用户数据(重要),以在EC2实例启动时配置所需的环境变量及启动Java应用。如下为配置示例:

#!/bin/bash
yum update -y
yum install -y java-1.8.0-openjdk.x86_64 jq.x86_64
mkdir /opt/spring_cloud
mkdir /var/log/spring_cloud

aws configure set region us-east-2
aws s3 cp s3://spring-cloud-test/api-gateway-0.0.1-SNAPSHOT.jar /opt/spring_cloud/

export eureka_server_port=$(aws ssm get-parameter --name='/Spring/Eureka/Server/port' --region us-east-2 | jq '.Parameter | .Value ' | sed 's/\"//g' )
export eureka_server_1=$(aws ssm get-parameter --name='/Spring/Eureka/Server/URL_1' --region us-east-2 | jq '.Parameter | .Value ' | sed 's/\"//g' )
export eureka_server_2=$(aws ssm get-parameter --name='/Spring/Eureka/Server/URL_2' --region us-east-2 | jq '.Parameter | .Value ' | sed 's/\"//g' )
export eureka_server_3=$(aws ssm get-parameter --name='/Spring/Eureka/Server/URL_3' --region us-east-2 | jq '.Parameter | .Value ' | sed 's/\"//g' )

java -jar /opt/spring_cloud/api-gateway-0.0.1-SNAPSHOT.jar &

 

 

 

5.创建Auto Scaling Group

 

选择步骤4中创建的启动模板

 

网络配置。选择在三个可用区启动。

 

启用负载均衡器及目标组

按需配置组大小。不添加扩展策略,待Auto Scaling Group创建完成后添加。配置如下。

 

添加扩展策略


 

6.确认API Gateway配置及工作正常

 

在Auto Scaling Group正确设置后,位于三个不同可用区的EC2实例将被自动创建。

访问Eureka Serve的ELB DNS,显示三个API Gateway已经注册则表示功能运行正常。

 

总结

微服务架构是现代大型系统设计开发中最流行的模式,Spring Cloud则是Java生态中微服务开发的实际标准。本文探讨了在AWS上如何规划Spring Cloud的部署,提出了架构的整体思路,最后提供了在EC2上部署Spring Cloud基础服务的具体实践。通过本文的介绍,希望能给Spring Cloud的使用者带来一点在AWS上进行部署的思路,从而更快更好地利用AWS提供的基础设施,快速实现业务价值。

 

参考资料

[1]https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/concepts.html

[2]https://docs.aws.amazon.com/AmazonS3/latest/dev/Welcome.html

[3]https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-parameter-store.html

[4]https://docs.aws.amazon.com/IAM/latest/UserGuide/introduction.html

[5]翟永超.Spring Cloud 微服务实战[M].电子工业出版社:北京,2017:1.

 

本篇作者

何文安

AWS解决方案架构师,负责帮助客户进行上云架构的设计和咨询。在银行及电商行业有丰富的咨询和架构设计经验。加入 AWS 前曾于全球大型银行、国际消费品企业,担任系统分析师及领域专家,负责高并发、高可用系统架构设计,应用微服务化及云上迁移等具体实践。