前言

由于实验是布置下来的个人实验,请勿直接抄袭,我这里写实操只是为了记录我的学习历程,与分享我的实验经验。

内容全部都为个人理解,不一定正确,如果你发现了文章中有存疑的地方或者你对某个地方有疑问,欢迎在评论区留言,大家一起学习。

部分常见问题可以访问下面这个文章

在前面的实践中,我们完成了架构一和架构二的实施与部署,接下来我们就可以对课程设计附加分部分进行操作了。

题目

在完成以上所有任务过程中,如果你使用了如下资源或服务,均可作为本课程设计成绩的加分项:

1.部分静态资源(如网页上的图片等)存储在S3中,通过CloudFront分发

2.使用堡垒机登录实例

3.VPC通过CloudFormation模板构建

4.基于CloudWatch指标做AutoScaling

5.使用DynamoDB保存会话状态

6.使用Amazon ElastiCache for Redis作数据库缓存

7.使用消息队列SQS

准备工作

基础补习

老规矩,先补习基础,看懂专有名词才能完成接下来的操作

  1. S3 (Simple Storage Service): Amazon Simple Storage Service 是一种对象存储服务,用于存储和检索大量数据,适用于各种用例,如备份和恢复、存档、大数据分析等。
  2. CloudFront: Amazon CloudFront 是一项快速内容传递网络服务 (CDN),可帮助加速静态和动态网络内容的传输。
  3. 堡垒机: 在云计算环境中,堡垒机是一种用于安全访问云资源的中间服务器。它充当了控制和监视用户对云资源访问的关键角色。
  4. CloudFormation: Amazon CloudFormation 是一项基础设施即代码服务,允许您以声明性模板的方式定义和部署 AWS 资源。
  5. CloudWatch: Amazon CloudWatch 是一项监控和管理 AWS 资源的服务,可帮助您收集和跟踪指标、监控日志文件和设置警报。
  6. DynamoDB: Amazon DynamoDB 是一种全托管的 NoSQL 数据库服务,具有高可扩展性和低延迟,适用于各种应用程序。
  7. Amazon ElastiCache for Redis: Amazon ElastiCache for Redis 是一种托管的 Redis 内存数据库服务,用于加速读取操作,缓存数据和提高性能。
  8. SQS (Simple Queue Service): Amazon Simple Queue Service 是一项托管的消息队列服务,用于在分布式系统中传递消息。

思路解析

由于我一开始并没打算做这部分的操作,导致我的web程序就没办法实现上面的很多内容。但笔记都写两篇了,感觉这部分也能争取做一下。

先简单说一下接下来的操作:

✔1.部分静态资源(如网页上的图片等)存储在S3中,通过CloudFront分发:做,我打算给我的web程序加一个背景图,这个背景图就用s3存储,通过CloudFront分发

✔2.使用堡垒机登录实例:做,比如在完成架构二后,我们需要对私有子网中的EC2实例进行一些操作,就可以通过这个堡垒机来操作。

✔3.VPC通过CloudFormation模板构建:不做,因为这需要会AWS的CloudFormation语法与清楚AWS资源的相关资源代码,比较麻烦,所以我这里就不去完成这个点。但实际上这个操作实用性非常强,可以摆脱web页面上的一些操作,直接通过代码来创建相关的VPC,对云计算比较感兴趣,可以操作一下。本来是不想做的,但无奈,某个月黑风高的晚上好奇心爆棚,进CloudFormation页面看了一眼,发现已经有一个堆栈,出于强迫症,我把这个堆栈删了,睡了一觉后实验就再也开启不了了。这个堆栈是实验初始化的堆栈,删了会把堆栈之前创建出来的资源也删除,所以后面实验就会启动不了。最后被逼无奈只能对账号来一个reset操作,想了一下反正账号实验环境都格式化了,就动手做了一下这部分。

✔4.基于CloudWatch指标做AutoScaling:做,这个操作其实在前面架构二的笔记中 创建AutoScaling时就已经完成了。

❌5.使用DynamoDB保存会话状态:

❌6.使用Amazon ElastiCache for Redis作数据库缓存

❌7.使用消息队列SQS

5.6.7都不做,因为我的web应用用不上,就不进行具体得操作了,但实操中会有相对应的个人思考讲解。

实操

1.使用S3存储,通过CloudFront分发

模拟需求:给Web应用设置一个背景图片,背景图片使用使用S3存储,通过CloudFront分发。

操作步骤:创建S3存储桶-->上传背景图片-->创建CloudFront-->修改Web程序代码,重新打包上传EC2-->创建新Web应用的AMI-->修改启动模板

创建S3存储桶

进入S3控制台,创建S3存储桶,在常规配置中填写桶名称。

搜索s3

image.png

这里要注意,因为我们这里的要求是用s3存储内容,通过CloudFront分发,所以我们的s3桶应该只对CloudFront开放访问,所以公共访问权限应该 阻止所有公开访问。存储桶版本控制看你的需求,如果你希望你的资源能自动备份,能回溯,那就开启。我这里就默认禁用了。

image.png

然后创建即可

image.png

上传图片到S3桶中

略,这个太简单了,进去桶里上传文件就行了。

创建CloudFront

搜索CloudFront进入CloudFront控制台创建CloudFront

image.png

在源设置这里,Origin domain选择上面创建的S3桶,Origin path的意思是你希望CloudFront的源为S3中的哪个文件夹,比如Origin Path 为 /images,这样 CloudFront 将仅缓存和提供存储桶中 images 文件夹下的内容,我这里希望CloudFront 指向整个S3,所以我这里不填。

来源访问不要设置公开,如果选择公开,这里给S3分配CloudFront 就没什么意义了。选择第二个或者第三个都可以,两者的区别在于CloudFront对S3的访问方式,有兴趣的可以自己去了解。我这里选择了第三个,没有OAI就创建一个。你也可以选择AWS推荐的第二个选项--来源访问控制设置,但这样,需要你在CloudFront创建后手动修改S3桶的存储桶策略(放心,不需要你去写,这个存储桶策略会在你创建完CloudFront后在顶部给你提示出来,你只需要复制粘贴到对应的S3桶的存储桶策略);

image.png

而选择第三个--Legacy access identities,AWS会自动给你选择的S3桶配置存储桶策略。(所以我这里图方便,我选择了第三个选项,但第二个选项我也创建过,然后手动配置策略,我推荐你也试试)

Enable Origin Shield直接默认否。

image.png

image.png

默认缓存行为和函数关联 不动,默认即可。或者你按需设置

image.png

image.png

我觉得WAF保护作用不大,我这选择关闭

image.png

这部分根据需求自定义,比如你希望这个CloudFront能绑定你自己的域名,能通过你自己的域名来访问,那么你就得在备用域名那增加上你的域名,然后上传或者创建你的域名证书,并且把你的域名CNAME解析到AWS给你分配的主域名;比如你觉得你的CloudFront并不需要给IPv6提供服务,那么就像我这样关闭IPv6的解析服务。当然,你这部分直接默认也可以。

image.png

然后完成创建即可

访问测试

等CloudFront部署完成(上次修改时间那显示时间就是部署完成了,显示 部署 就是在部署中),即可进行访问测试。图示有两个CloudFront,是因为上面两种不同的来源访问 我都创建了一个,并且都分配给了同一个S3桶,你上面创建有一个CloudFront就行了。

复制分配的CloudFront域名

image.png

在域名后加上S3桶中的文件路径即可完成访问,比如我的图片存在S3根目录下,文件名为background.jpg。

image.png

然后,你可以尝试在S3桶中复制对象的URL在浏览器打开,访问失败,那么我们就成功完成了AWS中的相关配置。接下来就是修改代码,重新打包程序发布了。

image.png

image.png

修改Web程序代码,重新打包上传EC2

因为距离最终的检查还有一段时间,这个CloudFront不一定就是我最终检查使用的那一个,所以我接下来打算把这个CloudFront的host放到配置文件application.yml文件中,实现动态配置。(实际上,如果只是背景图其实是可以直接在html中写死url的,但如果你的项目中使用了很多图片等静态资源,那么我还是建议把url中host部分抽离到配置文件中)

image.png

application.yml文件中新增custom.s3CloudFrontHost字段

image.png

在中加入css内联样式。通过${@environment.getProperty('custom.s3CloudFrontHost')}读取我们刚刚在上面application.yml文件中新增的custom.s3CloudFrontHost属性。(爆红也别怕,我这里使用的thymeleaf,idea的语法检查当纯html检查了)

image.png

image.png

然后再修修样式,加个卡片,防止背景和文字混在一起看不清。

image.png

完美,程序成功运行。重新打包上传EC2就不演示了,可以看架构一笔记中的操作。

创建新Web应用的AMI

很简单,如图所示

image.png

修改启动模板

EC2控制台,进入启动模板页,选择之前创建的启动模板,操作->修改模板

image.png

只需在要这里的AMI设置选择上面新建的AMI就行,其他配置不变。

image.png

访问负载均衡器,难搞喔,显示的内容怎么还是原来的版本,怎么没有自动更新?是缓存?还在构建新实例?

image.png

修改Auto Scaling 组

答案是,前面我们在创建Auto Scaling 组的时候选择启动模板,选择的版本是Default,Default版本,如果你不去改变它,那么就默认为1版本,而我们上面对启动模板进行了修改,修改后的版本为2,所以Auto Scaling 组还在使用着原来版本的AMI。

image.png

那么接下来就是要让Auto Scaling 组能启动到我们刚刚新建的AMI,那么有2种办法。两种办法的依据是不一样,看你这个Auto Scaling 组的定位来决定。

第一种方案

比如我现在这个Auto Scaling 组,已经确定了是生产环境下的了,那么我们可以对启动模板版本的Default进行修改,把Default设置成需要的版本,比如这里我需要它设置为2,

image.png

image.png

第二种方案

还有一种情况,就是我这个Auto Scaling 组是在开放环境下运行,我希望实例都是用的最新版本启动模板,那么我们就对Auto Scaling 组中启动模板的配置进行修改,把启动模板版本的配置改成Latest,那么Auto Scaling 组以后就会使用最新版本的启动模板来启动实例。

image.png

image.png

启动实例刷新

一般情况下,无论是修改启动版本的版本还是修改Auto Scaling 组绑定的启动模板版本,Auto Scaling 组都无法立刻对正在运行的实例进行更新,这个更新只会影响到以后的实例,而不会应用到已在运行的实例。所以如果就需要以下操作,来启动实例刷新

进入相关的Auto Scaling 组详情页,启动实例刷新

image.png

替换方案按照提示,根据你的需求来,我这里选择了第一个。

image.png

关掉跳过匹配,因为我们需要他根据新版本启动模板来启动新实例,所以不能跳过匹配。

image.png

所需的配置部分默认即可,因为我们已经对启动模板的默认版本进行了修改。

image.png

然后启动,Auto Scaling 组就会自动完成实例的更新。

image.png

再次访问负载均衡器的URL,成功访问最新版本的Web应用,并且背景图为CloudFront分发的S3桶对象。

image.png

2.使用堡垒机登录实例

模拟需求:在架构二中,我们使用Auto Scaling 组在私有子网中创建了若干个EC2实例,由于这些实例都是在私有子网上运行,那么我们就无法通过互联网连接到这些EC2实例上,那么这就需要堡垒机来做跳板(所以堡垒机又称跳板机),我们可以通过这个部署在公有子网的堡垒机连接私有子网的实例。

操作步骤:创建与修改安全组->创建堡垒机实例->创建实例连接

创建与修改安全组

在安全组标签页新建安全组

image.png

VPC选择我们创建的那个

image.png

增加一个入站规则,端口为22,源看情况。比如你的设备ip是固定的ip段,那么你就可以设置为固定的ip段,而我不确定我的网络情况,所以我这里设置了0.0.0.0,全开放。

出站规则的目标,我们这里是可以确定的,因为我这里的堡垒机作用就是连接Auto Scaling 组在私有子网中创建的那若干个EC2实例,那么这个目标就可以设置成这些实例绑定的安全组。

image.png

创建了堡垒机的安全组,那么还需要修改Auto Scaling 组创建的那若干个EC2实例绑定的安全组,使其对堡垒机开放。新增一个入站规则,端口为22,源设置为上面创建的堡垒机安全组

image.png

image.png

创建堡垒机实例

名称随意,AMI默认的Amazon Linux 2023就行

image.png

实例类型默认即可,或者选择最便宜的就行,因为我们只需要这个实例做跳板。密钥对默认,懒得下载配置。

image.png

VPC选择我们创建的,子网一定要选择公有子网,两个公有子网都无所谓;分配公有ip;安全组选择上面我们新建的堡垒机安全组。

image.png

登录私有实例

我这里以FinalShell为例,其他ssh也行,原理一样,触类旁通。

创建堡垒机隧道

复制堡垒机的公有IP地址

image.png

FinalShell里新建一个shh连接,先把常规内容填好,别点确定。

image.png

回到浏览器,选择Auto Scaling 组创建的实例,复制私有的IP地址

image.png

点击 隧道 新增一个隧道,名称随意;类型:本地;

监听端口:填你电脑未被占用的端口;

绑定ip:默认的127.0.0.1就行;

目标地址:上面复制的私有ip地址;目标端口:22。

然后确定新建隧道,确定新建连接。

image.png

创建私有实例连接

新建一个ssh连接,主机那里的ip部分填127.0.0.1;端口填上面堡垒机上的隧道中设置的端口;其他照常即可。

image.png

测试堡垒机连接

先连接我们的堡垒机,看登录信息,显示登录ip为电脑ip地址。

image.png

再连接私有EC2实例,可以看到登录的ip为局域网ip,一致堡垒机的私有ip一致。这就完成了堡垒机登录私有子网中实例的操作,同理,你也可以登录到私有子网中另一个实例,只需要对堡垒机的连接进行编辑,新增对应的隧道即可。

image.png

image.png

3.通过CloudFormation模板构建VPC

写CloudFormation模板

想使用CloudFormation模板来完成创建VPC这个操作,得先弄清楚CloudFormation模板的基本结构。那么不妨看一下官方文档的介绍。

使用 AWS CloudFormation 模板 - AWS CloudFormation (amazon.com)

image.png

我个人来说,更推荐使用YAML格式,更简洁。主要要了解的是这个 模板部分 ,这样你才能看得懂这yaml中到底在描述着什么。(这些蓝色标题是这个yaml的组成部分,在yaml中是英文的,别傻乎乎在yaml写什么“元数据”、“条件”,这AWS估计用的机翻,都给翻译过来了)

image.png

下面是我根据实验需求写的关于VPC的CloudFormation模板。如果你需要完成下面创建堆栈的操作,那么你需要在你电脑插件一个xxx.yaml文件,然后把我下面的这个CloudFormation模板复制进去。

# 描述
Description: "Create a VPC with two public and two private subnets, as well as corresponding routing tables and NAT gateways."

# 参数变量部分,创建堆栈时,可进行填写
Parameters:
  VpcCIDR:
    Type: String
    Default: "10.0.0.0/16"
    Description: "Please enter the CIDR for this VPC"

  PublicSubnet1CIDR:
    Description: "Please enter the CIDR for the public subnet"
    Type: String
    Default: "10.0.0.0/24"

  PublicSubnet2CIDR:
    Description: "Please enter the CIDR for the public subnet"
    Type: String
    Default: "10.0.2.0/24"

  PrivateSubnet1CIDR:
    Description: "Please enter the CIDR for the private subnet"
    Type: String
    Default: "10.0.1.0/24"

  PrivateSubnet2CIDR:
    Description: "Please enter the CIDR for the private subnet"
    Type: String
    Default: "10.0.3.0/24"

# 资源部分
Resources:
  # VPC
  MyVPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VpcCIDR
      EnableDnsSupport: true
      EnableDnsHostnames: true

  # 互联网网关
  InternetGateway:
    Type: AWS::EC2::InternetGateway

  # 网关关联
  VPCGatewayAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref MyVPC
      InternetGatewayId: !Ref InternetGateway

  # 公有子网1
  PublicSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref MyVPC
      # 可用区选择
      AvailabilityZone: !Select [ 0, !GetAZs '' ]
      CidrBlock: !Ref PublicSubnet1CIDR

  # 公有子网2
  PublicSubnet2:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref MyVPC
      AvailabilityZone: !Select [ 1, !GetAZs '' ]
      CidrBlock: !Ref PublicSubnet2CIDR

  # 私有子网1
  PrivateSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref MyVPC
      AvailabilityZone: !Select [ 0, !GetAZs '' ]
      CidrBlock: !Ref PrivateSubnet1CIDR

  # 私有子网2
  PrivateSubnet2:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref MyVPC
      AvailabilityZone: !Select [ 1, !GetAZs '' ]
      CidrBlock: !Ref PrivateSubnet2CIDR

  # 弹性IP
  NatGatewayEIP:
    Type: AWS::EC2::EIP
    DependsOn: VPCGatewayAttachment
    Properties:
      Domain: vpc

  # NAT网关
  NATGateway:
    Type: AWS::EC2::NatGateway
    Properties:
      # 给NAT网关授权上面这个弹性IP
      AllocationId: !GetAtt NatGatewayEIP.AllocationId
      SubnetId: !Ref PrivateSubnet1
  
  # 公有路由表
  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref MyVPC

  # 私有路由表
  PrivateRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref MyVPC

  # 给公有路由表关联互联网网关
  DefaultPublicRoute:
    Type: AWS::EC2::Route
    DependsOn: VPCGatewayAttachment
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: "0.0.0.0/0"
      GatewayId: !Ref InternetGateway

  # 公有路由表关联公有子网1
  PublicSubnet1RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnet1
      RouteTableId: !Ref PublicRouteTable

  # 公有路由表关联公有子网2
  PublicSubnet2RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnet2
      RouteTableId: !Ref PublicRouteTable

  # 给私有路由表关联NAT网关
  DefaultPrivateRoute:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PrivateRouteTable
      DestinationCidrBlock: "0.0.0.0/0"
      NatGatewayId: !Ref NATGateway

  # 私有路由表关联私有子网1
  PrivateSubnet1RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateSubnet1
      RouteTableId: !Ref PrivateRouteTable

  # 私有路由表关联私有子网2
  PrivateSubnet2RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateSubnet2
      RouteTableId: !Ref PrivateRouteTable

创建堆栈

进入CloudFormation操作台,这里已经有一个堆栈了,别动它,这个是账号实验环境初始化的堆栈,你第一次启动实验为什么慢,就是因为在运行这个堆栈。不管这个堆栈,我们新建一个堆栈。

image.png

选择上传模板文件,把上面保存的ymal文件上传上去

image.png

这里其实已经不用怎么改了,因为其实在ymal中,我就已经预设好了。

image.png

选一下IAM角色,把我们的LabRole加进去,相当于给这个堆栈授权。这个操作相当于在linux中授权root用户,所以这个操作实际上是不安全的,但我们自己写的CloudFormation模板,我们知道这些操作基本不会造成什么不可逆的影响(实际上是我懒得去新建角色)。其他配置默认,然后下一步提交即可。

image.png

然后点开这个新建的堆栈,打开资源页,即可看到堆栈在创建我们yaml中定义的资源。

image.png

进入VPC页面,查看创建的VPC资源地图,创建成功,后续就可以在这个VPC上完成相关操作了。

image.png

image.png

4.基于CloudWatch指标做AutoScaling组

我们在架构二中创建AutoScaling组时就已经完成这个操作了,具体你也可以进入EC2页面中AutoScaling组标签页看里面配置的动态扩展策略,图中这个策略就是根据CloudWatch指标做的动态扩展策略,这个策略表示:Amazon EC2 Auto Scaling 会根据需要启动和终止 EC2 实例,以将组中所有实例的累计 CPU 使用率保持在 80%。当然你也可以新建更多的策略来规划AutoScaling组的弹性伸缩。

image.png

5.Amazon ElastiCache for Redis、DynamoDB、SQS

关于这三者,我上面也说了,我的实验应用用不到,所以就不进行操作了。

Amazon ElastiCache for Redis是我比较推荐在这个实验中使用的,因为这个简单!因为Redis是一个开源的软件,它有一套公共认可的统一的开发规范,而且Spring Boot就集成了Redis的控制类,直接就能通过maven导入到项目中,然后像使用MySQL数据库一样,在配置文件设置相关参数即可。如果你想在你的项目中使用,只需要在Amazon ElastiCache中创建一个Redis实例,然后把程序中配置文件的参数修改成这个实例的参数,和迁移MySQL数据库的操作基本一致。

剩下的DynamoDB与SQS,如果你想在你的项目中集成就会有一点点难,因为这两个服务在AWS是无服务器类的资源,你想集成到你的程序中,你得在你的项目中使用AWS官方提供的SDK,你需要使用AWS提供的规范,就比较难受了,因为这样就需要你通过对文档和DEMO进行研究。下面是我找到的一些文档与DEMO,如果你有兴趣,也可以研究一下。

AWS SDK 代码示例 (amazon.com)

aws-doc-sdk-examples/javav2 at main · awsdocs/aws-doc-sdk-examples (github.com)

最后修改:2024 年 05 月 09 日
如果觉得我的文章对你有用,请随意赞赏