使用 Amazon Migration Hub Refactor Spaces 和 Amazon Copilot 将单体应用程序分解为多个微服务

亚马逊云科技帮助您分解单体应用,让您更专注于创新。
发布时间:2023 年 11 月 16 日
部署 Refactor Spaces
Amazon-Copilot
重构单体应用
教程
亚马逊云科技
Olawale Olaleye
亚马逊云科技使用经验
200 - 中级
完成所需时间
140 分钟
前提条件

如果您还没有账户,请先注册 / 登录 亚马逊云科技账户。

  • 安装和配置 Amazon CLI。
  • 安装和配置 Amazon Copilot。
  • 安装和配置 Docker。
  • 文本编辑器。在此试验中,我们将使用 VS Code。您也可以使用自己喜欢的 IDE。
示例代码
  • GitHub 上的应用程序示例代码
  • Amazon Samples 中适用于重构服务的 Amazon CloudFormation 脚本
上次更新时间
2023 年 11 月 16 日

简介

传统的单体应用架构很难扩展。因为随着应用程序代码库的内容越来越丰富,更新和维护变得越来越复杂。引入新的功能、语言、框架和技术变得越来越难以管理,进而限制了创新和新思路。您可以使用 Amazon Migration Hub Refactor Spaces 预配重构环境,自动化配置所需的亚马逊云科技基础设施。有多种方法可以将单体应用程序分解为微服务。您可以使用 strangler fig 模式、leave and layer 模式,或使用 multi-account strategy 进行重构。使用这些方法,可以减少应用重构给应用使用者带来的风险,从而提高应用程序的效率。

在微服务架构中,每个应用程序组件都运行着各自的服务,并通过 API 与其他服务进行通信。微服务是围绕业务功能构建的,每个服务执行单一功能。程序员可以使用不同的框架和编程语言编写微服务。然后,将这些微服务独立部署为单个服务或一组服务。

本教程将逐步介绍如何使用 Refactor Spaces 和 Amazon Copilot 并通过 strangler fig 模式 将单体应用分解为微服务。这些亚马逊云科技服务将帮您完成很多重复的繁重工作,让您专注于更重要的事情:创新。

目标

首先将单体 Node.js 应用程序部署到 Docker 容器,然后将该应用程序分解为多个微服务。使用 Refactor Spaces 预配重构微服务的环境。您的应用使用者不会感知到 Refactor Spaces 分解应用程序时的基础设施变更。在本例中,我们使用一个托管留言板的 Node.js 应用程序。该留言板中包含用户之间的线程和消息。应用部署完成后,您可以参考本教程,在亚马逊云科技上构建和部署容器化微服务。

前提条件

  • 亚马逊云科技账户。如果您还没有账户,请先参见设置亚马逊云科技环境注册一个账户。

  • 安装和配置 Amazon CLI。

  • 安装和配置 Amazon Copilot。

  • 安装和配置 Docker。

  • 文本编辑器。在本教程中,我们将使用 VS Code,但是您可以使用自己喜欢的 IDE。

  • 确认有足够的资源配额满足应用服务所需。例如,本试验中需要使用 5 个 VPC,每个地域的默认配额为 5 个 VPC。

模块

本此试验分为以下几个模块。您需要完成每个模块,上一个模块完成后才能继续下一个模块。

  1. 设置开发环境(20 分钟):安装和配置 Amazon CLI、Amazon Copilot 和 Docker。

  2. 容器化和部署单体应用(30 分钟):将应用程序容器化。使用 Amazon Copilot 将 Amazon ECS 计算实例上的 Fargate 托管集群实例化。此外,使用镜像部署运行在集群上的容器。

  3. 部署重构环境(20 分钟):部署 Refactor Spaces 环境。这一步设置重构应用程序的基础设施。然后,在 Refactor Spaces 中将上一步部署的单体应用注册为默认路由。

  4. 分解单体应用(20 分钟):将 Node.js 应用程序分解为多个互连的微服务。然后,将每个服务的镜像推送到 Amazon Elastic Container Registry (Amazon ECR) 存储库。

  5. 部署微服务(30 分钟):分解 Node.js 应用程序,并将其部署为基于应用程序负载均衡器的一组互连的微服务。然后,使用 Refactor Spaces 将流量从单体应用路由到微服务。

  6. 清理资源(10 分钟):终止所有试验过程中创建的资源。停止在 Amazon ECS 上运行的服务、删除应用程序负载均衡器并删除 Amazon CloudFormation 堆栈,终止所有底层资源。

模块 1:设置开发环境

概述

在本模块中,您将使用亚马逊云科技命令行安装配置环境所需的工具。

模块详情

时长:20 分钟

操作步骤

本示例中,需要为单体 Node.js 应用程序构建 Docker 容器镜像,并将其推送到 Amazon Elastic Container Registry (Amazon ECR)。

步骤 1:安装软件

在接下来的几个步骤中,您需要使用 Docker、GitHub、Amazon ECS 和 Amazon ECR 将代码部署到容器中。要完成这些步骤,您需要以下工具。

  1. 亚马逊云科技账户。如果您没有亚马逊云科技账户,请先注册一个账户。本试验中的所有部署都可使用 亚马逊云科技免费套餐配额完成。注意:某些服务可能在您的账户激活 12 小时之后才可使用。如果您使用的是新建账户,若预配服务资源失败,请等待几个小时后再重试。

  2. Docker:使用 Docker 构建运行容器的镜像文件。Docker 是一个开源项目。请根据您的操作系统,下载适用于 macOS 或 Windows 的 Docker。安装 Docker 后,在终端上运行 Docker --version 命令,确认 Docker 运行正常。该命令执行成功后,会返回版本号,例如:Docker version 19.03.5, build 633a0ea.

  3. Amazon CLI:

    • 使用亚马逊云科技命令行工具 (Amazon CLI) 将镜像推送到 Amazon ECR。了解如何下载和配置 Amazon CLI,请参阅 Amazon CLI 入门
    • 安装 Amazon CLI 后,执行 aws --version 命令,确认 Amazon CLI 运行正常。该命令执行成功后,会返回版本号,例如:aws-cli/1.16.217 Python/2.7.16 Darwin/18.7.0 botocore/1.12.207。
    • 如果您已经安装了 Amazon CLI,请运行以下命令,确认使用的是最新版本:pip install awscli --upgrade --user。
    • 如果您以前从未使用过 Amazon CLI,需要先配置您的凭证
  4. Amazon Copilot:Amazon Copilot 是一个开源命令行工具,可用于构建、发布和管理容器化的应用程序。您可以将应用部署在 Amazon App Runner、Amazon ECS 和 Amazon Fargate 上。如果您使用的是 macOS 系统,可以运行以下 brew 命令安装 Amazon Copilot。

brew install aws/tap/copilot-cli

如果使用其他系统,可以使用 curl 或 PowerShell 下载 Amazon Copilot。

  • macOS
  • curl -Lo copilot https://github.com/aws/copilot-cli/releases/latest/download/copilot-darwin &&chmod +x copilot && sudo mv copilot /usr/local/bin/copilot && copilot --help
  • Linux x86 (64 位)
  • curl -Lo copilot https://github.com/aws/copilot-cli/releases/latest/download/copilot-linux && chmod +x copilot && sudo mv copilot /usr/local/bin/copilot && copilot --help
  • Linux (ARM)
  • curl -Lo copilot https://github.com/aws/copilot-cli/releases/latest/download/copilot-linux-arm64 && chmod +x copilot && sudo mv copilot /usr/local/bin/copilot
  • Windows
  • Invoke-WebRequest -OutFile  'C:\\Program Files\\copilot.exe' https://github.com/aws/copilot-cli/releases/latest/download/copilot-windows.exe

步骤 2:下载和打开项目

从 GitHub 下载代码:前往 Amazon Labs,然后选择 Clone 或 Download,将存储库从 GitHub 下载到本地环境。您也可以使用 GitHub Desktop 或 Git 克隆存储库。

模块 2:容器化和部署单体应用

概述

容器是包含应用程序代码、配置和依赖项的轻量级包。使用容器可实现环境一致性、提高运营效率、提升开发人员工作效率和实现版本控制。无论在什么部署环境中,使用容器都可以帮助您快速、可靠和一致地部署应用程序。

为什么使用容器?

启动包含新版本代码的容器时,无需大量的部署开销。可将开发人员本地计算机上容器中的代码通过容器迁移至测试实例,并且无需重新编译。这种方式提高了运维开发速度。在构建时,可以将此容器连接到运行应用程序堆栈的其他容器。

控制依赖项和改进管道

Docker 容器镜像是基于捕获的某个时间点的应用程序代码和依赖项创建的。Docker 容器镜像可用于为应用程序生命周期创建标准管道。例如:

  • 开发人员在本地构建和运行容器。
  • 持续集成服务器运行相同的容器并运行集成测试,以确保其通过测试。
  • 在预发布环境部署相同的容器,然后可以在该环境中通过负载测试或手动 QA 检查容器运行时行为。
  • 在生产环境部署相同的容器。

在集成和部署管道的所有阶段构建、测试、移动和运行完全相同的容器可以提高质量和可靠性。

提高密度和资源效率

容器支持在单个系统上运行多个异构进程,从而提高了资源效率。容器所采用的隔离和分配技术可以提升资源效率。还可以限制容器消耗的主机 CPU 和内存容量。了解容器所需的资源以及底层主机服务器可以提供的资源,有助于优化实例大小。您可以通过使用更小的主机、增加单个主机上运行的进程密度或优化资源消耗和可用性来实现优化。

提高灵活性

Docker 容器具有可移植性、易于部署和体积小的特点,因此具有一定的灵活性。这与虚拟机上所需的安装和配置不同。例如,将服务打包在容器中便于在主机之间迁移服务。这可以将服务与相邻的故障服务隔离开,并保护服务免受主机系统的错误补丁或软件升级的影响。

应用程序概览

  1. 客户端:客户端通过端口 443 向重构代理 URL 发出请求。

  2. Elastic Load Balancer (ELB):Amazon Copilot 创建 ELB,并将单体应用注册到目标组。

  3. 容器化的 Node.js 单体应用:Node.js 集群的父级负责将流量分配给单体应用程序中的工作节点。此架构已容器化,但仍为单体,因为每个容器都具有与其他容器相同的所有功能。

什么是 Amazon ECS?

Amazon Elastic Container Service (Amazon ECS) 是一个全托管容器编排服务。使用 Amazon ECS,可以简化容器化应用程序的部署、管理和扩展。Amazon ECS 可与应用程序所需的其他亚马逊云科技服务自动集成,从而能够通过各种计算服务方案灵活地启动、监控和扩展您的应用程序。Amazon ECS 支持 Docker 容器。您可以调用 API 来启动和停止基于 Docker 的应用程序,查询集群的完整状态和使用功能,包括安全组、弹性负载均衡、EBS 卷以及 Amazon Identity and Access Management (IAM) 角色。

您可以根据您的资源需求和可用性要求,使用 Amazon ECS 调度容器在集群中的位置。另外,还可以集成自己的调度器或第三方调度器,以满足特定业务或应用程序的要求。

Amazon ECS 不收取额外费用。您只需为存储和运行应用程序而创建的亚马逊云科技资源(例如,EC2 实例或 EBS 卷)付费。

目标

使用 Amazon ECS 实例化 EC2 计算实例的托管集群。然后,将镜像部署为运行在集群上的容器。

模块详情

时长:30 分钟

所需服务

操作步骤

执行以下步骤,通过 Amazon Copilot 部署 Node.js 应用程序。

步骤 1:创建 Amazon Copilot 应用程序

Amazon Copilot 应用程序是一组服务和环境。可以将其视为所构建内容的标签。在本例中,它是一个构建为单体 Node.js 应用程序的 API。这一步,您将创建一个空应用程序。在终端或命令提示符中,运行以下命令并将应用程序命名为 api。

cd ./amazon-ecs-nodejs-microservices/
copilot app init

Amazon Copilot 应用程序将创建一个空应用程序,其中包含用于管理 StackSets、Amazon ECR 存储库、KMS 密钥和 S3 存储桶的角色。此外,还将在存储库中创建一个本地目录,用于保存应用程序和服务的配置文件。完成后,输出应如下所示:

Application name: monolith
✔ Proposing infrastructure changes for stack monolith-infrastructure-roles
- Creating the infrastructure for stack monolith-infrastructure-roles [create complete] [46.2s]
 - A StackSet admin role assumed by CloudFormation to manage regional stacks [create complete] [18.9s]
 - An IAM role assumed by the admin role to create ECR repositories, KMS keys, and S3 buckets [create complete] [20.5s]
✔ The directory copilot will hold service manifests for application monolith.

步骤 2:创建环境

Copilot 环境是运行应用程序的基础设施。Amazon Copilot 会预配安全 VPC、Amazon ECS 集群、负载均衡器以及应用程序所需的所有其他资源。输入 copilot env init 并选择 profile default 使用您的亚马逊云科技凭证。将环境命名为 monolith。

$ copilot env init
Environment name: monolith

Which credentials would you like **to** use **to** create api?  [Use
arrows **to** move, type **to** filter, ? **for** more help]
   Enter temporary credentials
  > [profile default]

选择 Yes, use default。

Environment name: monolith
Credential source: [profile default]

 Would you like to use the default configuration for a new environment?
 - A new VPC with 2 AZs, 2 public subnets and 2 private subnets 
 - A new ECS Cluster
 - New IAM Roles to manage services and jobs in your environment
 [Use arrows to move, type to filter]
 > Yes, use default.
 Yes, but I'd like configure the default resources (CIDR ranges, AZs).
 No, I'd like to import existing resources (VPC, subnets).

现在将开始创建所需的基础设施。Amazon Copilot 将创建一个 manifest.yml,用于配置环境。创建完成后,输出应如下所示:

Environment name: monolith
Credential source: [profile default]
Default environment configuration? Yes, use default.
✔ Wrote the manifest for environment api at copilot/environments/api/manifest.yml
- Update regional resources with stack set "api-infrastructure" [succeeded] [0.0s]
- Update regional resources with stack set "api-infrastructure" [succeeded] [130.8s]
 - Update resources in region "us-east-1" [create complete] [130.4s]
 - ECR container image repository for "monolith" [create complete] [2.5s]
 - KMS key to encrypt pipeline artifacts between stages [create complete] [124.5s]
 - S3 Bucket to store local artifacts [create complete] [2.4s]
✔ Proposing infrastructure changes for the api-api environment.
- Creating the infrastructure for the api-api environment. [create complete] [56.0s]
 - An IAM Role for AWS CloudFormation to manage resources [create complete] [22.4s]
 - An IAM Role to describe resources in your environment [create complete] [25.0s]
✔ Provisioned bootstrap resources for environment api in region us-east-1 under application api.

步骤 3:部署环境

部署环境并为应用程序预配服务。在终端上,运行 copilot env deploy --name monolith 部署环境。

$ copilot env deploy --name monolith

✔ Proposing infrastructure changes for the api-api environment.
- Creating the infrastructure for the api-api environment. [update complete] [78.3s]
 - An ECS cluster to group your services [create complete] [7.5s]
 - A security group to allow your containers to talk to each other [create complete] [1.4s]
 - An Internet Gateway to connect to the public internet [create complete] [16.0s]
 - Private subnet 1 for resources with no internet access [create complete] [1.7s]
 - Private subnet 2 for resources with no internet access [create complete] [1.7s]
 - A custom route table that directs network traffic for the public subnets [create complete] [10.9s]
 - Public subnet 1 for resources that can access the internet [create complete] [3.1s]
 - Public subnet 2 for resources that can access the internet [create complete] [6.0s]
 - A private DNS namespace for discovering services within the environment [create complete] [46.3s]
 - A Virtual Private Cloud to control networking of your AWS resources [create complete] [11.6s]

步骤 4:创建单体 Amazon Copilot 服务

Copilot 服务用于运行容器。面向互联网的服务可以是使用 Amazon App Runner 的请求驱动式 Web 服务。这些服务可以在 Amazon ECS 或 Fargate 上运行,并使用基于负载均衡的 Web 服务预配应用程序或网络负载均衡器,并配置安全组。

其他类型的服务包括后端服务。后端服务允许应用程序使用的亚马逊云科技服务相互通信,但不能与互联网通信。工作节点服务用于通过 Amazon Simple Queue Service (Amazon SQS) 进行异步的服务到服务消息传递。

本此试验中,使用基于负载均衡的 Web 服务实现面向互联网的单体服务。创建单体服务的方法:运行 copilot svc init 并选择 Load Balanced Web Service 。

$ copilot svc init

Note: It's recommended to run this command in the root of your Git repository.
Welcome to the Copilot CLI! We're going to walk you through some questions
to help you get set up with a containerized application on AWS. An application is a collection of
containerized services that operate together.


 Which workload type represents your architecture? [Use arrows to move, type to filter, ? for more help]
 Request-Driven Web Service (App Runner)
 > Load Balanced Web Service (Internet to ECS on Fargate)
 Backend Service (ECS on Fargate)
 Worker Service (Events to SQS to ECS on Fargate)
 Scheduled Job (Scheduled event to State Machine to Fargate)

将服务命名为 monolith。

Workload type: Load Balanced Web Service

What do you want to name this service? [? for help] monolith

Choose Enter custom path for your Dockerfile.

Workload type: Load Balanced Web Service
Service name: monolith

 Which Dockerfile would you like to use for monolith? [Use arrows to move, type to filter, ? for more help]
 > Enter custom path for your Dockerfile

输入 Dockerfile 文件路径: 2-containerized/services/api/Dockerfile

Service type: Load Balanced Web Service
Service name: monolith
Dockerfile: Enter custom path for your Dockerfile
Dockerfile: 2-containerized/services/api/Dockerfile

✔ Wrote the manifest for service monolith at copilot/monolith/manifest.yml

将路径更改为 ./amazon-ecs-nodejs-microservices/copilot/monolith,然后查看 manifest.yml 了解服务的配置方式。请注意,参数 http 指定应用的路径。Node.js 应用程序 server.js 将基本路由定义为 /。

The manifest for the "monolith" service.
Read the full specification for the "Load Balanced Web Service" type at:
 https://aws.github.io/copilot-cli/docs/manifest/lb-web-service/
Your service name will be used in naming your resources like log groups, ECS services, etc.
name: monolith
type: Load Balanced Web Service

Distribute traffic to your service.
http:
 # Requests to this path will be forwarded to your service.
 # To match all requests you can use the "/" path.
 path: '/'
 # You can specify a custom health check path. The default is "/".
 # healthcheck: '/'

部署单体服务的方法:在终端上运行 copilot svc deploy --name monolith。部署服务时,Docker 会在本地构建容器,并将其推送到您的 Elastic Container Registry 注册表中。该服务将从注册表中拉取容器并将其部署到环境中。部署完成后,monolith 应用程序将处于运行状态。

$ copilot svc deploy --name monolith
Only found one service, defaulting to: monolith
Only found one environment, defaulting to: monolith
Building your container image: docker build -t 837028011264.dkr.ecr.us-east-1.amazonaws.com/api/monolith --platform linux/x86_64 /Users/sparaaws/github/spara/amazon-ecs-nodejs-microservices/2-containerized/services/api -f /Users/sparaaws/github/spara/amazon-ecs-nodejs-microservices/2-containerized/services/api/Dockerfile
[+] Building 43.3s (10/10) FINISHED
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 36B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/mhart/alpine-node:7.10.1 5.6s
=> [auth] mhart/alpine-node:pull token for registry-1.docker.io 0.0s
=> [internal] load build context 0.0s
=> => transferring context: 392B 0.0s
=> [1/4] FROM docker.io/mhart/alpine-node:7.10.1@sha256:d334920c966d440676ce9d1e6162ab544349e4a4359c517300391c877bcffb8c 0.0s
=> => resolve docker.io/mhart/alpine-node:7.10.1@sha256:d334920c966d440676ce9d1e6162ab544349e4a4359c517300391c877bcffb8c 0.0s
=> CACHED [2/4] WORKDIR /srv 0.0s
=> [3/4] ADD . . 0.0s

步骤 5:确认部署

部署完成后,Amazon Copilot 在输出中显示服务的 URL。

✔ Proposing infrastructure changes for stack api-api-monolith
- Creating the infrastructure for stack api-api-monolith [create complete] [360.8s]
- Service discovery for your services to communicate within the VPC [create complete] [0.0s]
- Update your environment's shared resources [update complete] [149.9s]
- A security group for your load balancer allowing HTTP traffic [create complete] [5.9s]
- An Application Load Balancer to distribute public traffic to your services [create complete] [123.0s]
- A load balancer listener to route HTTP traffic [create in progress] [198.5s]
- An IAM role to update your environment stack [create complete] [23.5s]
- An IAM Role for the Fargate agent to make AWS API calls on your behalf [create complete] [19.9s]
- A HTTP listener rule for forwarding HTTP traffic [create complete] [3.5s]
- A custom resource assigning priority for HTTP listener rules [create complete] [5.1s]
- A CloudWatch log group to hold your service logs [create complete] [1.5s]
- An IAM Role to describe load balancer rules for assigning a priority [create complete] [23.5s]
- An ECS service to run and maintain your tasks in the environment cluster [create complete] [117.0s]
Deployments
Revision Rollout Desired Running Failed Pending
PRIMARY 1 [completed] 1 1 0 0
- A target group to connect the load balancer to your service [create complete] [15.0s]
- An ECS task definition to group your containers and run them on ECS [create complete] [0.0s]
- An IAM role to control permissions for the containers in your tasks [create complete] [23.5s]
✔ Deployed service monolith.
Recommended follow-up action:
- You can access your service at http://api-a-Publi-DU44D9VOSXLA-792918025.us-east-1.elb.amazonaws.com over the internet

您可以在浏览器中访问 URL,测试应用程序部署是否成功。例如:http://.us-east-1.elb.amazonaws.com/api/users/3

{"id":3,"username":"pb","name":"Bonnibel Bubblegum","bio":"Scientist, bearer of candy power, ruler of the candy kingdom"}

http://.us-east-1.elb.amazonaws.com/api/threads/2

{"id":2,"title":"Party at the candy kingdom tomorrow","createdBy":3}

http://.us-east-1.elb.amazonaws.com/api/posts/

[{"thread":1,"text":"Has anyone checked on the lich recently?","user":4},{"thread":1,"text":"I'll stop by and see how he's doing tomorrow!","user":2},{"thread":2,"text":"Come party with the candy people tomorrow!","user":3},{"thread":2,"text":"Mathematical!","user":2},{"thread":2,"text":"I'll bring my guitar","user":1},{"thread":3,"text":"I need a new guitar to play the most savory licks in Ooo","user":1}]

http://.us-east-1.elb.amazonaws.com/api/posts/in-thread/1

[{"thread":1,"text":"Has anyone checked on the lich recently?","user":4},{"thread":1,"text":"I'll stop by and see how he's doing tomorrow!","user":2}]

模块 3:部署重构环境

概述

Refactor Spaces 环境提供实现应用程序现代化所需的基础设施、多账户网络和路由。Refactor Spaces 环境包括一个应用程序代理,用于对 Strangler Fig 模式进行建模。这样可以在用户无感知的情况下,将新服务添加到外部 HTTPS 端点,并将流量路由到新服务。Refactor Spaces 还可以跨亚马逊云科技账户桥接网络,从而在旧服务和新服务之间建立通信,同时保持各个亚马逊云科技账户的独立性。

为什么使用 Refactor Spaces?

Migration Hub Refactor Spaces 可以简化应用程序重构。它具有以下优势:

  • 缩短了设置重构环境的时间。

  • 降低了以迭代方式将功能提取为新微服务并重新路由流量的复杂性。

  • 将现有应用和微服务视为单个应用,简化了管理工作,同时提供灵活的路由控制、隔离和集中管理功能。

  • 随着应用程序更新开发、管理和运营任务的简化,开发团队实现并加速技术和部署的独立性。

  • 简化使用多个亚马逊云科技账户的重构。若想了解更多详细信息,请参考以下参考架构

目标

使用 Amazon CloudFormation 部署 Refactor Spaces 环境和 Refactor Spaces 应用程序。

  1. 客户端:客户端通过端口 443 向重构代理 URL 发出请求。

  2. Amazon Migration Hub Refactor Spaces:Refactor Spaces 提供一个应用程序,用于对 Strangler Fig 模式进行建模以实现逐步重构。

  3. Elastic Load Balancer (ELB):Amazon Copilot 创建 ELB,并将单体应用注册到目标组。

  4. 容器化的 Node.js 单体应用:Node.js 集群的父级负责将流量分配给单体应用程序中的工作节点。此架构已容器化,但仍为单体,因为每个容器都具有与其他容器相同的所有功能。

模块详情

时长:30 分钟

所需服务

操作步骤

步骤 1:下载模板

前往 Amazon Samples,然后选择 Clone 或 Download,将存储库从 GitHub 下载到本地环境。将 rs.yaml 和 rs-service-op.yaml 文件复制到在模块 1 中下载的存储库中。您也可以运行 curl/Invoke-WebRequest 执行此操作,而无需克隆整个存储库:

  • macOS/Linux
  • curl -O https://raw.githubusercontent.com/aws-samples/aws-migration-hub-refactor-spaces-samples/main/rs-tutorial/rs-copilot-tutorial/rs-service-op.yaml
    curl -O https://raw.githubusercontent.com/aws-samples/aws-migration-hub-refactor-spaces-samples/main/rs-tutorial/rs-copilot-tutorial/rs.yaml
  • Windows
  • Invoke-WebRequest -Uri https://raw.githubusercontent.com/aws-samples/aws-migration-hub-refactor-spaces-samples/main/rs-tutorial/rs-copilot-tutorial/rs-service-op.yaml -OutFile rs-service-op.yaml
    Invoke-WebRequest -Uri https://raw.githubusercontent.com/aws-samples/aws-migration-hub-refactor-spaces-samples/main/rs-tutorial/rs-copilot-tutorial/rs.yaml -OutFile rs.yaml

步骤 2:部署 Refactor Spaces

部署 Amazon CloudFormation 模板,用于创建 Refactor Spaces 环境、应用程序,并将该单体应用注册为默认服务和默认路由。

  • 在该项目的根目录下运行以下命令,部署重构环境。请务必将 <<Stack Name>> 替换为您的堆栈名称,将 <<MonolithUrl>> 替换为上个模块中 Copilot CLI 输出的 URL,并附加 /api,因为该单体应用侦听 /api。例如, [http://api-m-Publi-5SPO2C-558916521.us-east-1.elb.amazonaws.com/api](http://api-m-Publi-5SPOLPJTUB2C-558916521.us-east-1.elb.amazonaws.com/api)
aws cloudformation deploy --template-file rs.yaml --stack-name <<Stack Name>> --parameter-override MonolithUrl=<<MonolithUrl>>

该进程需要一些时间才能完成。输出内容应类似以下内容(URL 不同):

o6rvhiz-1055935381.us-west-2.elb.amazonaws.com/api

Waiting for changeset to be created..
Waiting for stack create/update to complete

完成后,您将看到 Successfully created/updated stack - monolith-tutorial。

步骤 3:测试单体应用

在上一步中,您使用 CloudFormation 为重构环境创建了资源。现在,运行以下命令,查看部署的输出内容。

注意:将此内容保存到文本文件中,供以后使用。

命令:

aws cloudformation describe-stacks --stack-name <<Stack Name>> --query "Stacks[].Outputs"

响应:

[
 [
 {
 "OutputKey": "rsProxyURL",
 "OutputValue": "https://zx8lisag1a.execute-api.us-east-1.amazonaws.com/prod",
 "Description": "The API Gateway Proxy URL for the Refactor Spaces Application"
 },
 {
 "OutputKey": "VPCId",
 "OutputValue": "vpc-05d73902a4d92",
 "Description": "The ID of the VPC that this stack is deployed in"
 },
 {
 "OutputKey": "appId",
 "OutputValue": "env-xA8QIyk4|app-1b8Omyo2",
 "Description": "The ID of Refactor Spaces App"
 },
 {
 "OutputKey": "envId",
 "OutputValue": "env-xA8QIyk4",
 "Description": "The ID of Refactor Spaces Env"
 },
 {
 "OutputKey": "rsServiceId",
 "OutputValue": "svc-3yXgDEnW9",
 "Description": "The ID of Refactor Spaces Monolith"
 }
 ]
]

要查看 JSON 格式的输出内容,请复制 rsProxyURL 值,附加 /users、/threads 或 /posts,然后粘贴到 Web 浏览器中。以下屏幕截图是经过优化的 JSON 格式 的 Firefox 输出。

模块 4:分解单体应用

概述

最终的应用程序架构中包含 Refactor Spaces、Amazon ECS 和应用程序负载均衡器。

  1. 客户端:客户端通过端口 80 发出流量请求。

  2. 负载均衡器:应用程序负载均衡器将外部流量路由到对应的服务。应用程序负载均衡器检查客户端请求,并根据路由规则将请求定向到目标组的实例和端口。

  3. 目标组:每个服务都有一个目标组,用于跟踪运行该服务的每个容器的实例和端口。

  4. 微服务:Amazon ECS 将每个服务部署到 EC2 集群中的容器中。每个容器只处理一个功能。

为什么使用微服务?

崩溃隔离

生产环境中可能会发生严重的崩溃事件。如果使用微服务架构,崩溃事件在本质上是独立的,因此可以限制崩溃的影响。默认情况下,微服务架构是解耦的。这意味着,如果一个微服务发生崩溃,应用的其余部分可以继续正常运行。

安全隔离

在单体应用中,攻击冲击面限制在应用程序边界内。如果一个特性或功能被攻破,可以认为整个应用在某种程度上也暴露在攻击范围内。例如,如果漏洞包括远程代码执行,则可以认为,攻击者可能已经获得了对其他横向系统功能的访问权限。但是,如果使用微服务架构,可以将攻击面限制在微服务对应的一个特性或功能内。使用 Amazon ECS 将功能分解为微服务,并可以为每个服务提供 Amazon Identity and Access Management (IAM) 角色,从而有助于保护对亚马逊云科技资源的访问安全。

独立扩展

将功能分解为微服务后,每个微服务的基础设施数量和实例数量可以独立扩展。这有助于按功能衡量和优化总成本。如果需要扩展某个特定功能,其他功能不会受到影响。以电子商务为例,当客户在您网站中的浏览速率高于购买速率时,您可以单独扩展对应的微服务。可以将目录浏览或搜索的处理规模设置为高于结账的处理规模。

提升开发速度

在单体架构中,应用程序紧密耦合。添加新功能时,需要对应用程序中的其他功能进行完全回归和验证。而遵循松耦合最佳实践的微服务架构允许单独更改功能。只有当开发人员显式编写了两个微服务之间的连接时,一个功能代码更新才会影响另一个功能。微服务架构中的独立性降低了开发风险,并使您能更快地构建服务。

目标

将 Node.js 应用程序分解为多个互连的服务,并为每个微服务创建一个 Amazon Copilot 环境和服务。

模块详情

时长:20 分钟

所需服务

操作步骤

执行以下步骤,将单体服务分解为多个微服务。

步骤 1:创建环境

在上一模块中,您创建并部署了 api 应用程序。您可以重用该应用程序部署微服务环境。在本模块中,应用程序拆分为三个微服务:posts、threads 和 users。每一个微服务都作为一个独立服务部署在一个新环境中。之前已使用 CLI 部署了 monolith 环境和服务。现在,可以在 copilot env init 命令中指定 flag 来部署服务。首先,创建 posts 微服务。

$ copilot env init --name posts --profile default

Would you like to use the default configuration for a new environment?
 - A new VPC with 2 AZs, 2 public subnets and 2 private subnets
 - A new ECS Cluster
 - New IAM Roles to manage services and jobs in your environment
 [Use arrows to move, type to filter]
 > Yes, use default.
 Yes, but I'd like configure the default resources (CIDR ranges, AZs).
 No, I'd like to import existing resources (VPC, subnets).

选择 Yes, use default。

Default environment configuration? Yes, use default.
✔ Wrote the manifest for environment posts at copilot/environments/posts/manifest.yml
- Update regional resources with stack set "api-infrastructure" [succeeded] [10.7s]
✔ Proposing infrastructure changes for the api-posts environment.
- Creating the infrastructure for the api-posts environment. [create complete] [35.5s]
 - An IAM Role for AWS CloudFormation to manage resources [create complete] [14.3s]
 - An IAM Role to describe resources in your environment [create complete] [15.2s]
✔ Provisioned bootstrap resources for environment posts in region us-east-1 under application api.
Recommended follow-up actions:
 - Update your manifest copilot/environments/posts/manifest.yml to change the defaults.
 - Run `copilot env deploy --name posts` to deploy your environment.

运行 copilot env deploy —-name posts 命令部署环境。输出将如下所示:

✔ Proposing infrastructure changes for the api-posts environment.
- Creating the infrastructure for the api-posts environment. [update complete] [74.2s]
 - An ECS cluster to group your services [create complete] [2.7s]
 - A security group to allow your containers to talk to each other [create complete] [4.1s]
 - An Internet Gateway to connect to the public internet [create complete] [14.4s]
 - Private subnet 1 for resources with no internet access [create complete] [1.3s]
 - Private subnet 2 for resources with no internet access [create complete] [1.3s]
 - A custom route table that directs network traffic for the public subnets [create complete] [8.6s]
 - Public subnet 1 for resources that can access the internet [create complete] [1.3s]
 - Public subnet 2 for resources that can access the internet [create complete] [1.3s]
 - A private DNS namespace for discovering services within the environment [create complete] [48.9s]
 - A Virtual Private Cloud to control networking of your AWS resources [create complete] [12.8s]

重复此操作,为 users 和 threads 部署环境。

copilot env init --name users

copilot env deploy --name users

copilot env init --name threads

copilot env deploy --name threads

步骤 2:创建服务

使用 flag 为 Posts 创建服务。

$ copilot svc init --name posts --app api --dockerfile 3-microservices/services/posts/Dockerfile --svc-type "Load Balanced Web Service"

Note: It's best to run this command in the root of your workspace.
Note: Architecture type arm64 has been detected. We will set platform 'linux/x86_64' instead. If you'd rather build and run as architecture type arm64, please change the 'platform' field in your workload manifest to 'linux/arm64'.
✔ Wrote the manifest for service posts at copilot/posts/manifest.yml
Your manifest contains configurations like your container size and port (:3000).


- Update regional resources with stack set "api-infrastructure" [succeeded] [9.1s]
 - Update resources in region "us-east-1" [update complete] [6.8s]
 - ECR container image repository for "posts" [create complete] [4.1s]
Recommended follow-up actions:
 - Update your manifest copilot/posts/manifest.yml to change the defaults.
 - Run `copilot svc deploy --name posts --env test` to deploy your service to a test environment.

执行相同的操作,为 users 和 threads 创建服务。

copilot svc init --app api --dockerfile 3-microservices/services/users/Dockerfile --name users --svc-type "Load Balanced Web Service"

copilot svc init --app api --dockerfile 3-microservices/services/threads/Dockerfile --name threads --svc-type "Load Balanced Web Service

步骤 3:编辑每个微服务的 manifest.yml 中的路径

Amazon Copilot 根据服务名称设置服务的路径。但是,server.js 中微服务的路由由 api/<> 定义。在每个微服务清单中编辑路径,并在路径中添加 api/。

# Distribute traffic to your service.
http:
 # Requests to this path will be forwarded to your service.
 # To match all requests you can use the "/" path.
 path: 'api/posts'

模块 5:部署微服务

概述

部署微服务并安全地将应用流量从单体服务切换到微服务。

  1. 切换流量:首要配置。单体 Node.js 应用程序在 Amazon ECS 上的容器中运行,因此需要切换流量。

  2. 部署微服务:使用 Amazon Copilot 构建并推送到 Amazon ECR 的三个容器镜像部署三个微服务。

  3. 在 Refactor Spaces 中注册:在 Refactor Spaces 中注册微服务的负载均衡器 DNS。负载均衡器用于路由单体服务的流量。

  4. 关闭单体服务:删除 Copilot 环境,关闭单体服务。Refactor Spaces 将流量路由到各个端点上运行中的微服务。

目标

使用 Amazon Copilot 将 Node.js 应用部署为一组互连服务。然后,停止单体服务,并将流量从单体服务转移到微服务。

模块详情

时长:20 分钟

所需服务

操作步骤

执行以下步骤,部署微服务。

步骤 1:部署微服务

运行 copilot svc deploy --name --env  命令部署每个微服务。与 monolith service 类似,Amazon Copilot 会为微服务构建一个容器,并将其推送到存储库,然后部署到运行在 Fargate 上的 Amazon ECS 集群中。

$ copilot svc deploy --name posts --env posts
Building your container image: docker build -t 929897017989.dkr.ecr.us-east-1.amazonaws.com/api/posts:latest --platform linux/x86_64 --label com.aws.copilot.image.builder=copilot-cli --label com.aws.copilot.image.container.name=posts --label com.aws.copilot.image.version=v1.27.0 /Users/theheman/Library/CloudStorage/WorkDocsDrive-Documents/Downloads/amazon-ecs-nodejs-microservices-master/3-microservices/services/posts -f /Users/theheman/Library/CloudStorage/WorkDocsDrive-Documents/Downloads/amazon-ecs-nodejs-microservices-master/3-microservices/services/posts/Dockerfile
[+] Building 16.5s (9/9) FINISHED docker:desktop-linux
 => [internal] load build definition from Dockerfile 0.0s
 => => transferring dockerfile: 238B 0.0s
 => [internal] load .dockerignore 0.0s
 => => transferring context: 2B 0.0s
 => [internal] load metadata for docker.io/mhart/alpine-node:7.10.1 1.2s
 => [1/4] FROM docker.io/mhart/alpine-node:7.10.1@sha256:d334920c966d440676ce9d1e6162ab544349e4a4359c517300391c877bcffb8c 0.0s
 => [internal] load build context 0.0s
 => => transferring context: 617B 0.0s
 => CACHED [2/4] WORKDIR /srv 0.0s
 => [3/4] ADD . . 0.0s
 => [4/4] RUN npm install 15.2s
 => exporting to image 0.0s
 => => exporting layers 0.0s
 => => writing image sha256:c31c780560d4ab8e347fac4671e56731ee5dd1065936a4bfbf5f161bf633fed3 0.0s 
 => => naming to 929897017989.dkr.ecr.us-east-1.amazonaws.com/api/posts:latest 0.0s 
 
What's Next? 
 View summary of image vulnerabilities and recommendations → docker scout quickview
Login Succeeded
The push refers to repository [929897017989.dkr.ecr.us-east-1.amazonaws.com/api/posts]

执行同样的步骤,部署 Users 和 Threads 微服务。

copilot svc deploy --name threads --env threads
copilot svc deploy --name users --env users

步骤 2:在 Refactor Spaces 中注册微服务

在之前创建的 Refactor Spaces 应用程序中,将微服务注册为服务。然后,为基于 URI 的端点配置路由。Refactor Spaces 在代理中设置 URI 路径并自动切换。

  • 要在 Refactor Spaces 中注册服务并创建路由,请将 ApplicationID 和 EnvironmentId 参数值替换为模块 3 输出中的相应值。然后,传入上一步中执行 Copilot 命令后输出的三个服务的 Application Load Balancer URLs。

  • 此命令用于注册之前部署的三个微服务,并在 Refactor Spaces 中将其注册为服务。

aws cloudformation deploy \
 --template-file rs-service.yaml \
 --stack-name <<stackname>> 
 --parameter-override EnvironmentId=<<14 digit envID env-xxxxxxxxxx>> ApplicationID=<<14 digit appId app-xxxxxxxxxx>> PostsUrl=http://<<PostsUrl>>.elb.amazonaws.com UsersUrl=http://<<UsersUrl>>.elb.amazonaws.com ThreadsUrl=http://<<ThreadsUrl>>.elb.amazonaws.com \
 --output table

步骤 3:关闭单体服务

删除 monolith 服务,从而关闭单体服务。在终端上,运行 copilot svc delete --name monolith 命令。

$ copilot svc delete --name monolith
Sure? Yes
✔ Delete stack api-monolith-monolith
- Update regional resources with stack set "api-infrastructure" [succeeded] [8.7s]
 - Update resources in region "us-east-1" [update complete] [8.5s]


✔ Deleted service monolith from application api.
Recommended follow-up action:
 - Run `copilot pipeline deploy` to update the corresponding pipeline if it exists.

步骤 4:测试微服务

前往 Refactor Spaces 控制台,打开 rs-tutorial-env 环境,然后打开 rs-tutorial-app。您应当会看到四个服务及其相应的路由。

复制代理 URL,添加 /users、/threads 或 /posts,然后粘贴到新的浏览器标签页的地址栏中,访问该地址并查看输出内容。注意:DNS 更新需要一些时间。因此,可能会出现找不到服务器或内部服务器错误。在这种情况下,请等待完成,然后刷新。

模块 6:清理资源

概述

实验完成后,最好及时删除实验过程中创建的资源,以避免服务一直运行,从而持续产生费用。不过,此步骤是可选操作。您也可以保留部署的资源和服务,继续详细分析基础设施配置或者作为将来部署的模板。

目标

终止在实验过程中创建的资源。停止在 Amazon ECS 上运行的服务。删除应用程序负载均衡器。删除 Amazon CloudFormation 堆栈,从而终止 Amazon ECS 集群(包括所有底层 EC2 实例)。

模块详情

时长:20 分钟

所需服务

步骤 1:删除应用程序

运行以下命令,删除所有服务和基础设施:
copilot app delete --name api

步骤 2:删除 Refactor Spaces 资源

删除 CloudFormation 堆栈,从而删除 Refactor Spaces 环境和服务。运行以下命令,并将 <> 指定为您的堆栈名称,先删除服务堆栈,再删除环境堆栈。

aws cloudformation delete-stack --stack-name <<stackname>>

总结

恭喜您!您已完成本教程试验。您已了解如何在 Docker 容器中运行单体应用程序,并将应用程序部署为微服务,然后将流量切换到微服务。这个过程不会终端服务运行。请访问以下链接,学习其他学习内容。

轻松重构应用!

了解如何使用 Amazon ECS 以微服务的形式运行和管理大规模应用程序。

深入了解 Amazon Migration Hub Refactor Spaces 环境。

详细了解如何使用 Amazon ECS 在亚马逊云科技上构建和管理容器化架构。请参阅 Amazon ECS 资源。

使用 Overrides 将 Refactor Spaces 资源直接集成到 Copilot。了解 CDK Overrides。

了解在亚马逊云科技上构建和运行微服务的最佳实践,以加快部署、促进创新并提高可扩展性。阅读白皮书。