编者注: AWS Elastic Beanstalk是Amazon Web Services提供的一项编排服务,用于部署基础架构,该基础架构协调了各种AWS服务,包括EC2,S3,简单通知服务(SNS),CloudWatch,自动扩展和Elastic Load Balancer。
Elastic Beanstalk在裸服务器和OS上提供了一个附加的抽象层。 用户会看到操作系统和平台的预构建组合。
部署需要定义许多组件:“应用程序”作为项目的逻辑容器,“版本”是应用程序可执行文件的可部署构建,“配置模板”包含两个Beanstalk环境的配置信息和产品。 (来源: 维基百科 )
现在,我们提供了全面的指南,以便您可以开发自己的基于Amazon Elastic Beanstalk的应用程序。 我们涵盖了广泛的主题,从部署和配置到Java集成和命令行接口。 有了本指南,您将能够在最短的时间内启动并运行自己的项目。 请享用!
目录
1.简介
Amazon Elastic Beanstalk是一项服务,可让您使用一组现有的Amazon AWS服务托管您的应用程序。 与更通用的服务(如EC2)相比,您不必提供已部署到云中的计算机的映像,而只需提供一个可运行的应用程序,该应用程序托管在Amazon AWS的预定义环境中。
Amazon让您在不同的预定义环境之间进行选择,并设置代表您运行应用程序所需的一切。 因此,如果您只想专注于应用程序本身而不是基础操作系统和服务器,那么此服务非常适合您。 但是,由于Elastic Beanstalk在后台使用现有服务,例如EC2,S3,CodeCommit或Route 53,因此您可以完全控制应用程序。
2.概念
Amazon Elastic Beanstalk定义了在整个服务中使用的一组术语,因此必须从头开始理解。 应用程序是一组组件,这些组件不仅包含应用程序的不同版本,而且还包含应用程序部署到的环境的配置。 应用程序版本是可部署的工件,带有标签并存储在Amazon S3存储桶中。 因此,可以在以后的某个时间点还原它。 环境是一组Amazon AWS资源,用于运行特定版本的应用程序。 可以配置不同的环境,并且应用程序的版本可以在不同的环境中运行。
不同的环境可以同时存在,也可以为同一应用程序提供不同的版本。 环境由两层组成: Web服务器环境和工作环境 。 当Web服务器环境提供HTTP请求时,工作环境从队列中读取消息并进行处理。 这样,应用程序可以使用“工作队列”模式将业务逻辑与服务HTTP请求分离。 环境配置包含环境的设置。 应用此配置将使Amazon AWS创建相应的资源。 现有模板可用于创建配置,因此称为配置模板 。
2.1 Web服务器环境
“ Web服务器环境”提供了运行应用程序的所有资源。 它由一台或多台用于部署应用程序的Web服务器组成。 这些Web服务器托管在Amazon AWS云内运行的EC2计算机上。 由于这些计算机位于Elastic Load Balancer的后面,因此可以通过CNAME名称(例如myapp.us-west-2.elasticbeanstalk.com
。 使用Route 53服务将此CNAME别名为内部负载平衡URL。 通过使用域名系统(DNS),此Amazon服务提供了高可用性。 您环境中的EC2计算机可以属于“ Auto Scaling”组。
这意味着如果负载增加,Amazon会自动增加实例数,另一方面,如果负载消失,则将机器数减少到至少一台机器。 在每台计算机上运行的“主机管理器”负责部署应用程序以及收集指标和事件。 它还会监视应用程序服务器并在必要时轮换日志文件。 如果环境的一个组件需要修补程序或更新,则“主机管理器”可以代表您执行此更新。 “安全组”为一组实例定义防火墙规则。 Web服务器环境中的基本安全组允许访问应用程序的端口80(HTTP)。 如果您需要使用数据库,则可以自由定义更多具有更细粒度控制的安全组。
2.2工人环境
“工作人员环境”提供所有资源来运行消耗来自Amazon SQS队列的消息的工作人员应用程序。 因此,它不仅提供运行您的工作程序的EC2机器,还提供一个SQS队列,可用于将消息从“ Web服务器环境”传输到“工作环境”,然后再传输回来。 在“工作人员环境”的每个实例上运行的守护程序从队列中提取请求,并将其传递到您的应用程序。
2.3设计考虑
在开始应用程序之前,必须仔细考虑它的设计。 十分重要的一方面是可伸缩性。 基本上,有两种方法可以处理应用程序上不断增加的负载。 第一种方法是增加每台计算机的可用硬件资源,使其可以处理更多负载。 尽管这种方法可用于负载增加很小的范围,但它不能满足任意需求。
第二种方法是增加正在运行的服务的数量(水平扩展),因为它允许在必要时添加更多计算机。 第二种方法是Amazon Elastic Beanstalk遵循的方法,因为对可用EC2实例的严格监控允许在必要时在自动扩展组中设置新实例。 但这也意味着该应用程序的设计和编写可以扩展。 水平扩展不是构建需要更多硬件的单片应用程序,而是将负载分配到尽可能无状态的任意数量的较小服务上,以便可以在运行时添加新服务。
Web服务器环境前面的负载平衡器将在可用服务之间分配传入请求,要求每个服务可以处理其中一个。 开发适用于AWS Elastic Beanstalk的应用程序时的另一个重要点是安全性。 可以使用SSL对传入和传出Web服务器环境的数据进行加密。 因此,必须从外部认证机构之一(例如VeriSign或Entrust)获得有效的证书。 请注意,SSL加密在环境的负载均衡器处结束,并且它与Web服务器之间的流量通常不加密。
为了能够在必要时启动和停止其他实例,您的应用程序不应在每个节点的本地存储上存储任何数据,因为一旦关闭实例,该数据将被擦除,而在启动另一个实例时,该数据将不存在。 。 因此,必须关注持久性存储。 Amazon AWS提供了可用于您的应用程序以存储状态的不同服务:
- Amazon S3:此服务可用于在云中存储任意数量的数据。
- Amazon Elastic File System:EFS可以安装在您的EC2实例上,并且可以像普通文件系统一样使用。
- Amazon Elastic Block Store:EBS卷已附加到EC2实例,可用于与文件系统或数据库结合使用。
- Amazon DynamoDB:此服务在Amazon云中提供NoSQL数据库。
- Amazon Relational Database Service:RDS管理可以由您的应用程序使用的六个不同的关系数据库引擎(Amazon Aurora,PostgreSQL,MySQL,MariaDB,Oracle和Microsoft SQL Server)。
如果世界各地的用户遇到不同的延迟时间,您可以使用Amazon CloudFront使其自动在世界各地分发您的应用程序和存储,并将用户路由到最近的可用站点。 最后但并非最不重要的一点是,如果有必要,您可以让Amazon更新和修补环境。 这些更新以“滚动批次”的形式执行,即Amazon获取第一批EC2实例并终止它们。
新实例出现后,可以处理下一批。 是否应处理下一批的条件可以基于计时策略或新计算机的运行状况。 通过此过程可以使站点保持运行状态,而应用程序的新旧服务将在短时间内运行。 为此,您当然必须设计应用程序,以使旧版本的服务可以读取新版本已写入的数据。
3. Java Web应用程序
既然我们已经学到了很多有关Amazon Elastic Beanstalk背后的概念的知识,我们应该动手实践,并开发一个小型应用程序,该应用程序使用Apache Tomcat公开一个简单的REST接口。
3.1简单的REST-API
首先,我们使用以下命令行创建一个新的maven项目:
mvn archetype:generate -DgroupId=com.javacodegeeks.ultimate.aws.eb -DartifactId=tomcat-web-service -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false
之后,我们将使用以下结构创建一个名为tomcat-web-service
的新目录:
|-- pom.xml
`-- src
|-- main
| `-- webapp
| `-- index.jsp
| `-- WEB-INF
| `-- web.xml
该原型已经为我们创建了一个web.xml
和一个index.jsp
文件。 后者可用于稍后在云中简单地测试第一个版本,因此我们尚未删除JSP页面。 web.xml
文件需要进行一些编辑:
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>tutorial-webapp</display-name>
<servlet>
<servlet-name>RestServlet</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>com.javacodegeeks.ultimate.aws.eb</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>RestServlet</servlet-name>
<url-pattern>/tutorial-service/*</url-pattern>
</servlet-mapping>
</web-app>
使用XML元素display-name
我们定义如何在Apache Tomcat服务器内部标记应用程序。 servlet
和servlet-mapping
元素定义了正在侦听请求的Servlet类及其应侦听的URL模式。 在我们的例子中,我们使用模式/tutorial-service/*
,即所有看起来像http://://tutorial-service/*
URL都将由该servlet处理。
上下文名称是通过我们部署到tomcat中的战争档案的名称定义的。 参数jersey.config.server.provider.packages
告诉我们将用于实现REST-API的JAX-B实现,它应该扫描哪个Java包以查找注释。 为此,我们必须在maven项目中创建以下目录结构: src/main/java/com/javacodegeeks/ultimate/aws/eb
。 为了告诉maven我们要使用哪个版本的JAX-B实现,我们将以下依赖性信息块复制到您的pom.xml
文件中:
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<jersey.version>2.26</jersey.version>
<junit.version>4.12</junit.version>
<commons-logging>1.1.3</commons-logging>
<log4j.version>1.2.17</log4j.version>
<javax-ws-rs-api.version>2.1</javax-ws-rs-api.version>
<aws-sdk.version>1.11.106</aws-sdk.version>
<db.dynamodb.local-endpoint>false</db.dynamodb.local-endpoint>
</properties>
<dependencies>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>${javax-ws-rs-api.version}</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>${commons-logging}</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>${jersey.version}</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-bom</artifactId>
<version>${aws-sdk.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
在仅API合同( javax.ws.rs-api
)旁边,我们定义使用jersey-container-servlet
作为JAX-B实现,并使用jersey-hk2
进行对jersey的依赖项注入。 由于Amazon SDK使用commons-logging
我们也要这样做。 作为日志记录服务,我们选择了经典的log4j
实现。 目前, junit
和jersey-client
依赖项仅用于我们的集成测试。
拥有可以在本地执行的集成测试大大简化了开发,因为我们不必每次都将新版本的应用程序上载到AWS云中。 当前不需要aws-java-sdk-bom
依赖关系