使用Node.js,AWS Lambda和MongoDB Atlas进行无服务器开发

本文最初在mongoDB发布 感谢您支持使SitePoint成为可能的合作伙伴。

近年来,开发人员的状况发生了巨大变化。 对于我们开发人员来说,在我们自己的机器上运行我们所有的工具(数据库,Web服务器,开发IDE…)曾经是相当普遍的事情,但是GitHubMongoDB AtlasAWS Lambda等云服务正在极大地改变游戏规则。 它们使开发人员越来越容易地在没有(或很少)依赖的任何地方和任何设备上编写和运行代码。

几年前,如果您崩溃了机器,丢失了机器或者只是断电了,那么可能要花几天时间才能使新机器恢复正常运行,并且需要正确设置和配置所有方式以前是。

借助云中的开发人员工具,您现在可以在中断最少的情况下从一台笔记本电脑切换到另一台笔记本电脑。 但是,这并不意味着一切都乐观。 在云中编写和调试代码仍然充满挑战。 作为开发人员,我们知道拥有本地开发环境,尽管更轻巧,但仍然非常有价值。

这正是我将在此博文中向您展示的内容:如何轻松地将AWS Lambda Node.js函数与MongoDB Atlas (用于MongoDB的DBaaS(数据库即服务))中托管的MongoDB数据库集成。 更具体地说,我们将编写一个简单的Lambda函数,该函数在MongoDB Atlas数据库中存储的集合中创建单个文档。 我将逐步指导您完成本教程,并且您应该在不到一个小时的时间内完成它。

让我们从必要的要求开始,以使您开始运行:

  1. 具有对IAM和Lambda服务具有管理访问权的用户可用的Amazon Web Services帐户。 如果您还没有,请注册一个免费的AWS账户
  2. 带有Node.js的本地计算机(我告诉过我们,我们不会轻易摆脱本地开发环境…)。 我们将在下面的教程中使用Mac OS X,但是在Windows或Linux上执行相同的任务应该相对容易一些。
  3. MongoDB Atlas集群活跃起来。 如果您还没有,请注册一个免费的MongoDB Atlas帐户,然后单击几下即可创建集群 。 您甚至可以尝试我们的M0免费集群层 ,非常适合小型开发项目!)。

既然您已经了解了需求,那么让我们来谈谈我们编写,测试和部署Lambda函数将要采取的具体步骤:

  1. MongoDB Atlas默认情况下是安全的,但是作为应用程序开发人员,我们应该采取一些步骤来确保我们的应用程序符合最小特权访问最佳实践 。 也就是说,我们将通过创建仅对应用程序数据库具有读/写访问权限的MongoDB Atlas数据库用户来微调权限。
  2. 我们将在本地计算机上建立一个Node.js项目,并确保在将lambda代码端到端测试到本地之前,将其部署到Amazon Web Services。
  3. 然后,我们将创建我们的AWS Lambda函数并上传Node.js项目以对其进行初始化。
  4. 最后但并非最不重要的一点是,我们将对Lambda函数进行一些修改,以加密一些敏感数据(例如MongoDB Atlas连接字符串)并从函数代码中对其解密。

关于VPC对等的简短说明

我没有深入研究在MongoDB Atlas集群和AWS Lambda之间设置VPC对等的细节,原因有两个:1)我们已经拥有详细的VPC对等文档页面和我强烈推荐的Atlas中VPC对等信息 ,以及2) M0集群(我用来构建该演示的集群) 不支持VPC Peering

如果您没有设置VPC对等,则会发生以下情况:

  1. 您将必须将臭名昭著的0.0.0.0/0 CIDR块添加到MongoDB Atlas群集IP白名单中,因为您将不知道AWS Lambda使用哪个IP地址拨打Atlas数据库。
  2. 您需要为Lambda函数和Atlas群集之间的带宽使用情况付费。

如果您只想编写此演示代码,则这两个警告可能很好,但是如果您打算部署可用于生产的Lambda-Atlas集成,则强烈建议设置VPC对等是安全性最佳做法。 M0是我们当前的免费产品; 请查看我们的MongoDB Atlas定价页面 ,以获取可用实例大小的所有范围。

提醒一下,对于开发环境和低流量网站,M0,M10和M20实例大小应该合适。 但是,对于支持高流量应用程序或大型数据集的生产环境,建议使用M30或更大的实例大小。

在MongoDB Atlas集群中设置安全性

确保您的应用程序符合最低特权访问策略,这对于保护数据免受恶意威胁至关重要。 这就是为什么我们将设置一个特定的数据库用户,该用户仅对我们的旅行数据库具有读/写访问权限。 让我们看看如何在MongoDB Atlas中实现这一点:

在“ 群集”页面上,选择“ 安全性”选项卡,然后按“ 添加新用户”按钮

集群

Lambda用户

在“ 用户权限”部分中,选择 链接。 这使我们可以在特定数据库而不是任何数据库上分配读/写。

用户权限

然后,您可以选择分配更多细粒度的访问控制特权:

访问控制

在“ 选择角色”下拉列表中,选择readWrite并在“ 数据库”字段中填写将用于存储文档的数据库的名称。 我选择将其命名为travel

选择角色

在“ 密码”部分中,使用“自动生成安全密码”按钮(并记下生成的密码)或设置您喜欢的密码。 然后按添加用户按钮以确认此用户的创建。

让我们抓住集群连接字符串,因为它需要用Lambda代码连接到我们的MongoDB Atlas数据库:

假设您已经创建了MongoDB Atlas集群 ,请按集群旁边的Connect按钮:

连接集群

复制URI连接字符串值,并将其安全地存储在文本文档中。 我们稍后将在代码中将其与您刚设置的密码一起使用。

URI连接字符串

另外,如果您不使用VPC对等网络,请导航到IP白名单选项卡并添加0.0.0.0/0 CIDR块,或按“ 允许从任何地方访问”按钮。 提醒您,强烈不建议将此设置用于生产环境,并且可能会使您的MongoDB Atlas群集容易受到恶意攻击。

添加白名单条目

创建一个本地Node.js项目

虽然LAMBDA功能在多国语言的支持,我已经选择使用Node.js的感谢的JavaScript的日益普及,作为一种多用途的编程语言和的巨大成功MEANMERN栈(缩写词对于M ongoDB,E xpress.js, Angular / R eact, N ode.js –请查看Andrew Morgan关于该主题的出色的面向开发人员的博客系列 )。 另外,说实话,我喜欢它是一种解释性的,轻量级的语言,不需要大量的开发工具和编译器。

现在该写一些代码了,接下来让我们继续使用Node.js作为我们Lambda函数的首选语言。

首先创建一个文件夹,例如lambda-atlas-create-doc

mkdir lambda-atlas-create-doc 
&& cd lambda-atlas-create-doc

接下来,从终端控制台运行以下命令以使用package.json文件初始化我们的项目

npm init

系统将提示您配置一些字段。 我将让他们发挥自己的创造力,但请注意,我选择将入口点设置为app.js(而不是默认的index.js),因此您可能也希望这样做。

我们将需要使用MongoDB Node.js驱动程序,以便我们可以从Lambda函数连接到Atlas上的MongoDB数据库,因此让我们从项目根目录运行以下命令来进行安装:

npm install mongodb --save

我们还希望在本地编写和测试Lambda函数,以加快开发速度并简化调试,因为在Amazon Web Services中每次实例化Lambda函数并不是特别快(并且几乎不存在调试功能,除非您成为console.log()函数的粉丝)。 我选择使用lambda-local包,因为它提供了对环境变量的支持(我们将在以后使用):

(sudo) npm install lambda-local -g

创建一个app.js文件。 这将是包含我们的lambda函数的文件:

touch app.js

现在,您已经导入了所有必需的依赖项并创建了Lambda代码文件,在您选择的代码编辑器(Atom,Sublime Text,Visual Studio Code…)中打开app.js文件,并使用以下代码对其进行初始化:

'use strict'

var MongoClient = require('mongodb').MongoClient;

let atlas_connection_uri;
let cachedDb = null;

exports.handler = (event, context, callback) => {
  var uri = process.env['MONGODB_ATLAS_CLUSTER_URI'];
    
  if (atlas_connection_uri != null) {
    processEvent(event, context, callback);
  } 
  else {
    atlas_connection_uri = uri;
    console.log('the Atlas connection string is ' + atlas_connection_uri);
    processEvent(event, context, callback);
  } 
};

function processEvent(event, context, callback) {
  console.log('Calling MongoDB Atlas from AWS Lambda with event: ' + JSON.stringify(event));
}

让我们暂停一下并注释上面的代码,因为您可能已经注意到一些特殊的构造:

  • 该文件的编写与Amazon Web Services期望的Lambda代码完全相同(例如,使用“ exports.handler”功能)。 这是因为我们正在使用lambda-local本地测试我们的lambda函数,这可以方便地使我们完全按照AWS Lambda的期望编写代码。 一分钟内可以了解更多。
  • 我们宣布了MongoDB Node.js驱动程序,它将有助于我们连接和查询MongoDB数据库。
  • 还要注意,我们在处理程序函数的外部声明了一个cachedDb对象。 顾名思义,这是我们计划在AWS Lambda为我们的函数实例化基础容器的持续时间内缓存的对象。 这使我们节省了一些宝贵的毫秒(甚至几秒钟)来在Lambda和MongoDB Atlas之间建立数据库连接。 有关更多信息,请阅读我的后续博客文章, 了解如何使用MongoDB Atlas优化Lambda性能
  • 我们正在使用一个名为MONGODB_ATLAS_CLUSTER_URI的环境变量来传递Atlas数据库的uri连接字符串,主要出于安全目的:我们显然不想在我们的功能代码中硬编码此uri,以及非常敏感的信息(例如用户名和密码)我们用。 由于AWS Lambda自2016年11月以来就支持环境变量 (就像lambda-local NPM软件包所支持的那样),我们将不使用它们。
  • 该函数代码看起来似乎毫无用处的if-else语句和processEvent函数看起来有些混乱,但是当我们使用AWS Key Management Service(KMS)添加解密例程时,所有这些都将变得清晰起来。 实际上,我们不仅要在环境变量中存储MongoDB Atlas连接字符串,而且还希望对其进行加密(使用AWS KMS),因为它包含高度敏感的数据(请注意,即使使用AWS KMS,您也可能会产生费用)如果您有一个免费的AWS账户)。

现在我们已经完成了代码注释,让我们在根项目目录中创建一个event.json文件,并用以下数据填充它:

{
  "address" : {
    "street" : "2 Avenue",
    "zipcode" : "10075",
    "building" : "1480",
    "coord" : [ -73.9557413, 40.7720266 ]
  },
  "borough" : "Manhattan",
  "cuisine" : "Italian",
  "grades" : [
    {
      "date" : "2014-10-01T00:00:00Z",
      "grade" : "A",
      "score" : 11
    },
    {
      "date" : "2014-01-16T00:00:00Z",
      "grade" : "B",
      "score" : 17
    }
  ],
 "name" : "Vella",
 "restaurant_id" : "41704620"
}

(以防万一,您会将该JSON文件发送给MongoDB Atlas以创建我们的BSON文档)

接下来,通过在终端控制台中运行以下命令来确保设置正确:

lambda-local -l app.js -e event.json -E {\"MONGODB_ATLAS_CLUSTER_URI\":\"mongodb://lambdauser:$PASSWORD@lambdademo-shard-00-00-7xh42.mongodb.net:27017\,lambdademo-shard-00-01-7xh42.mongodb.net:27017\,lambdademo-shard-00-02-7xh42.mongodb.net:27017/$DATABASE?ssl=true\&replicaSet=lambdademo-shard-0\&authSource=admin\"}

如果要使用自己的群集URI连接字符串进行测试(如我确定的那样),请不要忘记在E参数中转义双引号,逗号和&字符,否则lambda-local会抛出错误(您还应该用自己的值替换$ PASSWORD和$ DATABASE关键字)。

在本地运行它之后,应该获得以下控制台输出:

控制台输出

如果遇到错误,请检查连接字符串以及双引号/逗号/与转义符(如上所述)。

现在,通过定制processEvent()函数并添加createDoc()函数来深入了解函数代码:

function processEvent(event, context, callback) {
  console.log('Calling MongoDB Atlas from AWS Lambda with event: ' + JSON.stringify(event));
  var jsonContents = JSON.parse(JSON.stringify(event));
    
  //date conversion for grades array
  if(jsonContents.grades != null) {
    for(var i = 0, len=jsonContents.grades.length; i  connecting to database');
    MongoClient.connect(atlas_connection_uri, function (err, db) {
      cachedDb = db;
        return createDoc(db, jsonContents, callback);
      });
    }
    else {
      createDoc(cachedDb, jsonContents, callback);
    }
  }
  catch (err) {
    console.error('an error occurred', err);
  }
}

function createDoc (db, json, callback) {
  db.collection('restaurants').insertOne( json, function(err, result) {
    if(err!=null) {
      console.error("an error occurred in createDoc", err);
      callback(null, JSON.stringify(err));
    }
    else {
      console.log("Kudos! You just created an entry into the restaurants collection with id: " + result.insertedId);
      callback(null, "SUCCESS");
    }
    //we don't need to close the connection thanks to context.callbackWaitsForEmptyEventLoop = false (above)
   //this will let our function re-use the connection on the next called (if it  can re-use the same Lambda container)
     //db.close();
  });
};

请注意连接到MongoDB Atlas数据库并插入文档有多么容易,以及我添加的一小段代码将JSON日期(格式化为符合ISO的字符串)转换为真实的JavaScript日期,MongoDB可以将其存储为BSON日期。

您可能还会注意到我的性能优化注释以及对context.callbackWaitsForEmptyEventLoop = false的调用。 如果您有兴趣了解它们的含义(我想应该!),请参阅我的后续博客文章,了解如何使用MongoDB Atlas优化Lambda性能。

现在,您可以在本地全面测试Lambda函数了。 使用与以前相同的lambda-local命令,希望您会收到一条不错的“ Kudos”成功消息:

控制台输出

如果在您的本地计算机上一切正常,让我们将本地Node.js项目发布为新的Lambda函数!

创建Lambda函数

我们要采取的第一步是压缩Node.js项目,因为我们不会在Lambda代码编辑器中编写Lambda代码函数。 相反,我们将选择zip上传方法来将代码推送到AWS Lambda。

我已经在终端控制台中使用了zip命令行工具,但是任何方法都可以工作(只要您将文件压缩在顶层文件夹中,而不是顶层文件夹本身中即可!):

zip -r archive.zip node_modules/ app.js package.json

接下来,登录到AWS控制台并导航到“ IAM角色”页面,并使用AWSLambdaBasicExecutionRole权限策略创建一个角色(例如LambdaBasicExecRole):

AWS Lambda基本执行角色

现在让我们导航到AWS Lambda页面。 单击立即开始 (如果您从未创建Lambda函数)或单击“ 创建Lambda函数”按钮。 我们将不会使用任何蓝图,也不会配置任何触发器,因此请直接在左侧导航栏中选择“ 配置功能”

AWS Lambda配置

在“ 配置功能”页面中,输入您的功能的名称(例如MongoDB_Atlas_CreateDoc )。 运行时会自动设置为Node.js 4.3 ,这对我们来说是完美的,因为这是我们将使用的语言。 在“ 代码输入类型”列表中,选择“上Upload a .ZIP file ,如下面的屏幕快照所示:

配置功能

单击上按钮,然后选择先前创建的压缩的Node.js项目文件。

Lambda函数处理程序和角色部分中,将Handler字段值修改为app.handler (为什么?这是一个提示:我使用了app.js文件,而不是Lambda函数代码使用index.js文件…),然后选择我们刚刚创建的现有LambdaBasicExecRole角色:

Lambda函数处理程序

在“ 高级设置”部分中,您可能希望将“ 超时”值增加到5或10秒,但始终可以在以后进行调整。 将VPC和KMS密钥字段保留为默认值(除非您想使用VPC和/或KMS密钥),然后按Next

最后,查看您的Lambda函数,然后按底部的创建函数 。 恭喜,您的Lambda函数已启用,您将看到类似于以下屏幕截图的页面:

Lambda创建功能

但是您还记得我们对环境变量的使用吗? 现在是配置它们并使用AWS Key Management Service保护它们的时候了!

配置和保护Lambda环境变量

在Lambda函数的“代码”选项卡中向下滚动,并创建具有以下属性的环境变量:

名称
MONGODB_ATLAS_CLUSTER_URI YOUR_ATLAS_CLUSTER_URI_VALUE

环境变量

此时,您可以按页面顶部的“ 保存并测试”按钮,但是为了提高安全性(并建议使用),我们将加密该连接字符串。

选中启用加密助手复选框,如果您已经创建了加密密钥,请选择它(否则,您可能必须创建一个密钥-这相当简单):

密码匙

接下来,为MONGODB_ATLAS_CLUSTER_URI变量选择“ 加密”按钮:

选择加密

返回内联代码编辑器,在顶部添加以下行:

const AWS = require('aws-sdk');

并使用以下代码替换“ exports.handler”方法中“ else”语句的内容:

const kms = new AWS.KMS();
  kms.decrypt({ CiphertextBlob: new Buffer(uri, 'base64') }, (err, data) => {
  if (err) {
    console.log('Decrypt error:', err);
    return callback(err);
  }
  atlas_connection_uri = data.Plaintext.toString('ascii');
  processEvent(event, context, callback);
});

(希望我们最初编写的复杂代码现在变得有意义了!)

如果要检查我使用过的全部功能代码 ,请查看以下Gist 。 对于Git爱好者,还可以在GitHub上获得完整的Node.js项目源代码

现在按下Save and test按钮,然后在Input test event文本编辑器中,粘贴event.json文件的内容:

输入测试事件

滚动并按保存并测试按钮。

如果正确配置了所有内容,则应在Lambda日志输出中收到以下成功消息:

Lambda日志输出

荣誉! 在继续阅读之前,您可以先品尝一下成功的经验。

下一步是什么?

我希望此AWS Lambda-MongoDB Atlas集成教程为您提供第一个Lambda项目入门的正确步骤。 现在,您应该能够在本地编写和测试Lambda函数,并在AWS KMS中安全地存储敏感数据(例如MongoDB Atlas连接字符串)。

那你下一步该怎么做?

当然,请随时向我们提出任何问题,或在下面的评论中留下您的反馈。 编码愉快!

喜欢这篇文章吗? 重播我们的网络研讨会,那里有关于使用AWS Lambda的无服务器架构的交互式教程。

From: https://www.sitepoint.com/serverless-development-with-node-js-aws-lambda-and-mongodb-atlas/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值