本篇教程,我们将共同了解如何将AWS Lambda函数(Node.js)迁移至 OpenFaaS。
为什么要迁移至 OpenFaas?
云函数服务确实优点很多,不仅成本低廉,而且适合大部分用例的实际需求。但在另一方面,OpenFaaS 相较于云函数服务也拥有不少独特优势。
下面,我先聊聊自己在使用 OpenFaaS 中的具体感受:
可以在自有基础设施上托管函数以满足本地化标准。
确保函数托管在符合用例特性的资源之上(包括 CPU、内存以及 GPU 密集型任务)。
可以使用现有 Kubernetes 或者 Docker Swarm 集群部署 OpenFaaS。
对 TTL 没有任何限制,可以长期保持函数运行。
确保用户不致锁定于特定云服务供应商处。
拥有一整套函数库以及为其提供贡献的活跃社区,能够为项目提供巨大助益。
默认提供自动规模伸缩功能。
支持一系列编程语言选项,甚至能够使用 bash 脚本,极大提升使用体验!
极易学习,而且使用感受也非常友好。
Cli 客户端与 faas-cil 的存在又让 OpenFaaS 的使用难度进一步降低。
Grafana、Prometheus 以及 ALertManager 可在框架中开箱即用,允许大家轻松查看函数指标并设置警报机制。
根据实际体验,我之前已经建立起一套 Docker Swarm 集群,其中的资源由云服务供应商管理,同时拥有监控、高可用性以及自我修复机制。
现在,我可以在这套集群设置之上使用 OpenFaaS,而且完美匹配实际用例。
架构
终极目标是将 AWS Lambda Function 迁移至 OpenFaaS:
应用程序
我们在AWS中的无服务器应用程序包含 API 网关、DynamoDB 以及 Lambda(Node.js)。
在示例中,我会尽量控制应用程序的复杂度,因此其功能非常简单:当我在 API 网关资源上发出 GET 请求时,在 DynamoDB 表上执行 GetItem。
在这种情况下,我将哈希键值硬编码至 ruan.bekker 中。
整个流程如下所示:
-> API: /dev/person,-> Lambda calls DynamoDB: {"id": "ruan.bekker"},-> Response: {"id": "ruan.bekker", "name": "ruan", ...}
复制代码
AWS 设置
为了完全透明,我将使用无服务器方式设置整个 AWS 栈:
$ mkdir -p ~/dev/aws-node-get-dynamodb \&& cd ~/dev/aws-node-get-dynamodb$ npm install -g serverless$ serverless create --template aws-nodejs
复制代码
创建 Lambda 函数:
$ mkdir function/handler.js$ cat function/handler.js'use strict';const AWS = require('aws-sdk');const dynamoDb = new AWS.DynamoDB.DocumentClient();module.exports.identity = (event, context, callback) => {const params = {TableName: process.env.DYNAMODB_TABLE,Key: { id: 'ruan.bekker', }, };dynamoDb.get(params, (error, result) => { if (error) { console.error(error); callback(null, { statusCode: error.statusCode || 501, headers: { 'Content-Type': 'text/plain' }, body: 'GetItem Failed', }); return; } const response = { statusCode: 200, body: JSON.stringify(result.Item), }; callback(null, response); });};
复制代码
无服务器定义文件:
$ cat serverless.ymlservice: aws-node-get-dynamodbframeworkVersion: ">=1.1.0 <2.0.0"provider: name: aws runtime: nodejs10.x environment: DYNAMODB_TABLE: my-dynamodb-table iamRoleStatements: - Effect: Allow Action: - dynamodb:GetItem Resource: "arn:aws:dynamodb:${opt:region, self:provider.region}:*:table/${self:provider.environment.DYNAMODB_TABLE}"functions: get: handler: functions/handler.identity events: - http: path: person method: get cors: trueresources: Resources: TodosDynamoDbTable: Type: 'AWS::DynamoDB::Table' DeletionPolicy: Retain Properties: AttributeDefinitions: - AttributeName: id AttributeType: S KeySchema: - AttributeName: id KeyType: HASH ProvisionedThroughput: ReadCapacityUnits: 1 WriteCapacityUnits: 1 TableName: ${self:provider.environment.DYNAMODB_TABLE}
复制代码
部署该栈:
$ serverless deploy --region eu-west-1Serverless: Packaging service...Serverless: Excluding development dependencies...Serverless: Uploading CloudFormation file to S3...Serverless: Uploading artifacts...Serverless: Uploading service aws-node-get-dynamodb.zip file to S3 (7.38 MB)...Serverless: Validating template...Serverless: Updating Stack...Serverless: Checking Stack update progress.................Serverless: Stack update finished...Service Informationservice: aws-node-get-dynamodbstage: devregion: eu-west-1stack: aws-node-get-dynamodb-devresources: 12api keys: Noneendpoints: GET - https://xx.execute-api.eu-west-1.amazonaws.com/dev/personfunctions: get: aws-node-get-dynamodb-dev-getlayers: NoneServerless: Run the "serverless" command to setup monitoring, troubleshooting and testing.
复制代码
现在我们的技术栈已经部署完成,接下来就是向 DynamoDB 中写入一个条目。
由于本文的重点在于迁移,因此我将哈希键硬编码至 ruan.bekker 当中,下面在 DynamoDB 中创建该条目:
$ aws dynamodb put-item \ --table-name my-dynamodb-table --item \'{ "id": {"S": "ruan.bekker"}, "name": {"S": "ruan"}, "surname": {"S": "bekker"}, "country": {"S": "south africa"}, "age": {"N": "32"}}
复制代码
发送一条指向该 API 网关 URL 的 GET 请求:
$ curl https://xx.execute-api.eu-west-1.amazonaws.com/dev/person{"id":"ruan.bekker","surname":"bekker","name":"ruan","country":"south africa","age":32}
复制代码
可以看到,现在我们已经能够在 DynamoDB 中检索到该条目。
设置 OpenFaaZS 函数
创建一个新的 Node.js OpenFaaS 函数(请注意,设置当中使用了镜像前缀与网关 url,如下所示):
$ mkdir -p ~/dev/lambda-to-openfaas-migration \ && cd ~/dev/lambda-to-openfaas-migration$ faas-cli new \ --lang node person \ --prefix=ruanbekker \ --gateway https://openfaas.ruan.dev$ mv person.yml stack.yml
复制代码
在本示例中,我会将 AWS Access Keys 与 Secret Keys 创建为 OpenFaaS secrets:
$ faas-cli secret create my-aws-secret-key --from-literal="your-access-key"$ faas-cli secret create my-aws-access-key --from-literal="your-secret-key"
复制代码
在我们的 package.json 当中提供 aws-sdk 依赖项,并借此与 AWS 进行交互:
$ cat person/package.json{ "name": "function", "version": "1.0.0", "description": "", "main": "handler.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "aws-sdk": "latest" }}
复制代码
我们的栈定义:
$ cat stack.ymlprovider: name: openfaas gateway: https://openfaas.ruan.devfunctions: person: lang: node handler: ./person image: ruanbekker/person:latest environment: content_type: application/json DYNAMODB_TABLE: my-dynamodb-table AWS_REGION: eu-west-1 secrets: - my-aws-access-key - my-aws-secret-key
复制代码
我们的初始设置中仍包含 AWS Lambda 函数代码,但到这里的栈已经设置完成,而且无需任何本地复本。
下面,我们需要下载 Lambda 部署软件包:
$ mkdir aws-lambda \ && cd aws-lambda$ lambda_url=$(aws lambda get-function --function-name serverless-rest-api-with-dynamodb-dev-get | jq -r .Code.Location)$ curl -o deployment_package.zip "${lambda_url}"
复制代码
提取该部署软件包并利用由此得到的 OpenFaaS 处理程序替换原 Lambda 函数处理程序:
$ unzip deployment_package.zip$ cd ..$ mv aws-lambda/function/handler.js person/handler.js
复制代码
接下来,我们需要修改处理程序以纳入各 secrets 与环境变量:
$ cat person/handler.js'use strict';const fs = require('fs');const secretAK = "/var/openfaas/secrets/my-aws-access-key";const secretSK = "/var/openfaas/secrets/my-aws-secret-key";const accessKey = fs.readFileSync(secretAK, "utf-8");const secretKey = fs.readFileSync(secretSK, "utf-8");const AWS = require('aws-sdk');AWS.config.update({ credentials: new AWS.Credentials ({ region: process.env.AWS_REGION, accessKeyId: accessKey, secretAccessKey: secretKey })})const dynamoDb = new AWS.DynamoDB.DocumentClient();module.exports = (context, callback) => { const params = { TableName: process.env.DYNAMODB_TABLE, Key: { id: 'ruan.bekker', }, }; dynamoDb.get(params, (error, result) => { if (error) { console.error(error); callback(null, { statusCode: error.statusCode || 501, headers: { 'Content-Type': 'text/plain' }, body: 'GetItem Failed', }); return; } const response = result.Item; callback(null, response); });};
复制代码
部署 OpenFaaS 函数:
$ export OPENFAAS_URL=https://openfaas.ruan.dev$ faas-cli upDeploying: person.Deployed. 202 Accepted.URL: https://openfaas.ruan.dev/function/person
复制代码
现在,我们需要在 OpenFaaS API 网关 URL 上通过 GET 请求测试新创建的函数:
$ curl https://openfaas.ruan.dev/function/person{"id":"ruan.bekker","surname":"bekker","name":"ruan","country":"south africa","age":32}
复制代码
搞定,现在我们已经将 AWS Lambda Function 迁移至 OpenFaaS。
原文链接:
https://sysadmins.co.za/migrate-your-aws-node-js-lambda-function-to-openfaas/
评论