有关迁移现有软件产品以在云中无服务器运行的逐步指南 (A step by step guide to migrating an existing software product to run serverlessly in the cloud)
You’ve got an app that you run and you've heard loads about serverless and the benefits. You may have even tried deploying some things with serverless but you want to move you whole app to serverless.
您已经运行了一个应用程序,并且听说过有关无服务器及其好处的负载。 您甚至可能尝试使用无服务器部署某些内容,但您想将整个应用程序迁移到无服务器。
How do you do that? What bits do you do first? Do you have to do it all at the same time?
你是怎样做的? 您首先要做什么工作? 您是否必须同时执行所有操作?
This article will guide you through the steps you can take to migrate your app or service to the cloud with Serverless.
本文将指导您完成通过Serverless将应用程序或服务迁移到云时可以采取的步骤。
1.简单的API (1. Simple APIs)
When you start the process of migrating your service to, it’s best to start with the low hanging fruit. This will get you some experience working with serverless and AWS but still provide value to the application.
当您开始将服务迁移到的过程时,最好从低落的果实开始。 这将使您获得使用无服务器和AWS的一些经验,但仍可为应用程序提供价值。
Simple APIs are endpoints that don’t need to access your databases to perform their actions. This could be an API for sending emails, hitting external APIs and combining the data or for running some logic on the input.
简单的API是不需要访问数据库即可执行其操作的端点。 这可以是用于发送电子邮件,访问外部API并组合数据或在输入上运行某些逻辑的API。
A secondary advantage to creating these APIs is that it reduces the load on the existing servers. We, at MissionLabs, have found that this removal of functionality and complexity has allowed us to reduce the code on our servers by over 50%. This has resulted in much more readable code and quicker bug fixes.
创建这些API的第二个优点是它减少了现有服务器上的负载。 我们在MissionLabs发现,这种功能和复杂性的消除使我们能够将服务器上的代码减少50%以上。 这导致了更具可读性的代码和更快的错误修复。
How to migrate
如何迁移
Luckily, migrating simple APIs to the cloud using serverless is really easy with AWS Lambda and API Gateway.
幸运的是,借助AWS Lambda和API网关,使用无服务器将简单的API迁移到云非常容易。
AWS Lambda is a cloud function service where you can run code functions and only pay for when the function is running. You can write your code in Ruby, Python, Node, Java, Go or .Net and through the AWS SDK you can easily access other AWS services (such as email, sms, kinesis, databases).
AWS Lambda是一种云功能服务,您可以在其中运行代码功能,并且仅在功能运行时付费。 您可以用Ruby,Python,Node,Java,Go或.Net编写代码,并通过AWS开发工具包轻松访问其他AWS服务(例如电子邮件,短信,运动,数据库)。
To create an API using AWS Lambda and API Gateway you need to write a function that executes the logic. Then you need to export the function as exports.handler
.
要使用AWS Lambda和API Gateway创建API,您需要编写一个执行逻辑的函数。 然后,您需要将函数导出为exports.handler
。
exports.handler = async (event, context) => {
// your function code goes here
}
To deploy your code with an API using serverless, we need to add this new function to our serverless.yml file under function declaration. You need to define the location of the code as well as the methods and path for the API endpoint.
要使用无服务器的API通过API部署代码,我们需要将此新函数添加到函数声明下的serverless.yml文件中。 您需要定义代码的位置以及API端点的方法和路径。
functions:
myFirstApi:
handler: src/myFirstApi/index.handler
events:
- http:
path: getFromMyAPI
method: GET
cors: true
This will deploy your function code to ${random-api-subdomain}.execute-api.${region}.amazonaws.com/${stage}/getFromMyApi
. Here is an example of an endpoint.
这会将您的功能代码部署到${random-api-subdomain}.execute-api.${region}.amazonaws.com/${stage}/getFromMyApi
。 这是端点的示例。
https://ic5hwq6j0a.execute-api.eu-west-1.amazonaws.com/live/item
https://ic5hwq6j0a.execute-api.eu-west-1.amazonaws.com/live/item
If you want to create a more readable API address then you can use Route 53 to forward traffic so that your endpoint could be something like:
如果您想创建一个更具可读性的API地址,则可以使用Route 53转发流量,以便您的端点可以是:
https://api.completecoding.io/v1/item (not active)
https://api.completecoding.io/v1/item(无效)
2.数据库和连接的API (2. Databases and Connected APIs)
Now that you’ve migrated some of your APIs, you’re familiar with writing Lambda functions and deploying them with Serverless.
现在,您已经迁移了一些API,您熟悉编写Lambda函数并将其与Serverless一起部署。
The next step is to migrate your databases over to serverless and create the rest of your APIs.
下一步是将数据库迁移到无服务器,并创建其余的API。
2.1数据库 (2.1 Databases)
Databases are obviously a massive part of any software product, but creating, managing and scaling them can be a pain. Provisioning shards and syncing instances can be difficult at the best of times.
数据库显然是任何软件产品的重要组成部分,但是创建,管理和扩展数据库可能会很麻烦。 在最好的情况下,调配碎片和同步实例可能很困难。
With Serverless you can use DynamoDB, where scaling and performance are managed by AWS, leaving you to work on the valuable parts of the product.
借助无服务器,您可以使用DynamoDB,DynamoDB的扩展和性能由AWS管理,使您可以处理产品的重要部分。
How to migrate
如何迁移
Creating DynamoDB tables in serverless is relatively simple. All we need to do is create a new Resource and provide the table details.
在无服务器中创建DynamoDB表相对简单。 我们需要做的就是创建一个新的Resource并提供表格详细信息。
Resources:
OrderTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: order-table
AttributeDefinitions:
- AttributeName: userID
AttributeType: S
- AttributeName: orderId
AttributeType: S
KeySchema:
- AttributeName: userId
KeyType: HASH
- AttributeName: orderId
KeyType: HASH
Things can get a little more complex when it comes to auto-scaling and secondary indexes.
当涉及自动缩放和二级索引时,事情可能会变得更加复杂。
To get auto-scaling added to our table, we have two options. We can either set up PayPerReqest billing or provision auto-scaling on the table.
要在表中添加自动缩放比例,我们有两个选择。 我们可以在表上设置PayPerReqest结算,也可以设置自动缩放。
PayPerRequest is better if you have more irregular traffic that comes in spikes and troughs. To provision is you can remove these lines:
如果您有更多的高峰和低谷不规则流量,则PayPerRequest会更好。 要进行设置,您可以删除以下几行:
ProvisionedThroughput:
ReadCapacityUnits: 5
WriteCapacityUnits: 5
and replace them with this line:
并将其替换为此行:
BillingMode: PAY_PER_REQUEST
The other option is to add auto-scaling. This wasn’t a feature when Dynamo was first released so the configuration is more complex. To reduce the complexity we can use the serverless-dynamodb-autoscaling
plugin. To install this plugin run npm install serverless-dynamodb-autoscaling
and then add some custom fields to our serverless.yml file.
另一个选项是添加自动缩放。 当Dynamo首次发布时,这不是一项功能,因此配置更加复杂。 为了降低复杂性,我们可以使用serverless-dynamodb-autoscaling
插件。 要安装此插件,请运行npm install serverless-dynamodb-autoscaling
,然后将一些自定义字段添加到我们的serverless.yml文件中。
plugins:
- serverless-dynamodb-autoscaling
custom:
capacities:
- table: order-table # DynamoDB Resource
read:
minimum: 5 # Minimum read capacity
maximum: 1000 # Maximum read capacity
usage: 0.75 # Targeted usage percentage
write:
minimum: 40 # Minimum write capacity
maximum: 200 # Maximum write capacity
usage: 0.5 # Targeted usage percentage
You should use whichever of these methods is most applicable to how each of your tables is used. There is no reason you can’t have some tables on PayPerRequest and others using normal auto-scaling.
您应该使用哪种方法最适合每个表的使用方式。 您没有理由在PayPerRequest上没有某些表,而其他表则无法使用正常的自动缩放功能。
There is also the issue of migrating all your data from your existing tables to your new dynamo tables. Luckily this is a brilliant article about how to complete these kinds of migrations, whether from MongoDB, Cassandra, mySQL or RDBMS.
还有一个问题,就是将所有数据从现有表迁移到新的发电机表。 幸运的是,这是一篇精彩的文章,介绍了如何完成从MongoDB,Cassandra,mySQL或RDBMS进行的此类迁移。
2.2连接的API (2.2 Connected APIs)
Now that we have our databases created, we should be able to convert most of our remaining APIs over to serverless. These might be user lookups, logins, product lookups, order status updates or any other kind of request that read or write to one of your tables.
现在我们已经创建了数据库,我们应该能够将剩余的大多数API转换为无服务器。 这些可能是用户查询,登录名,产品查询,订单状态更新或任何其他读取或写入您的表的请求。
How to migrate
如何迁移
The process to create these functions will be exactly the same as the process that you did in step 1, but now we have databases to access.
创建这些功能的过程与您在步骤1中所做的过程完全相同,但是现在我们可以访问数据库了。
To access your data in DynamoDB, you can use the AWS SDK and the DynamoDB document client. This interface has the functionality to perform all the rest methods as well as a few extra such as scan, query, batchGet and batchWrite.
要访问DynamoDB中的数据,您可以使用AWS开发工具包和DynamoDB文档客户端。 该接口具有执行所有其余方法的功能以及一些其他功能,例如scan,query,batchGet和batchWrite 。
Whilst these sound perfect for baking into your Lambda code, I would suggest creating your own class that uses these methods. This is because the format of the request made to the document client is often overly complicated. Here’s my example of a simplified method for getting from Dynamo.
尽管这些听起来非常适合烘焙到Lambda代码中,但我建议您创建使用这些方法的自己的类。 这是因为对文档客户端的请求格式通常过于复杂。 这是我从Dynamo获取的一种简化方法的示例。
get(ID, table) {
if (!table)
throw 'table needed';
if (typeof ID !== 'string')
throw `ID was not string and was ${ID} on table ${table}`;
return new Promise((resolve, reject) => {
let params = {
TableName: table,
Key: {
ID: ID,
},
};
documentClient.get(params, function (err, data) {
if (err) {
console.log(`There was an error fetching the data for ID ${ID} on table ${table}`, err);
return reject(err);
}
return resolve(data.Item);
});
});
}
If you now need to do a lookup in any of your APIs you can just use
如果现在需要在任何API中进行查找,则可以使用
let user = await DB.get('123-f342-3ca', 'user-table')
You can do the same for write, update, delete, scan and query.
您可以对写入,更新,删除,扫描和查询执行相同的操作。
With these methods you should be able to port almost all your APIs over to serverless. This can be a large piece of work but there are a lot of benefits, including autoscaling, only pay for what you use, redundancy, separation of concerns and many more.
使用这些方法,您应该能够将几乎所有的API移植到无服务器。 这可能是一项繁重的工作,但是有很多好处,包括自动缩放,只为您使用的东西付费,冗余,关注点分离等等。
3.储存 (3. Storage)
Cloud storage was the first service that was ever provided by AWS - Amazon S3. This service allows you to host file in the cloud, define the access policies, and easily use those files in other AWS services.
云存储是AWS有史以来提供的第一项服务-Amazon S3。 通过此服务,您可以在云中托管文件,定义访问策略,并轻松在其他AWS服务中使用这些文件。
Items stored in S3 are put into buckets, which are isolated containers used to group items (similar to folders on your machine). You can store whatever files you like in S3, from product images, to invoices, from data in JSON format to whole websites.
S3中存储的项目放入存储桶中,这些存储桶是用于对项目进行分组的独立容器(类似于您计算机上的文件夹)。 您可以在S3中存储所需的任何文件,从产品图像到发票,从JSON格式的数据到整个网站。
How to migrate
如何迁移
There are two stages to migrating to serverless cloud storage: creating the buckets and deploying the resources.
迁移到无服务器云存储有两个阶段:创建存储桶和部署资源。
To create a bucket in serverless, you are defining a new resource. One thing to remember is that the bucket name must be globally unique. This means you can't have the same bucket name on two accounts, or in two regions.
要在无服务器中创建存储桶,您需要定义一个新资源。 要记住的一件事是,存储桶名称必须是全局唯一的。 这意味着您不能在两个帐户或两个区域中使用相同的存储桶名称。
resources:
Resources:
UploadBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: my-bucket-name-is-unique
When you run sls deploy
now, you'll find that you've created a bucket on your account. Now you can manually upload files into this bucket using the UI, or use it as a location to put uploaded files, but we're also going to learn how to sync up local files to the bucket.
立即运行sls deploy
,您会发现已在帐户上创建了存储桶。 现在,您可以使用用户界面将文件手动上传到此存储桶,或将其用作放置上传文件的位置,但是我们还将学习如何将本地文件同步到存储桶。
To automatically upload files to our new bucket, we're going to be using the serverless-s3-sync
plugin. This plugin allows us to upload all the content of a folder on our computer to an S3 bucket as part of the deployment process.
要将文件自动上传到我们的新存储桶,我们将使用serverless-s3-sync
插件。 此插件使我们可以在部署过程中将计算机上文件夹的所有内容上载到S3存储桶。
To start using the plugin, we need to install it using npm install --save serverless-s3-sync
and then adding the plugin to our serverless file. With out autoscaling DynamoDB plugin we'll now have this:
要开始使用插件,我们需要使用npm install --save serverless-s3-sync
进行npm install --save serverless-s3-sync
,然后将插件添加到我们的无服务器文件中。 在没有自动缩放DynamoDB插件的情况下,我们现在有了这个:
plugins:
- serverless-dynamodb-autoscaling
- serverless-s3-sync
To configure the upload we need to add another field to our custom
section as well.
要配置上传,我们还需要在custom
部分添加另一个字段。
custom:
s3Sync:
- bucketName: my-bucket-name-is-unique # required
bucketPrefix: assets/ # optional
localDir: dist/assets # required
The bucketName
needs to match the name of the bucket you created. The localDir
is the folder that you want to upload to the bucket. You can also use bucketPrefix
if you want to add a prefix onto the start of the files (put them in a folder within the bucket).
bucketName
必须与您创建的存储桶的名称匹配。 localDir
是您要上载到存储桶的文件夹。 如果要在文件开头添加前缀(将它们放入存储桶中的文件夹中),也可以使用bucketPrefix
。
With this all set up, running sls deploy
will now create a new bucket and upload the files you have in dist/assets
.
完成所有这些设置后,运行sls deploy
现在将创建一个新的存储桶并上传dist/assets
的文件。
4.网站托管 (4. Website Hosting)
So far you will have had to make quite a few URL changes to your website for all the API changes that you've already implemented. Now wouldn't it be cool if you could also host that website entirely serverlessly and deploy it with all of your APIs, databases and everything else.
到目前为止,对于已经实现的所有API更改,您将不得不对网站进行很多URL更改。 现在,如果您还可以完全无服务器托管该网站并将其与所有API,数据库和所有其他内容一起部署,那将不是很酷。
How to migrate
如何迁移
We're going to host and deploy our website in a very similar way to the way that we are hosting our asset storage in the last section: serverless-s3-sync.
我们将以与上一节中托管资产存储的方式非常类似的方式托管和部署我们的网站:serverless-s3-sync。
There are a few extra bits that we need to take care of when we're hosting a website. To start out though, we're still uploading a folder (containing our static site) to an S3 bucket. We can add a new bucket (MyWebsiteBucket) and new S3Sync setup. We set a custom variable called siteName
and then use that to define the bucket name.
托管网站时,需要注意一些额外的事项。 首先,我们仍将一个文件夹(包含我们的静态站点)上传到S3存储桶。 我们可以添加一个新的存储桶(MyWebsiteBucket)和新的S3Sync设置。 我们设置了一个名为siteName
的自定义变量,然后使用该变量来定义存储桶名称。
resources:
Resources:
UploadBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: my-bucket-name-is-unique
MyWebsiteBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: ${self:custom.siteName}
custom:
s3Sync:
- bucketName: my-bucket-name-is-unique
bucketPrefix: assets/
localDir: dist/assets
- bucketName: ${self:custom.siteName}
localDir: myWebsiteFolder
siteName: serverlessfullstack.com
But this time we need to add a few more things onto our S3 bucket configuration. We need to set the access control and tell S3 that this is a website we're hosting in the bucket.
但是这一次,我们需要在S3存储桶配置中添加更多内容。 我们需要设置访问控制,并告诉S3这是我们正在托管的网站。
MyWebsiteBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: ${self:custom.siteName}
WebsiteConfiguration:
IndexDocument: index.html
AccessControl: PublicRead
We also need to create a policy document for the bucket in our resources
我们还需要为资源中的存储桶创建一个策略文档
WebsiteS3BucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket:
Ref: MyWebsiteBucket
PolicyDocument:
Statement:
- Sid: PublicReadGetObject
Effect: Allow
Principal: "*"
Action:
- s3:GetObject
Resource:
Fn::Join: ["", [
"arn:aws:s3:::",
{"Ref": "StaticSite"},
"/*"
]]
When we now run sls deploy
we'll get our content of our website uploaded to S3 and all the correct permissions set on the bucket.
现在,当我们运行sls deploy
,会将我们的网站内容上载到S3,并在存储桶上设置所有正确的权限。
You'll now be able to view your site at http://serverlessfullstack.com.s3-website-us-east-1.amazonaws.com/
现在,您可以在http://serverlessfullstack.com.s3-website-us-east-1.amazonaws.com/
上查看您的网站。
This is nice but it would be better if we were hosting on our own url, so that's what we'll do now. We need to create a DNS record that points the requested domain to our s3 bucket.
很好,但是如果我们托管自己的URL,那就更好了,所以这就是我们现在要做的。 我们需要创建一个DNS记录,将请求的域指向我们的s3存储桶。
In Route 53, make sure you've set up your hosted zone name and then we can add the DNS record to the resources.
在Route 53中,确保已设置托管区域名称,然后我们可以将DNS记录添加到资源中。
DnsRecord:
Type: 'AWS::Route53::RecordSet'
Properties:
AliasTarget:
DNSName: ${self:custom.aliasDNSName}
HostedZoneId: ${self:custom.aliasHostedZoneId}
HostedZoneName: ${self:custom.siteName}.
Name:
Ref: MyWebsiteBucket
Type: 'A'
With this we also need to set a few extra custom fields of hostedZoneName
, aliasHostedZoneId
and aliasDNSName
.
这样,我们还需要设置hostedZoneName
, aliasHostedZoneId
和aliasDNSName
的一些其他自定义字段。
custom:
s3Sync:
- bucketName: ${self:custom.siteName}
localDir: myWebsiteFolder
siteName: serverlessfullstack.com
hostedZoneName: ${self:custom.siteName}
aliasHostedZoneId: Z3AQBSTGFYJSTF # us-east-1
aliasDNSName: s3-website-us-east-1.amazonaws.com
If you've set this up in a region that isn't us-east-1
then you can find your aliasHostedZoneId
here.
如果您在非us-east-1
的区域中进行了设置,则可以在此处找到您的aliasHostedZoneId
。
With this all set up you should now be able to run sls deploy
again. This will add the DNS record to your account and now you can visit serverlessfullstack.com and see the live page hosted from S3.
通过所有这些设置,您现在应该可以再次运行sls deploy
了。 这会将DNS记录添加到您的帐户,现在您可以访问serverlessfullstack.com并查看从S3托管的实时页面。
If you've followed along, the only differences between our code should be: custom.siteName
and your assets bucket name and you should have your own serverlessly hosted app!
如果您一直遵循,我们的代码之间的唯一区别应该是: custom.siteName
和资产存储桶名称,并且您应该拥有自己的无服务器托管应用程序!
If you've found this article useful and want to start working with Serverless then check out my FREE course on creating and deploying a Serverless API. You'll learn to:
如果您发现本文很有用,并且想开始使用Serverless,请查看我有关创建和部署Serverless API的免费课程 。 您将学会:
- Create a user and get credentials on AWS and set up Serverless 在AWS上创建用户并获取凭证并设置Serverless
- Create a Lambda and API Endpoint to handle the API requests 创建Lambda和API端点以处理API请求
- Deploy, Test and Update your API 部署,测试和更新您的API
翻译自: https://www.freecodecamp.org/news/migrating-your-app-to-the-cloud-using-serveless/