【ArchSummit架构师峰会】探讨数据与人工智能相互驱动的关系>>> 了解详情
写点什么

如何将 AWS Node.js Lambda 函数迁移至 OpenFaaS?

  • 2019-10-24
  • 本文字数:4100 字

    阅读完需:约 13 分钟

如何将AWS Node.js Lambda函数迁移至OpenFaaS?

本篇教程,我们将共同了解如何将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/


2019-10-24 14:571459
用户头像
赵钰莹 InfoQ 主编

发布了 874 篇内容, 共 604.5 次阅读, 收获喜欢 2671 次。

关注

评论

发布
暂无评论
发现更多内容

2023年,你需要了解Zebec生态的几个开年利好

EOSdreamer111

FL水果Studio21免费版有哪些功能?

茶色酒

水果FL Studio FL水果

实现Promise的原型方法--前端面试能力提升

helloworld1024fd

JavaScript

几个常见的js手写题,你能写出来几道

helloworld1024fd

JavaScript

手写一个Redux,深入理解其原理-面试进阶

beifeng1996

React

社招前端一面经典手写面试题

helloworld1024fd

JavaScript

从React源码角度看useCallback,useMemo,useContext

goClient1992

React

2023年,你需要了解Zebec生态的几个开年利好

股市老人

js事件循环与macro&micro任务队列-前端面试进阶

loveX001

JavaScript

Java高手速成 | 使用TCP进行手机文件传输

TiAmo

Java TCP

理解「业务」与「技术」概念

架构 技术 业务

说说你对Vue的keep-alive的理解

bb_xiaxia1998

Vue

带你实现react源码的核心功能

goClient1992

React

你是如何使用React高阶组件的?

beifeng1996

React

阿里前端一面必会react面试题总结

beifeng1996

React

如何在 C# 项目中链接一个文件夹下的所有文件

newbe36524

滴滴前端一面必会vue面试题(附答案)

bb_xiaxia1998

Vue

湖仓一体电商项目(十九):业务实现之编写写入DWS层业务代码

Lansonli

数据湖 湖仓一体电商项目

从React源码来学hooks是不是更香呢

goClient1992

React

js异步编程面试题你能答上来几道

loveX001

JavaScript

2023最新前端面试总结

loveX001

JavaScript

如何整理自己的前端面试题库

loveX001

JavaScript

面试官:vue2和vue3的区别有哪些?

bb_xiaxia1998

Vue

前端vue面试题

bb_xiaxia1998

Vue

用户行为分析模型实践(三)——H5通用分析模型

vivo互联网技术

大数据 数据分析 数仓建模

高级前端常考手写面试题(必备)

helloworld1024fd

JavaScript

Backbone前端框架解读

京东科技开发者

Vue 前端 前端架构 企业号 2 月 PK 榜 backbone

基于SLO告警(Part 3):开源项目 sloth 使用

Grafana 爱好者

云原生 可观测性 Prometheus SRE SLO

EasyRecovery14最新个人版本有哪些功能?

茶色酒

Okhttp 如何构建一个 Get 的 URL

HoneyMoose

校招前端二面常考react面试题总结

beifeng1996

React

如何将AWS Node.js Lambda函数迁移至OpenFaaS?_语言 & 开发_Ruan_InfoQ精选文章