Serverless 简明教程

Serverless - Layer Creation

What are layers?

层是一种隔离代码块的方法。假设你要在应用程序中导入 NumPy 库。你信任该库,几乎不可能更改该库的源代码。因此,如果你不喜欢 NumPy 的源代码会让你的应用程序工作区混乱,那么你就不会喜欢它。粗略地说,你只想让 NumPy 放在别处,与你的应用程序代码隔离。层允许你执行此操作。你只需将所有依赖项(NumPy、Pandas、SciPy 等)捆绑到一个单独的层中,然后在 serverless 中的 lambda 函数中引用该层。太棒了!该层中捆绑的所有库现在都可以导入到你的应用程序。与此同时,你的应用程序工作区始终保持井井有条。你只需查看应用程序代码进行编辑。

Layers are a way of isolating code blocks. Say you want to import the NumPy library in your application. You trust the library and there’s hardly any chance that you will be making changes in the source code of that library. Therefore, you won’t like it if the source code of NumPy clutters your application workspace. Speaking very crudely, you would simply want NumPy to sit somewhere else, isolated from your application code. Layers allow you to do exactly that. You can simply bundle all your dependencies (NumPy, Pandas, SciPy, etc.) in a separate layer, and then simply reference that layer in your lambda function within serverless. And boom! All the libraries bundled within that layer can now be imported into your application. At the same time, your application workspace remains completely uncluttered. You simply see the application code to edit.

layers

Iva RajovicUnsplash 上的照片表示在层中分离代码

Photo by Iva Rajovic on Unsplash, indicative of code separation in layers

层真正的优点是它们可以跨函数共享。假设你使用包含 NumPy 和 Pandas 的 python-requirements 层部署了一个 lambda 函数。现在,如果另一个 lambda 函数需要 NumPy, 你无需为此函数部署一个单独的层。你可以简单地使用前一个函数的层,它也可以与新函数协同工作。

The really cool thing about layers is that they can be shared across functions. Say you deployed a lambda function with a python-requirements layer that contains NumPy and Pandas. Now, if another lambda function requires NumPy, you need not deploy a separate layer for this function. You can simply use the layer of the previous function and it will work well with the new function as well.

这将为你节省大量部署宝贵时间。毕竟,你只部署应用程序代码。依赖项已经存在于一个现有的层中。因此,多个开发人员将依赖项层保存在一个单独的堆栈中。然后他们在此层中使用所有其他应用程序。通过这种方式,他们不必一次又一次地部署依赖项。毕竟,依赖项相当繁重。NumPy 库本身大约有 80 MB 大小。每当你对应用程序代码(可能只有几 KB)进行更改时,部署依赖项将非常不方便。

This will save you a lot of precious time during deployment. After all, you will be deploying only the application code. The dependencies are already present in an existing layer. Therefore,several developers keep the dependencies layer in a separate stack. They then use this layer in all other applications. This way, they don’t need to deploy the dependencies again and again. After all, the dependencies are quite heavy. NumPy library itself is approx. 80 MB large. Deploying dependencies every time you make changes to your application code (which may measure just a few KBs) will be quite inconvenient.

添加一个依赖项层只是一个例子。还有其他一些用例。例如, serverless.com 上给出的示例涉及使用 FFmpeg 工具创建 GIF。在该示例中,他们将 FFmpeg 工具存储在层中。总而言之,AWS Lambda 允许我们为每个函数添加最多 5 个层。唯一的条件是这 5 个层与应用程序的总大小应小于 250 MB。

And adding a dependencies layer is just one example. There are several other use-cases. For example, the example given on serverless.com concerns the creation of GIFs using the FFmpeg tool. In that example, they have stored the FFmpeg tool in a layer. In all, AWS Lambda allows us to add a maximum of 5 layers per function. The only condition is that the total size of the 5 layers and the application should be less than 250 MB.

Creating python-requirements layer

现在让我们看看如何使用 serverless 创建和部署包含所有依赖项的层。要做到这一点,我们需要 serverless-python-requirements 插件。此插件仅适用于 Serverless 1.34 及更高版本。因此,如果你拥有低于 1.34 的版本,你可能需要升级你的 Serverless 版本。你可以使用以下命令安装插件 −

Now let’s see how the layer containing all the dependencies can be created and deployed using serverless. To do that, we need the serverless-python-requirements plugin.This plugin only works with Serverless 1.34 and above. So you may want to upgrade your Serverless version if you have a version <1.34. You can install the plugin using −

sls plugin install -n serverless-python-requirements

接下来,你在 serverless.yml 的插件部分添加此插件,并在自定义部分中提及其配置 −

Next, you add this plugin in the plugins section of your serverless.yml, and mention it’s configurations in the custom section −

plugins:
   - serverless-python-requirements
custom:
   pythonRequirements:
      dockerizePip: true
      layer: true

在这里, dockerizePiptrue 启用 docker 的使用并允许你将所有依赖项打包到一个 docker 容器中。我们在上一章中讨论了使用 docker 打包。 layertrue 告诉 serverless python 要求应存储在一个单独的层中。现在,此时你可能想知道 serverless 如何理解要打包哪些依赖项?如插件章节中所述,答案就在 requirements.txt 文件中。

Over here, dockerizePiptrue enables the usage of docker and allows you to package all the dependencies in a docker container. We’ve discussed about packaging using docker in the previous chapter. layertrue tells serverless that the python requirements should be stored in a separate layer. Now, at this point, you may be wondering that how does serverless understand which dependencies to package? The answer, as mentioned in the plugins chapter, lies in the requirements.txt file.

在定义了层插件和自定义配置后,你可以将层添加到 serverless 中的各个函数中,如下所示 −

Once the layer plugin and custom configurations have been defined, you can add the layer to your individual functions within serverless as follows −

functions:
   hello:
      handler: handler.hello
      layers:
         - { Ref: PythonRequirementsLambdaLayer }

关键字 PythonRequirementsLambdaLayer 来自 CloudFormation Reference 。通常,它从层的名称派生而来。语法为“LayerNameLambdaLayer”(大写,没有空格)。在我们的例子中,由于层名称是 python requirements,所以引用变为 PythonRequirementsLambdaLayer。如果你不确定 lambda 层的名称,你可以按照以下步骤获取它 −

The keyword PythonRequirementsLambdaLayer comes from the CloudFormation Reference.In general, it is derived from the layer’s name. The syntax is 'LayerNameLambdaLayer' (TitleCased, without spaces). In our case, since the layer name is python requirements, the reference becomes PythonRequirementsLambdaLayer. If you aren’t sure about the name of your lambda layer, you can get it in the following steps −

  1. Run sls package

  2. Open .serverless/cloudformation-template-update-stack.json

  3. Search for 'LambdaLayer'

Using an existing layer from another function in the same region

正如我在开头提到的,层的一大优点是能够在你的函数中使用现有层。通过使用现有层的 ARN 可以轻松地完成此操作。使用 ARN 将现有层添加到函数的语法非常简单 −

Like I mentioned in the beginning, a really cool thing about layers is the ability to use existing layers in your function. This can be done easily by using the ARN of your existing layer.The syntax to add an existing layer to a function using the ARN is quite straightforward −

functions:
   hello:
      handler: handler.hello
      layers:
         - arn:aws:lambda:region:XXXXXX:layer:LayerName:Y

就是这样。现在具有指定 ARN 的层将与你的函数一起工作。如果该层包含 NumPy 库,则你可以继续在你的“hello”函数中调用 import numpy 。它将毫无错误地运行。

That’s it. Now the layer with the specified ARN will work with your function. If the layer contains the NumPy library, you can simply go ahead and call import numpy in your 'hello' function. It will run without any error.

如果你想知道从哪里可以获得 ARN,其实很简单。只需导航到 AWS 控制台中包含该层的函数,然后单击“层”。

If you are wondering from where you can get the ARN, it is quite simple actually. Simply navigate to the function containing the layer in the AWS Console, and click on 'Layers'.

layerarn

当然,如果该层不属于你的帐户,那么它需要公开共享或专门与你的帐户共享。稍后对此进行更多介绍。

Of course, if the layer doesn’t belong to your account, then it either needs to be publicly shared or shared specifically with your account. More on that later.

此外,请记住该层应与你的应用程序兼容。不要期望与 python3.6 运行时中创建的函数一起运行与 node.js 运行时兼容的层。

Also, keep in mind that the layer should be compatible with your application. Don’t expect a layer compatible with node.js runtime to run with a function created in python3.6 runtime.

Non-requirements/ generic layers

如开头所述,层的主要功能是隔离你的代码块。因此,它们不必仅包含依赖项。它们可以包含你指定的任何代码段。在 custom 中的 pythonRequirements 内调用 layer: trueserverless-python-requirements 插件实现的一种快捷方式。但是,要创建一个通用层,serverless.yml 中的语法,如 serverless docs 中所述,如下所示 −

As mentioned in the beginning, the layers serve the main function of isolating your code blocks. Therefore, they don’t need to contain just dependencies. They can contain any piece of code that you specify. Calling layer: true within pythonRequirements within custom is a kind of a shortcut made possible by the serverless-python-requirements plugin. However, to create a generic layer, the syntax within serverless.yml, as explained in the serverless docs, is as follows −

layers:
   hello:
      path: layer-dir # required, path to layer contents on disk
      name: ${opt:stage, self:provider.stage, 'dev'}-layerName # optional, Deployed Lambda layer name
      description: Description of what the lambda layer does # optional, Description to publish to AWS
      compatibleRuntimes: # optional, a list of runtimes this layer is compatible with
         - python3.8
      licenseInfo: GPLv3 # optional, a string specifying license information
      # allowedAccounts: # optional, a list of AWS account IDs allowed to access this layer.
      #   - '*'
      # note: uncommenting this will give all AWS users access to this layer unconditionally.
      retain: false # optional, false by default. If true, layer versions are not deleted as new ones are created

由于提供了注释,因此各种配置参数不言自明。除了“path”之外,所有其他属性都是可选的。path 属性是你希望从应用程序代码中隔离的所选目录的路径。它将被压缩并作为你的层发布。例如,在 example project on serverless 中,他们在层中托管 FFmpeg 工具,他们在名为“layer”的单独文件夹中下载此工具并将其指定在 path 属性中。

The various configuration parameters are self-explanatory thanks to the comments provided. Except for the 'path', all other properties are optional. The path property is a path to a directory of your choice that you want to be isolated from your application code. It will be zipped up and published as your layer. For instance, in the example project on serverless, where they host the FFmpeg tool in a layer, they download the tool in a separate folder called 'layer' and specify that in the path property.

layers:
   ffmpeg:
      path: layer

如前所述,我们可以在 layers 属性内添加多达 5 层。

As told before, we can add up to 5 layers within the layers − property.

为了在函数中使用这些通用层,再次强调,你可以使用 CloudFormation 引用或指定 ARN。

To use these generic layers in your functions, again, you can use either the CloudFormation reference or specify the ARN.

Allowing other accounts to access layers

只需在“allowedAccounts”属性中提及帐号就可让更多帐号访问你的层。例如 −

More accounts can be provided access to your layer by simply mentioning the account numbers in the 'allowedAccounts' property. For example −

layers:
   testLayer:
      path: testLayer
      allowedAccounts:
         - 999999999999 # a specific account ID
         - 000123456789 # a different specific account ID

如果你希望该图层公开可访问,则可以在 allowedAccounts 中添加“*” −

If you want the layer to be publicly accessible, you can add '*' in allowedAccounts −

layers:
   testLayer:
      path: testLayer
      allowedAccounts:
      - '*'