当前位置: 首页 > news >正文

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

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}-uuidfunctions:api:# ...package:individually: true# 既然我们把所有运行时都打成 layer 了自然不用上传 node_modules 了patterns:- "!node_modules/**"# layer 绑定配置layers:# 绑定 UuidLambdaLayer- !Ref UuidLambdaLayerenvironment:# 环境变量,告诉函数应该从哪里找依赖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: uuidname: ${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: Layeron:workflow_dispatch:jobs:upload:name: uploadtimeout-minutes: 15strategy:fail-fast: falsematrix:# 找一个相似的镜像 osos: [ubuntu-latest]node-version: [18]runs-on: ${{ matrix.os }}steps:- name: Check out codeuses: actions/checkout@v3with:fetch-depth: 2- name: Configure AWS credentials from Test accountuses: aws-actions/configure-aws-credentials@v3with:aws-region: cn-northwest-1aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}- name: Setup Node.js environmentuses: actions/setup-node@v3with:node-version: ${{ matrix.node-version }}- name: Install Serverlessrun: yarn global add serverless- name: Install puppeteer Layerrun: yarnworking-directory: apps/aws-express-api-ts/layers/puppeteer- name: sls deployrun: yarn deployworking-directory: apps/aws-express-api-ts/layers

镜像部署

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

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

Next Chapter

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

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

完整示例及文章仓库地址

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

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

相关文章:

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

依赖项的处理与层的创建与注册 依赖项的处理与层的创建与注册 新问题什么是 layer?layer 的创建与注册 与函数同时创建和绑定单独上传 layer 再绑定函数(推荐) 真正的运行时依赖 注册包的约定与平台强关联的运行时 1. 云端安装依赖2. 本地构建 Amazon Linux 2 容器环境3. 利用…...

Linux CentOS7 系统中添加用户

在linux centOS7系统中,添加用户是管理员的基本操作。作为学习linux系统的基本操作,对添加用户应该多方面了解。 添加用户的命令useradd,跟上用户名,就可以快速创建一个用户。添加一些选项,可以设置更人性化的用户信息…...

八、任务状态

1、任务状态简介 (1)任务状态可以简单的分为运行和非运行。 (2)非运行状态可以细分为:阻塞状态、暂停状态、就绪状态。 2、阻塞状态(Blocked) (1)举例说明:在日常生活的例子中,母亲在电脑前跟同事沟通时,如果同事一直没回复&a…...

基于python的反爬虫技术的研究设计与实现

摘 要 当下的网络是复杂的,网络上的信息非常的丰富,但也造成了大量的信息堆积,特别是大量的重复信息被反复的推送给用户。这是一个流量的时代,很多社会群体都会聚焦具备流量潜力的信息,从而发生蹭热度等行为来提升自己…...

msvcr120.dll放在哪里?怎么修复msvcr120.dll文件

当您在运行某些应用程序或游戏时遇到“msvcr120.dll缺失”错误时,这可能会影响您的使用体验。msvcr120.dll是Microsoft Visual C Redistributable的一部分,并且它提供了程序运行所需的运行时支持,今天我们来讨论一下msvcr120.dl文件缺失了要怎…...

Ubuntu搭建NFS服务

# 服务器初始化步骤 ## 查看磁盘 fdisk -l ## 格式化磁盘,后面的盘符注意对应关系 mkfs.ext4 /dev/sdc ## 新建文件夹 mkdir /mnt/nfs ## 挂载磁盘到创建的文件夹 echo "/dev/sdc /mnt/nfs ext4 defaults 0 0" >> /etc/fstab ## 重新挂载所有分区…...

PHP教学质量评估系统Dreamweaver开发mysql数据库web结构php编程计算机网页代码

一、源码特点 PHP教学质量评估系统是一套完善的web设计系统,对理解php编程开发语言有帮助,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。 代码 https://download.csdn.net/download/qq_41221322/88301983 论文 https://down…...

ElementUI浅尝辄止15:Table 表格

用于展示多条结构类似的数据,可对数据进行排序、筛选、对比或其他自定义操作。 Table组件比较常用,常见于数据查询,报表页面,用来展示表格数据。 1.如何使用? //当el-table元素中注入data对象数组后,在el-t…...

配置LVS_DR模式以及nginx负载均衡

一、配置LVS--DR模式: yum install ipvsadm 配置 LVS 负载均衡服务 ( 1 )手动添加 LVS 转发 1 )用户访问: www.uolookking.com-->vip 192 .168.79.110 ##> 这个是在 DNS 配置 hzitedu 域的 DNS 记录设置 w…...

虚拟数字人直播软件实现带货功能,成为新一代直播风口!

随着短视频带货市场的不断发展,虚拟数字人直播技术逐渐成为热门话题。而在现如今的市场趋势下直播带货则成为了一种火热的营销方式。那么,虚拟数字人直播软件是否可以结合起来,实现无人直播带货的效果呢?让我们来了解一下。 灰豚数…...

01背包问题暴力解法(回溯法)和经典解法

暴力解法(回溯法) import java.util.Arrays; import java.util.Scanner;public class Main {private final static int N 999;public static int SumValue 0;public static int SumWeight 0;public static int OptimalValue 0;public static int O…...

K8S的CKA考试环境和题目

CKA考试这几年来虽然版本在升级,但题目一直没有大的变化,通过K8S考试的方法就是在模拟环境上反复练习,通过练习熟悉考试环境和考试过程中可能遇到的坑。这里姚远老师详细向大家介绍一下考试的环境和题目,需要详细资料的同学请在文…...

docker清理

1. 查看docker 磁盘占用 docker system df 2. 参考: Docker磁盘占用与清理问题_docker system prune_蓝鲸123的博客-CSDN博客...

队列和栈两种数据结构的区别和Python实现

队列和栈是两种数据结构,其内部都是按照固定顺序来存放变量的,二者的区别在于对数据的存取顺序 栈是最后存入的数据最先取出,即后进先出 队列是先存入的数据最先取出,即先进先出 Python实现栈 使用append()方法存入数据,使用pop()方法读取数据 # 定义一个空列表(当做栈使…...

java 企业工程管理系统软件源码+Spring Cloud + Spring Boot +二次开发+ MybatisPlus + Redis

鸿鹄工程项目管理系统 Spring CloudSpring BootMybatisVueElementUI前后端分离构建工程项目管理系统 1. 项目背景 一、随着公司的快速发展,企业人员和经营规模不断壮大。为了提高工程管理效率、减轻劳动强度、提高信息处理速度和准确性,公司对内部工程管…...

使用Smartctl脚本输入当前所有磁盘的状态

一、安装Smartctl yum install smartmontools 二、写一个脚本输出当前所有磁盘的状态并且按名称分别写入到文件中 #!/bin/bashfor dev in $(lsblk -l | grep disk | awk {print $1}) doecho "检测磁盘 $dev"smartctl -a /dev/$dev > $dev.smartctl done 以下是这…...

数学建模之插值法

目录 1 插值法概述2 插值法原理3 拉格朗日插值4 牛顿插值5 三次Hermite插值(重点)6 三次样条插值(重点)7 各种插值法总结8 n 维数据的插值9 插值法拓展10 课后作业 1 插值法概述 数模比赛中,常常需要根据已知的函数点进…...

rhcsa学习2(vim、创建管理用户、组等)

创建、查看和编辑文本文件 重定向符号 > 进程使用称为文件描述符的编号通道来获取输入并发送输出。所有进程在开始时至少要有三个文件描述符。如果程序打开连接至其他文件的单独连接,则可能要使用更大编号的文件描述符 上述通过通道1去写入,且写入的文…...

【使用教程】Github(自用)

1.下载Git⼯具 使在windows 命令⾏下边可以输⼊这两个命令: gitssh-keygen 2.配置git信息: 在命令⾏⾥输⼊: $ git config --global user.name “你在Github上注册的账号” $ git config --global user.email 你在Github上注册的邮箱 3. c…...

typeScript学习笔记(一)

学习资源来自: 类与接口 TypeScript 入门教程 (xcatliu.com) 一.TypeScript的安装和运行 1.安装TypeScript 通过npm(Node.js包管理器)安装Visual Studio的TypeScript插件:(Visual Studio 2017和Visual Studio 2015 Update 3默认包含了Ty…...

浅谈 React Hooks

React Hooks 是 React 16.8 引入的一组 API,用于在函数组件中使用 state 和其他 React 特性(例如生命周期方法、context 等)。Hooks 通过简洁的函数接口,解决了状态与 UI 的高度解耦,通过函数式编程范式实现更灵活 Rea…...

地震勘探——干扰波识别、井中地震时距曲线特点

目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波:可以用来解决所提出的地质任务的波;干扰波:所有妨碍辨认、追踪有效波的其他波。 地震勘探中,有效波和干扰波是相对的。例如,在反射波…...

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法

树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作,无需更改相机配置。但是,一…...

UDP(Echoserver)

网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法:netstat [选项] 功能:查看网络状态 常用选项: n 拒绝显示别名&#…...

【机器视觉】单目测距——运动结构恢复

ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛&#xf…...

【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表

1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...

从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)

设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile,新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...

【单片机期末】单片机系统设计

主要内容:系统状态机,系统时基,系统需求分析,系统构建,系统状态流图 一、题目要求 二、绘制系统状态流图 题目:根据上述描述绘制系统状态流图,注明状态转移条件及方向。 三、利用定时器产生时…...

SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题

分区配置 (ptab.json) img 属性介绍: img 属性指定分区存放的 image 名称,指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件,则以 proj_name:binary_name 格式指定文件名, proj_name 为工程 名&…...

【 java 虚拟机知识 第一篇 】

目录 1.内存模型 1.1.JVM内存模型的介绍 1.2.堆和栈的区别 1.3.栈的存储细节 1.4.堆的部分 1.5.程序计数器的作用 1.6.方法区的内容 1.7.字符串池 1.8.引用类型 1.9.内存泄漏与内存溢出 1.10.会出现内存溢出的结构 1.内存模型 1.1.JVM内存模型的介绍 内存模型主要分…...