Amazon CloudFront 部署小指南(六)- Lambda@Edge 基础与诊断

内容简介

本文适用于希望使用 Amazon CloudFront Lambda@Edge 提升 Amazon CloudFront 边缘计算能力的用户,旨在帮助您更好的进行 CloudFront Lambda@Edge 的开发、调试、测试、部署等工作。

首先我们会对 CloudFront Lambda@Edge 做个简单的介绍,然后分七个步骤为您讲述如何创建一个带有 CloudFront Lambda@Edge 处理能力的测试环境,并开展一些相关的调试工作。

  • 步骤一:准备基于部署小指南(二)的整体架构

  • 步骤二:创建一个 Lambda 函数

  • 步骤三:添加 CloudFront 触发器来运行函数

  • 步骤四:CloudFront Lambda@Edge 日志输出及查询

  • 步骤五:使用 Response Header 提升调试效率

  • 步骤六:查看 Lambda@Edge 资源利用率

  • 步骤七:CloudFront Extension 中的 CFF 应用

通过本指南,您将学会如何使用 CloudFront,快速构建一个内容分发网络,并展示分发效果。

CloudFront Function

和 Lambda@Edge 的简单介绍

使用 Amazon CloudFront,您可以编写自己的代码来处理 HTTP 请求和响应。代码在您的用户附近运行以最大限度的减少延迟,并且您无需管理服务器或其他基础设施。您可编写代码来操纵流经 CloudFront 的请求和响应、执行基本身份验证和授权、在边缘生成 HTTP 响应等。您编写并附加到 CloudFront 分配的代码称为边缘函数。CloudFront 目前提供了两种编写和管理边缘函数的方法:

  • CloudFront Functions -- 借助 CloudFront Functions,您可以使用 JavaScript 编写轻量级函数,以实现大规模、对延迟敏感的 CDN 自定义处理。CloudFront Functions 运行时环境提供亚毫秒级启动时间,可立即扩展以每秒处理数百万个请求,并且高度安全。CloudFront Functions 是 CloudFront 的原生功能,这意味着您可以完全在 CloudFront 中构建、测试和部署代码。

  • Lambda@Edge -- Lambda@Edge 是 Amazon Lambda 的扩展,它为复杂功能和完整的应用程序逻辑提供强大而灵活的计算,更接近您的查看者,并且高度安全。Lambda@Edge 函数在 js 或 Python 运行时环境中运行。您将它们发布到单个 Amazon 区域,但当您将函数与 CloudFront 分配相关联时,Lambda@Edge 会自动在全球范围内复制您的代码。

有关 CloudFront Functions 和 Lambda@Edge 的区别以及选择可以参阅 CloudFront 文档。

本文会致力于介绍 CloudFront Lambda@Edge,有关

CloudFront Functions 的详细介绍可以参考Amazon CloudFront 部署小指南(四)- CloudFront Function 基础与诊断

如下图所示,Lambda@Edge 既可以放在 Viewer 阶段,又可以放在 Origin 阶段。Lambda@Edge 非常适合以下场景:

  • 需要几毫秒或更长时间才能完成的函数。

  • 需要可调节 CPU 或内存的函数。

  • 依赖于第三方库(包括 Amazon 开发工具包,用于与其他 Amazon 服务集成)的函数。

  • 需要网络访问才能使用外部服务进行处理的函数。

  • 需要文件系统访问或访问 HTTP 请求正文的函数。

如何开始

CloudFront Lambda@Edge 的开发

CloudFront Lambda@Edge 是 Lambda 的扩展,实际使用时也是先完成 Lambda 的开发、测试、部署,然后将其与 CloudFront 分配相关联,CloudFront 则会将 Lambda 分发到边缘站点,在边缘站点中截获请求和响应进行处理,可以显著的减少延迟并改善用户体验。

与 Lambda 不同的是,Lambda@Edge 只支持 Node.js 和 Python 作为开发语言,且必须创建在 US East(N. Virginia)区域,它会自动分发到各个边缘站点去执行。更多对 Lambda@Edge 的限制可以参考开发人员指南。

下面我们就着手搭建一个最小的 CloudFront Lambda@Edge 环境。

步骤一:

准备基于部署小指南(二)的整体架构,来进行部署过程的演示

首先,让我们基于 CloudFront 部署小指南(二),搭建一个加速动静结合网站的 CloudFront 环境。在本文中,我们主要会用这个环境里动态网站的部分来完成调试。

在调试过程中,我们会主要使用/api 这个关闭缓存的 Behavior path 进行调试。利用 Echo-Sever 观察 CloudFront Lambda@Edge 带来的 Web 请求的改变。

步骤二:

创建一个 Lambda 函数

您可以参考官方文档第三步,通过使用蓝图来快速创建一个修改响应头的示例函数。使用以下代码进行测试,以下代码中增加了 AWS_REGION 环境变量的输出,并和自定义的 function-version 一起放在 header 中返回给客户端。

官方文档第三步:https://docs.aws.amazon.com/zh_cn/AmazonCloudFront/latest/DeveloperGuide/lambda-edge-how-it-works-tutorial.html#lambda-edge-how-it-works-tutorial-create-function

如果想了解更多环境变量,可以参考官方文档检索环境变量。

*注意,修改响应头的函数需要关联 CloudFront 的 Viewer Response 或者源响应(Origin Response)事件,并且修改的是 CloudFront 的 response event 数据结构。该数据结构在 Viewer Request 和 Origin Request 事件里是无法获取的。

c 复制代码
'use strict';
exports.handler = (event, context, callback) => {


    //Get contents of response
    const response = event.Records[0].cf.response;
    const headers = response.headers;
    
    let region = process.env.AWS_REGION;
    console.log("region: ", region);


    //Set new headers
    headers['strict-transport-security'] = [{key: 'Strict-Transport-Security', value: 'max-age= 63072000; includeSubdomains; preload'}];
    headers['content-security-policy'] = [{key: 'Content-Security-Policy', value: "default-src 'none'; img-src 'self'; script-src 'self'; style-src 'self'; object-src 'none'"}];
    headers['x-content-type-options'] = [{key: 'X-Content-Type-Options', value: 'nosniff'}];
    headers['x-frame-options'] = [{key: 'X-Frame-Options', value: 'DENY'}];
    headers['x-xss-protection'] = [{key: 'X-XSS-Protection', value: '1; mode=block'}];
    headers['referrer-policy'] = [{key: 'Referrer-Policy', value: 'same-origin'}];
    
    headers['function-version'] = [{key: 'Function-Version', value: 'V01'}];
    headers['function-region'] = [{key: 'Function-Region', value: region}];


    //Return modified response
    callback(null, response);
};

左滑查看更多

步骤三:

添加 CloudFront 触发器来运行函数

您可以参考官方文档第四步,为 Lambda 函数配置 CloudFront 触发器以运行您的函数。这儿您可以选择步骤一中提前创建好的 CloudFront 分配,缓存行为选择 /api/*,这一次,CloudFront 事件类型我们选择源响应(Origin Response),勾选确认部署到 Lambda@Edge,点击部署。

官方文档第四步:https://docs.aws.amazon.com/zh_cn/AmazonCloudFront/latest/DeveloperGuide/lambda-edge-how-it-works-tutorial.html#lambda-edge-how-it-works-tutorial-add-trigger

部署完成后,可以通过 curl 命令进行测试,我们看到响应头中已经包含了在 Lambda 中添加的标头信息。

注意:Lambda@Edge 的部署需要一些时间,可以进入 CloudFront 分配中的常规页面查看上次修改时间,确认部署进度。

python 复制代码
curl -i http://xxxx.cloudfront.net/api/test

左滑查看更多

更新 Lambda@Edge 函数

**方式一:**在 Lambda 控制台重新发布

对于已经部署到 Lambda@Edge 的函数,如果在 Lambda 中修改了代码,需要先点击**部署(Deploy)**按钮,保存修改后的代码。然后重复步骤三,将修改后的函数部署到 Lambda@Edge。

**方式二:**发布新版本后,更新 CloudFront

部署(Deploy) 之后,切换到版本 标签页,点击发布新版本 进行发布,发布后会得到一个新的版本号,然后到 CloudFront 控制台选择需要部署的目标分配,在行为(Behavior) 中选择对应的行为,点击编辑 按钮,在最下面的函数关联 中更新函数 ARN/名称 为刚刚生成的版本号,点击保存更改

对于需要同时更新源请求源响应 的场景,可以采取方式二,同时变更源请求源响应的版本,这样 CloudFront 在部署的时候则可以同时更新两个函数。

步骤四:

CloudFront Lambda@Edge 日志输出及查询

使用 Console.log 进行日志输出,Lambda@Edge 会自动将日志发送到 CloudWatch 日志组,在函数运行的 Amazon 区域中创建日志流,日志组名称的格式为

/aws/lambda/us-east-1.function-name ,

其中 function-name 是您在创建函数时为函数指定的名称, us-east-1 是运行函数的 Amazon 区域的区域代码。

Lambda@Edge 的日志存放在函数实际执行的区域,而非函数部署的区域( us-east-1 ),所以在调试的时候,需要先确定函数执行的区域,在 CloudWatch 控制台中切换到对应的区域,搜索 function-name 进入日志组方能查看最新日志。在不确定执行区域的情况下,如果在各个区域之间不停的切换,查找日志信息,极其耽误时间。而且由于日志存在延迟,还会出现明明找对了区域,但是因为延迟而错过日志,然后不停的在错误区域中寻找,耽误了宝贵的时间。

官方文档中提到的通过在 CloudFront 控制台上查看对应函数的指标图表的方式,由于是统计信息,在请求非常少的时候或许适用,如果多个区域都存在一定的请求数量,就比较难判断。

通过 Header 中的 X-Amz-Cf-Pop 值,可以获得当前请求所对应的边缘位置编号,通过 Amazon CloudFront CDN Edge Locations 网站查找可以指导其对应的国家和城市,可以在其邻近的区域中查找日志。

**这里介绍一种可以快速准确的获得函数每一次执行所在区域的方法,就是获取 AWS_REGION 环境变量,并在 Response Header 中返回。**这里的 AWS_REGION 指的是执行 Lambda 函数的 Amazon 区域。

实现方式:

如果您已经创建了用于**源响应(Origin Response)**的 Lambda 代码,则在代码中返回修改后的 response 之前添加下面这行代码:

c 复制代码
event.Records[0].cf.response.headers['execution-region'] = [{key: 'Execution-Region', value: process.env.AWS_REGION}];

左滑查看更多

如果您只创建了用于源请求(Origin Request) 的 Lambda 代码,则建议您使用以下代码创建一个用于**源响应(Origin Response)**的 Lambda 代码,并部署到 Lambda@Edge。

c 复制代码
'use strict';
exports.handler = (event, context, callback) => {
    event.Records[0].cf.response.headers['execution-region'] = [{key: 'Execution-Region', value: process.env.AWS_REGION}];
    callback(null, response);
};

左滑查看更多

下面是响应结果示例,只要能获得相应,就可以通过 response header 获悉执行函数的区域,接下来就可以在 CloudWatch 控制台中切换到该区域等待日志的出现。

注意:在发布到生产环境时,建议删除不必要的日志输出,以节约成本。如有需要,还可以禁用 Lambda 对 CloudWatch 日志输出的权限杜绝任何日志,将执行角色中的 Allow:logs:PutLogEvents 移除。

步骤五:

使用 Response Header 提升调试效率

遇到在线调试的场景,可以通过在 Response Header 中添加版本标头的方式,来确定当前请求使用的是哪个版本的代码。在每次更新代码的时候需使用新的版本号,可以参考上面代码中的 Function-Version。

调试的时候,如果想打印查看某个变量的值,可以将该变量转换为 string 类型放到 Response Header 中输出。这样可以在得到响应结果后即可查看该值,无需再到控制台中查看,大大提高效率。

该方法在Amazon CloudFront 部署小指南(四)- CloudFront Function 基础与诊断中有详细介绍,思想和方式上都非常相似,可以参考。

使用 response header 输出信息进行调试的时候,需要遵循 response header 的规范,value 必须是 string 类型,且只有 CloudFront Function 执行正常将 response 完整返回给客户端时才能看到相关信息。如果代码执行异常,中断的情况,则无法获得正常响应,此时无法通过 response header 查看调试信息,这种情况下 console.log()可以将异常中断前的日志都打印出来。我们在实际开发测试时可以结合使用。

步骤六:

查看 Lambda@Edge 资源利用率

我们可以通过 CloudWatch Logs 查看函数执行时长以及使用的内存信息。建议在发布到生产环境之前,使用 Lambda Power Tuning 进行测试,以获得最佳的内存配置。

步骤七:

CloudFront Extension 中的 Lambda@Edge 应用

上面以修改 HTTP Response 为案例介绍了 CloudFront Lambda@Edge 的开发及调试全流程,在亚马逊解决方案团队(CSDC)维护的 CloudFront Extension 项目 中还有很多代码案例,可以供大家参考学习。CloudFront Extenstion 的 Github 链接在这里:aws-cloudfront-extensions。

总结

通过本篇文章,您应该通过动手操作对 CloudFront Lambda@Edge 有了一个初步的了解。您现在已经有了一个小巧实用的 CloudFront Lambda@Edge 的调试环境,能够在这个环境中利用 CloudFront Lambda@Edge 代码按照自己的需要修改 Web 请求,并且通过 Echo-Server、CloudWatch 指标和日志观察它们的运行情况,更可以通过在 Response Header 里写入的日志头即时了解函数执行所在的区域以及程序的运行状态。

亚马逊云科技 CloudFront 部署小指南 系列文章

点击标题,即可查看往期文章:

Amazon CloudFront 部署小指南(一)- 快速构建 CDN 内容分发

Amazon CloudFront 部署小指南 (二)- 进阶部署

Amazon CloudFront 部署小指南 (三)- 持续部署

Amazon CloudFront 部署小指南(四)- CloudFront Function 基础与诊断

Amazon CloudFront 部署小指南(五)- 使用 Amazon 边缘技术优化游戏内资源更新发布

本篇作者

朱劲松

亚马逊云科技解决方案架构师,负责基于亚马逊云平台的解决方案咨询和设计,拥有 10 多年的 IT 行业工作经验,历任系统架构师、大数据总监、CTO 等职,在边缘计算、Serverless、大数据方面有丰富的实践经验。

崔俊杰

亚马逊云科技高级产品解决方案架构师,负责亚马逊云科技云边缘安全相关的服务产品。为亚马逊云用户提供 DDoS 防御/网站前端安全防御/域名安全相关的产品咨询。对 Cloudfront,Shield,WAF,Route53,Global Accelerator 等云边缘安全相关产品有深入了解。在计算机安全、数据中心和网络领域有多年的工作经验。

听说,点完下面4个按钮

就不会碰到bug了!

相关推荐
心.c10 分钟前
vue3大事件项目
前端·javascript·vue.js
姜 萌@cnblogs20 分钟前
【实战】深入浅出 Rust 并发:RwLock 与 Mutex 在 Tauri 项目中的实践
前端·ai·rust·tauri
蓝天白云下遛狗27 分钟前
google-Chrome常用插件
前端·chrome
多多*1 小时前
Spring之Bean的初始化 Bean的生命周期 全站式解析
java·开发语言·前端·数据库·后端·spring·servlet
linweidong1 小时前
在企业级应用中,你如何构建一个全面的前端测试策略,包括单元测试、集成测试、端到端测试
前端·selenium·单元测试·集成测试·前端面试·mocha·前端面经
满怀10151 小时前
【HTML 全栈进阶】从语义化到现代 Web 开发实战
前端·html
东锋1.32 小时前
前端动画库 Anime.js 的V4 版本,兼容 Vue、React
前端·javascript·vue.js
满怀10152 小时前
【Flask全栈开发指南】从零构建企业级Web应用
前端·python·flask·后端开发·全栈开发
小杨升级打怪中2 小时前
前端面经-webpack篇--定义、配置、构建流程、 Loader、Tree Shaking、懒加载与预加载、代码分割、 Plugin 机制
前端·webpack·node.js
Yvonne爱编码3 小时前
CSS- 4.4 固定定位(fixed)& 咖啡售卖官网实例
前端·css·html·状态模式·hbuilder