依赖项的处理与层的创建与注册

news2024/11/25 12:25:58

Image

依赖项的处理与层的创建与注册

  • 依赖项的处理与层的创建与注册
    • 新问题
    • 什么是 layer?
    • layer 的创建与注册
      • 与函数同时创建和绑定
      • 单独上传 layer 再绑定函数(推荐)
    • 真正的运行时依赖
      • 注册包的约定
      • 与平台强关联的运行时
        • 1. 云端安装依赖
        • 2. 本地构建 Amazon Linux 2 容器环境
        • 3. 利用 CI 构建并进行上传和部署
    • 镜像部署
    • Next Chapter
    • 完整示例及文章仓库地址

新问题

在一个 nodejs 函数里,我们往往会去安装和使用各种各样的依赖包,来辅助我们项目的开发。

这些依赖以及对应的版本都被注册在了 package.json里 (由 npm init创建)。在安装依赖之后,它们会被存放在当前项目的 node_modules 目录里。而 sls deploy 默认也会把 node_modules 里所有文件,打包压缩后,和代码一起上传到云上。这点很好理解,没有依赖项,函数压根跑不起来。

但是当我们 node_modules 依赖足够大,足够深之后,整个 node_modules 就会变成一个黑洞。随随便便就有 1GB/2GB 甚至更多,这时候去进行 sls deploy 就会变成一种折磨,因为要压缩 node_modules,这个行为耗时太长了,即使压缩好了,上传到 S3 对象存储也要花费很久的时间。

如何解决? 这时候就需要让我们的 layer(层)出场了。

什么是 layer?

layer 你可以理解成,预先放置在我们 Lambda 函数容器中的文件包,你可以在里面放一些代码,库,数据文件,配置文件甚至是一些自定义语言运行时。比如我在使用的时候,往往会把 运行时 依赖的包,打成 zip 上传上去,又或者有些爬虫函数,需要使用 chromium 来模仿用户的行为,那么这种case则需要在 layer 里面直接内置一个 headless chromium

这些文件最终都会被挂载到函数容器中的 /opt 目录。

layer 的创建与注册

这里我给出一个示例,假设运行时的依赖只有 uuid (假设我们只依赖这一个包)

我们现在项目中安装 npm i uuid 并使用它:

// index.ts
import { v4 } from 'uuid'
v4()
// ...code...

这时候 uuid 在函数package.json这一层的 node_modules 文件夹里,测试运行后,运转良好。

让我们在当前目录下,创建一个 layers 文件夹,然后再在里面创建一个 uuid(名称可自定义)文件夹,创建 package.json 并写入:

{
  "dependencies": {
    "uuid": "^9.0.0"
  }
}

layers/uuid/package.json#dependencies 字段中的 uuid 即为你主目录下安装的版本。

然后执行 npm i/yarn 安装依赖 (不要使用pnpm),安装完成后会出现 layers/uuid/node_modules 文件夹,接下来就可以 layer 的上传和绑定了。

与函数同时创建和绑定

我们可以复用原先部署函数的那个 serverless.yml 文件,让它不但部署函数,也同时创建 layer 并进行绑定。具体配置如下:

layers:
  # layer 配置
  uuid:
    # 路径
    path: layers/uuid
    # aws lambda layer 里的名称
    name: ${sls:stage}-uuid

functions:
  api:
    # ...
    package:
      individually: true
      # 既然我们把所有运行时都打成 layer 了自然不用上传 node_modules 了
      patterns:
        - "!node_modules/**"
    # layer 绑定配置
    layers:
      # 绑定 UuidLambdaLayer
      - !Ref UuidLambdaLayer
    environment:
      # 环境变量,告诉函数应该从哪里找依赖
      NODE_PATH: "./:/opt/node_modules"

其中最重要的就是2layers的配置了,其中 !Ref UuidLambdaLayer 这个其实就是引用了layers.uuid,只不过它的命名是一种约定,即 uuidu 大写加上 LambdaLayer,于是就变成了 UuidLambdaLayer 了,命名规则为 layer 名称的 Title_CaseLambdaLayer

注意!NODE_PATH: "./:/opt/node_modules" 这个环境变量是必不可少的,不然会导致无法从 layer 中加载 node_modules

相关配置的参考链接

此时使用 sls package 会在 .serverless 目录下生成 2zip:

  • api.zip 函数代码包
  • uuid.zip layer包

2个压缩包的名字,就是我们在 serverless.yml注册的名字。

sls deploy 会把它们依次上传,先layerfunction,并把layer上传部署后的结果,注册进我们的function,从而达成绑定的效果。

单独上传 layer 再绑定函数(推荐)

除了与函数同时创建和绑定的形式,我们还可以分步骤单独上传 layer 再绑定函数,这也是我推荐的方式。

这个就顾名思义,我们可以先上传layer拿到结果,在把结果写到函数的 serverless.yml 中去。这样步骤方面分为了 2 步,但是好处却是显而易见的。

它适用于这样的场景,我们的 layer 包很大,且不经常更新,这种情况是没有必要每次都去打包上传 layer 的。

我们部署只需要部署我们自己的函数代码,然后告诉 AWS 应该去绑定哪个 layer 的哪个版本就行。

按照这样的思路,我们就可以把刚刚那个 serverless.yml 拆成 2yml 文件:

  1. 单独上传 layer 配置文件
  2. 函数的 deploy 配置文件,加一行绑定 layer 的配置即可

单独部署 layer 的配置,内容如下:

# layers/serverless.yml
layers:
  uuid:
    path: uuid
    name: ${sls:stage}-uuid

执行 sls deploy 后上传部署成功会显示:

layers:
  uuid: arn:aws-cn:lambda:cn-northwest-1:000000000000:layer:dev-uuid:2

这一个字符串就是接下来我们需要写入函数 yml 配置进行绑定的关键,当然当时没保存刷了terminal也没关系,这个信息通过在当前目录执行 sls info 还会显示出来。

接下来我们去函数的 yml 配置去绑定 layers:

# serverless.yml
functions:
  api:
    # ....
    layers:
      # - !Ref UuidLambdaLayer 改为
      - arn:aws-cn:lambda:cn-northwest-1:000000000000:layer:dev-uuid:2

这样再在函数这一层执行 sls deploy 这层绑定关系就完成了,同时上传速度也要比 与函数同时创建和绑定 快不少,因为这种方法只要上传函数的代码包,再通过调用 AWS API 告诉它们这层绑定关系即可。

真正的运行时依赖

之前有一个细节没有讲,为什么我们上传 layer 是单独建一个 layers 的目录,在里面单个单个上传,而不是把外面函数的 node_modules 整个打包上传上去呢?

其实那样也可以,但是不够完美,因为这样做会导致layer代码包中的文件,过于冗余

举个简单的例子,默认情况下 npm 安装包时,会把 devDependenciesdependencies 都安装在 node_modules

比如 dependencies 里就是一些 express/lodash 啥的,devDependencies 里面就是 eslint/sass/webpack 这些开发时用的包,运行代码的时候用不着。

这时候,你直接打包上传 node_modules 显然是可以的,因为你所有的运行时依赖已经在里面了,不幸的是 eslint 等等许多无关紧要的包也进去了,这些加起来有可能会占用你 layer 包整体体积的一般以上甚至更多,显然这是没有必要的。

所以,你必须找到真正的运行时依赖!

注册包的约定

首先你必须在安装包时正确的注册 devDependenciesdependencies

我们把运行时用的到的放在 dependencies 里,到时候也从这里面抽出包名和版本,做成 layer。至于devDependencies 里我们只会把那些开发时用得到的包放在里面,它们就没有必要上传了,本地运行即可。

与平台强关联的运行时

其次你必须很清楚你的运行时是 nodejs 而不是什么浏览器。

虽然说 nodejs 是跨平台的,但是我们使用的第三方库里,有时候会存在着很多和平台强关联的二进制文件。

比如有些包会在下载下来之后,调用 postinstall 脚本获取我们的系统信息(平台,cpu架构),然后根据这些信息去使用不同的二进制文件。

又或者有些包基于 C++ addons 的,安装好之后,才在我们机器上实时去编译,生成适配我们系统平台的二进制文件。

这就导致一个问题,假如你直接用 win/macos 开发,你安装的二进制包,大概率无法在 aws lambda 环境下运行,因为它的环境是 Amazon Linux 2

所以,我们应该在挑选与线上 Lambda 运行时,相似的容器中,进行开发,上传代码和层 (layer)

具体怎么做呢?这里给出三种解决方案:

1. 云端安装依赖

顾名思义,直接在云上的目标容器环境中进行安装依赖这个行为,这也是最简单的解决方案。

2. 本地构建 Amazon Linux 2 容器环境

这要求我们在 docker 容器中开发,拉下 Amazon Linux 2 的镜像,在里面开发并上传层函数和代码包。

3. 利用 CI 构建并进行上传和部署

这个思路便是,由环境相同或者相似的 CI 容器,进行上传和部署。

比如我们可以利用 Github Action 去构建和上传,大致的配置如下:

name: Layer

on:
  workflow_dispatch:

jobs:
  upload:
    name: upload
    timeout-minutes: 15
    strategy:
      fail-fast: false
      matrix:
        # 找一个相似的镜像 os
        os: [ubuntu-latest]
        node-version: [18]
    runs-on: ${{ matrix.os }}

    steps:
      - name: Check out code
        uses: actions/checkout@v3
        with:
          fetch-depth: 2

      - name: Configure AWS credentials from Test account
        uses: aws-actions/configure-aws-credentials@v3
        with:
          aws-region: cn-northwest-1
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

      - name: Setup Node.js environment
        uses: actions/setup-node@v3
        with:
          node-version: ${{ matrix.node-version }}

      - name: Install Serverless
        run: yarn global add serverless

      - name: Install puppeteer Layer
        run: yarn
        working-directory: apps/aws-express-api-ts/layers/puppeteer

      - name: sls deploy
        run: yarn deploy
        working-directory: apps/aws-express-api-ts/layers

镜像部署

当然,假如你使用镜像去部署 lambda,那以上这些问题都可以避免,但是代价便是冷启动时间比较长。

不过很多技术上的问题,都是可以通过付出更多金钱的方式去解决的,这点就综合考虑利弊吧。

Next Chapter

现在你已经学会了 layer 的用法和一些稀奇古怪的场景。

下一篇,《lambda nodejs 函数降低冷启动时间的最佳实践》中,将会详细介绍如何优化我们自身的代码,欢迎阅读。

完整示例及文章仓库地址

https://github.com/sonofmagic/serverless-aws-cn-guide

如果你遇到什么问题,或者发现什么勘误,欢迎提 issue 给我

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/980525.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Nginx__高级进阶篇

目录 Nginx Web服务器 Nginx Proxy服务器 Nginx 邮 件 Nginx Web服务器 Nginx Proxy服务器 代理原理 正向代理:内网客户机通过代理访问互联网。通常要设置代理服务器地址和端口。 反向代理:外网用户通过代理访问内网服务器。内…

解决VSCode下载速度特别慢

背景: 我们在vscode官网下载vocode的时候速度慢得离谱,而且下载会断开,这时候我们需要将下载镜像切换到国内! 解决方法 我是用chrome浏览器,点击右上角的三个点按钮,点击下载内容。 如果你是用其他浏览器,可能使用其他方式跳…

“深入理解SpringMVC的注解驱动开发“

目录 引言1. SpringMVC的常用注解2. SpringMVC的参数传递3. SpringMVC的返回值4. SpringMVC页面跳转总结 引言 在现代的Web开发中,SpringMVC已经成为了一个非常流行和强大的框架。它提供了许多注解来简化开发过程,使得我们能够更加专注于业务逻辑的实现…

设置windos电脑开机自动启动chrome浏览器,并且打开指定网页

需求 web项目设置windos电脑开机自动启动chrome浏览器,打开指定网页地址,并设置为全屏显示 解决 使用windos的bat脚本,设置为开机自启动,代码如下 echo off cd /d %~dp0 title Chrome tasklist|find /i "chrome.exe"…

Hadoop的第二个核心组件:MapReduce框架第三节

Hadoop的第二个核心组件:MapReduce框架 九、MR程序运行的核心阶段的细节性知识1、MR程序在运行过程中,涉及到的阶段和作用2、MR程序运行的的第一个组件:InputFormat3、MR程序的Job提交流程的源码分析4、MR程序运行中Mapper组件的作用5、MR程序…

【IC设计】Chisel开发环境搭建

首先安装一个Ubuntu的虚拟机 然后给Ubuntu换个镜像,方便下载 注意换源后使用apt-get update更新下 安装vim(可以不做) 这里安装Vim是我感觉Ubuntu自带的vi编辑器似乎有问题,因为我按i进入【插入模式】并没有提示,所以…

气象监测设备中一般包括哪些设备?

气象监测设备是指用于测量和记录气象数据的设备,这些设备通常被安装在各种气象站上,用于监测对应的气象参数。 气象监测设备主要包括以下几种: 温湿度传感器:用于测量空气温度和湿度,是气象监测设备中的重要组成部分…

Linux命令200例:who用于显示当前登录到系统的用户信息

🏆作者简介,黑夜开发者,CSDN领军人物,全栈领域优质创作者✌。CSDN专家博主,阿里云社区专家博主,2023年6月csdn上海赛道top4。 🏆数年电商行业从业经验,历任核心研发工程师&#xff0…

基于网络表示学习的 新闻推荐算法研究与系统实现

摘要 第1章绪论 新闻推荐通常是利用用户的阅读行为和习惯、阅读选择和爱好等信息,为 用户推荐新闻内容。新闻推荐能够减少用户在数量庞大数据信息中获取信息的 时间消耗,从而能够缓解“信息过载[7]”的难题。以文本为内容的新闻,和商品、 电影、短视频等推荐系统相比,新闻推…

vite搭建vue3项目

参考视频 1.使用npm搭建vite项目,会自动搭建vue3项目 npm create vitelatest yarn create vite2.手动搭建vue3项目 创建一个项目名称的文件夹执行命令:npm init -y 快速的创建一个默认的包信息安装vite: npm i vite -D -D开发环境的依赖 安装vue,现在默认是vue3.…

2023年最新 wechaty 框架开发微信机器人详细 API 教程说明(NodeJs 版本)

基本概述 wechaty 基础 在使用 wechaty 相关 api 之前,请大家先学习基础篇:如何使用 wechaty 框架开发微信机器人详细教程(NodeJs 版本) 设置 script 脚本执行 在 package.json 文件中,配置 "start": &qu…

OpenWrt的内核启动分析

u-boot从Flash分区中读取Linux内核到内存,然后跳转到内存(某个地址)执行Linux内核。Linux内核会进行一系列验证,根据设备树文件(见下图openwrt/target/linux/realtek/dts-5.15/XXX.dts,)注册相关…

gma 2 教程(二)数据操作:7.矢量数据操作简介

功能逻辑架构 gma矢量数据操作类主要包括数据资源(DataSource)、矢量图层(Layer)、矢量要素(Feature)(与ogr一致,内部与ogr差异巨大),三者的示意图如下&#…

ctfshow-web-红包一

0x00 前言 CTF 加解密合集CTF Web合集网络安全知识库 文中工具皆可关注 皓月当空w 公众号 发送关键字 工具 获取 0x01 题目 0x02 Write Up 上来就丢了一个站,还有一个不怎么有用的图片。 按照常规流程,先扫目录,但是无果(工具…

Java # Java基础八股

1、JVM、JRE、JDK之间的关系 个人理解:JVM可以帮助屏蔽底层的操作系统,使程序一次编译到处都可以运行,JVM可以运行class文件。JRE是java文件运行的环境,但不能新建程序,JRE包含JVM。JDK功能最齐全,包含了编…

基于TSINGSEE青犀视频AI智能技术的自然生态水源保护管理解决方案

一、方案背景 水是生命之源,日常生产生活离不开水。围绕全面深入打好打赢碧水保卫战,针对集中式饮用水源地等野外场景碎片化的特点,迫切需要建设数字智治、闭环管理、规范高效的水质监测体系,进一步加强水源地保护工作的开展落地…

腾讯云服务器优惠价格表(2023年最新版)

腾讯云作为国内领先的云服务提供商,提供了多种规格的云服务器,满足不同用户的需求,本文将详细介绍腾讯云服务器的优惠价格,并给出相应的购买建议。 腾讯云服务器提供了多种配置和多种购买时长选择,用户可以根据实际需求…

超震撼!全网疯传的第七届世界渲染大赛创意大盘点

第七届CG挑战赛TOP100新鲜出炉!这是一场被圈内誉为“地表最强”、“全球最火”的世界渲染大赛,由拥有百万订阅的油管博主 pwnisher 发起。这次比赛的创作主题是《Boss Fight—终极决斗》,吸引了2880名创意大师和视觉艺术爱好者的参与。他们的…

【操作系统】聊聊页面置换算法

操作系统的缓存淘汰 操作系统一是提供的基础编程接口,二是实现软件治理的功能。但是因为内存是有限的,想要在有限的内存多存储数据,就利用段、页、段页方式进行数据的映射。但是内存存储有限,所以如何将内存中不用的数据进行及时…

【数据分享】2012-2022年1km分辨率全球夜间灯光时序数据(无需转发\免费获取)

夜间灯光数据是我们在各项研究中经常使用的数据!在之前的文章中我们分享了来自NCEI国家环境信息中心的2012-2022年全球范围的逐年的NPP/VIIRS夜间灯光数据(可查看之前推送的文章获悉详情)! 我们本次为大家分享的是来自中国农业大…