将Java应用部署到AWS的Elastic Beanstalk上的教程

523 阅读3分钟

将Java应用部署到AWS的Elastic Beanstalk上

本教程分享了一个通过使用亚马逊CDK将Java应用部署到Elastic Beanstalk的简单例子。

我一直在研究亚马逊网络服务,我意识到在亚马逊Elastic Beanstalk(EB)上部署Java应用与部署不需要编译就能运行的应用有些不同。所以这花了我很多时间,我决定分享一个简单的例子,通过使用亚马逊CDK将一个Java应用部署到Elastic Beanstalk。 我们也可以通过很多不同的方式来完成,比如使用EB CLI,但我要讲的是通过使用CDK CLI进行部署。

创建你的应用程序

在开始之前,你可以在GitHub上查看包括已完成的SpringBootCDK项目的存储库。

首先,我们需要创建一个简单的Spring boot应用,你应该在创建时添加Spring Web包。如果你没有IntelliJ Idea Ultimate,你可以从这里初始化一个Spring Boot项目。初始化项目后,你应该将你的应用程序构建为一个jar。

$ mvn clean install

当你正确遵循这些步骤时,你的spring boot应用程序的目标文件夹将看起来像这样: 在你运行命令后的'目标'文件

为了部署我们的Spring Boot应用程序,我们将使用AWS云开发工具包(CDK)与Typescript,但你可以使用任何语言代替。首先,我们需要在一个空目录下创建一个CDK应用项目的例子。在一个你想要的空目录下运行这个命令。

$ CDK init app –language typescript

运行这个命令后,你的CDK文件夹会是这样的:

初始化后的CDK文件夹

现在是编码的时候了!我们将对lib/cdk-deployment-stack.ts 文件进行修改。 首先,我们将创建一个S3 bucket资产来存储我们的应用程序,然后创建一个Elastic Beanstalk环境来运行我们的应用程序。

JavaScript

    const appName ="EBS-Demo"
    
    const app = new elasticbeanstalk.CfnApplication(this, 'Application', {
      applicationName: `${appName}-EB-App`
    });
  
    const apiZipped = new s3assets.Asset(this, 'Zipped-Spring-App',{
      path: `Path of our application zip`,
    });
  
    const appVersionProps = new elasticbeanstalk.CfnApplicationVersion(this, 'Version-1.0', {
      applicationName: `${appName}-EB-App`,
      sourceBundle: {
        s3Bucket: apiZipped.s3BucketName,
        s3Key: apiZipped.s3ObjectKey,
      },
    });
    
    appVersionProps.addDependsOn(app);

有两个构造--由我们的Spring应用组成的S3资产和EB应用版本资源,这是我们可部署代码的迭代。

Elastic Beanstalk可以自动对环境资源执行一些操作,但你需要使用AWS身份和访问管理(IAM)服务定义一些权限。我们将为这些权限向我们的EB角色添加管理策略。

JavaScript

const EbInstanceRole = new iam.Role(this, `${appName}-aws-elasticbeanstalk-ec2-role`, {
  assumedBy: new iam.ServicePrincipal('ec2.amazonaws.com'),
});
const managedPolicy = iam.ManagedPolicy.fromAwsManagedPolicyName('AWSElasticBeanstalkWebTier')

EbInstanceRole.addManagedPolicy(managedPolicy);

const profileName = `${appName}-EbsDemoProfile`

const instanceProfile = new iam.CfnInstanceProfile(this, profileName, {
  
  instanceProfileName: profileName,
  roles: [
    EbInstanceRole.roleName
  ]
});

这些策略和角色将由我们环境实例的OptionSettingProperty来配置。在分配了所有这些之后,我们的环境设置将看起来像这样:

JavaScript

const optionSettingProperties: elasticbeanstalk.CfnEnvironment.OptionSettingProperty[] = [
  {
    namespace: 'aws:autoscaling:launchconfiguration',
    optionName: 'InstanceType',
    value: 't3.small',
  },
  {
    namespace: 'aws:autoscaling:launchconfiguration',
    optionName: 'IamInstanceProfile',
    value: profileName
  },
  {
    namespace: 'aws:autoscaling:launchconfiguration',
    optionName: 'IamInstanceProfile',
    value: instanceProfile.attrArn,
  }
];

现在我们可以创建我们的EB环境了。

JavaScript

    const ebs_env = new elasticbeanstalk.CfnEnvironment(this, 'Environmentm', {
      environmentName: `${appName}-EB-Env`,
      applicationName:  `${appName}-EB-App`,
      solutionStackName: '64bit Amazon Linux 2 v3.2.7 running Corretto 8',
      optionSettings: optionSettingProperties,
      versionLabel: appVersionProps.ref,
    });

我们正在设置我们刚刚创建的用于配置的'optionSettings'。此外,我们还定义了VersionLabel来让EB知道我们的应用程序压缩包在哪里。SolutionStackName是另一个重要的属性,你可以自由选择你的基础设施,但你必须选择适合你的Spring Boot项目的JDK版本。要查看可用的解决方案堆栈名称,请在任何终端上运行此命令。

$ aws elasticbeanstalk list-available-solution-stacks

部署您的应用程序

在这一点上,你的应用程序将被上传到S3桶,但它还没有被部署。你可以在AWS控制台看到你的Elastic Beanstalk环境和应用程序,但应用程序的URL将无法使用。你需要使用 "Elastic Beanstalk > Environments > EBS-Demo-Env " 页面上的 "Upload and Deploy " 按钮,从版本标签中选择你上传的应用程序。在每次部署时都这样做,听起来一点都不实用,不是吗?所以,我们现在要把它自动化...

只有一个配置可以正确运行Spring应用程序。我们需要告诉Elastic Beanstalk如何运行我们存在于S3中的应用程序。我们将分三步来做这件事:

  1. 创建Procfile,运行所需的命令来运行上传的应用程序。你可以在Spring Boot应用程序的根目录下创建它,但建议你把它移到名为 "conf " 的文件夹下,以使你的项目树更简洁。Procfile可以只由一条运行jar的命令组成。

属性文件

web: java -jar SpringApp-0.0.1-SNAPSHOT.jar

2.在 'src/main/resources/assembly'目录下创建'bin.xml'。这就配置了我们的Procfile。

XML

<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd">
    <id>assembly-descriptor</id>
    <baseDirectory>/</baseDirectory>
    <formats>
        <format>zip</format>
    </formats>
    <fileSets>
        <fileSet>
            <directory>${project.basedir}/conf</directory>
            <outputDirectory>/</outputDirectory>
            <includes>
                <include>Procfile</include>
            </includes>
        </fileSet>
        <fileSet>
            <directory>${project.build.directory}</directory>
            <outputDirectory>/</outputDirectory>
            <includes>
                <include>*.jar</include>
            </includes>
        </fileSet>
        <fileSet>
            <directory>${project.basedir}</directory>
            <outputDirectory>/</outputDirectory>
            <includes>
                <include>*.jar</include>
            </includes>
        </fileSet>
    </fileSets>
</assembly>

SpringApp/src/main/resources/assembly/bin.xml

我们还将构建格式的输出改为zip。所以我们可以插入代理或额外的包,供我们的应用程序使用。

3.在你的pom.xml中插入汇编插件。

XML

    <profiles>
        <profile>
            <id>build</id>
            <activation>
                <activeByDefault>false</activeByDefault>
            </activation>
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-assembly-plugin</artifactId>
                        <version>2.6</version>
                        <executions>
                            <execution>
                                <id>assembly-on-package</id>
                                <configuration>
                                    <descriptor>src/main/resources/assembly/bin.xml</descriptor>
                                    <finalName>${project.build.finalName}</finalName>
                                    <appendAssemblyId>false</appendAssemblyId>
                                </configuration>
                                <phase>package</phase>
                                <goals>
                                    <goal>single</goal>
                                </goals>
                            </execution>
                        </executions>
                    </plugin>
                </plugins>
            </build>
        </profile>
    </profiles>

另外,我们还需要做一个配置,以正确运行spring应用程序。在'64bit Amazon Linux 2 v3.2.5 running Corretto 8'上,Elastic Beanstalk使用的默认端口是5000。我使用了这个端口,但Spring Boot使用的是8080。因此,如果我们直接部署我们的应用程序,EB将无法运行这个。我们可以通过添加这一行来改变我们应用程序的端口 application.properties 文件中。

server.port=5000

此外,我们还可以从 "OptionSettingProperty"中改变Elastic Beanstalk的默认端口,而不是改变Spring应用的端口。

所有的配置都完成了!现在通过使用Spring应用目录下的汇编插件再次运行构建命令。

$ mvn clean install -P build

检查目标文件下的zip文件是否存在:

运行命令后的'目标'文件

你可以记得,我们在创建S3资产时没有填写应用路径。请按以下方式更新你的代码。

JavaScript

const apiZipped = new s3assets.Asset(this, 'Zipped-Spring-Api',{
     path:`${__dirname}/../../SpringApp/target/SpringApp-0.0.1-SNAPSHOT.zip`,
})

最后,在你的CDK目录下运行deploy命令,这就结束了。

$ cdk deploy

我们可以看到我们的应用程序在EB上运行。从AWS控制台查看:

转到你的URL地址:

恭喜你!你的应用程序正在云上运行。你的应用程序正在云上运行。不要忘记销毁你的应用程序以防止不需要的发票。

$ cdk destroy

奖金

我简单地谈到了为什么我们要配置我们的 "bin.xml "来在一个压缩文件中构建我们的应用程序。现在我们将在我们的Spring应用程序中使用一个代理。这将帮助我们监控在Elastic Beanstalk上运行的应用程序。通过这样做,我们将能够监控端点的点击率、成功率、延迟信息等。这是一个来自Thundra的名为应用性能监控(APM)的产品。

在你的应用程序中添加一个APM代理是很容易的。你也可以按照文档来做,但我将简单介绍一下如何做。

  1. 注册Thundra 后,登录并选择 APM。从左侧底部选择 "简介">"项目",然后从这里复制API密钥。不要分享这个ApiKey,要把它当作自己的荣誉来保护:)

  2. 下载APM代理,并将其移动到Spring应用程序的根目录中。

3.更新procfile,使我们的应用程序与APM代理一起运行。

属性文件

web: java -javaagent:thundra-agent-bootstrap-2.7.50.jar -Dthundra.apiKey=********-****-****-****-************ -Dthundra.agent.application.name=My-Spring-App -jar SpringApp-0.0.1-SNAPSHOT.jar

这就是全部! 当你用'mvn clean install -P build'再次构建你的应用程序时,你会看到我们的压缩文件包括APM代理。最后,你可以重新部署资源并更新应用程序:

$ cdk deploy