如何创建可插拔的Golang应用程序并从AWS Lambda Layers中受益。

Golang-为什么值得关注?

Golang是Google开发和实施的一种开源编程语言。 它在现代应用程序中非常广泛地使用,尤其是在云中。 它们是最有特色的功能:

  • Golang是静态编写的-灵活性较差,但可以保护您免受错误的侵害,
  • 它不是面向对象的。 但是,您可以创建结构和接口,这将导致4个OOP原则中的3个:数据抽象,封装和多态。 所缺少的就是继承
  • Goroutines! -我曾经使用过的轻线程的最佳实现。 使用go运算符,您可以轻松创建新线程并通过不同goroutine之间的通道进行通信。
  • 它被编译成具有所有依赖性的单个二进制文件-不再有软件包冲突!

就个人而言,我认为Golang是我每天使用的最出色的语言。 但是,本文与创建您的第一个函数或打印“ Hello World”无关。 我将向您展示一些更高级的内容。 如果您是初学者,并且想了解有关Golang的更多信息,请访问主页。

AWS Lambda和Golang

AWS Lambda是公共云中最受欢迎的无服务器计算服务之一,由Amazon Web Services于2014年11月发布。 您可以运行代码来响应DynamoDB,SNS或HTTP触发器等事件,而无需设置或管理服务器! 你知道什么真的很棒吗? 自2018年1月以来,它一直在支持Golang任期。 使用AWS Lambda真的很容易-只需上载带有代码和所有依赖项的压缩包(如果使用Golang,则为单个二进制文件)。

快进,四年后的2018年,re:Invent AWS发布了Lambda Layers,使您可以存储和管理在一个甚至多个AWS账户中为各种功能共享的数据! 例如,如果您使用的是Python,则可以将所有依赖项放在一个附加层中,以后可以供其他lambda使用。 不再需要为每个压缩包添加不同的依赖项! 在Golang世界中,情况有所不同,因为AWS Lambda需要上传已编译的二进制文件。 我们如何从AWS Lambda层中受益? 答案很简单-使用Golang插件构建模块化应用程序!

Golang插件-一种构建模块化应用程序的方法

Golang插件是Go1.8中发布的功能,可让您动态加载共享库(.so文件)。 您可以选择将某些代码导出到单独的库中,也可以使用其他人创建和编译的插件。 但是,令人鼓舞的是存在一些限制:

  • 您的插件必须是单个主模块,
  • 您只能加载导出为ELF符号的函数和变量。
  • 由于是静态类型,因此必须将每个加载的符号转换为正确的类型。 在最坏的情况下,您需要在代码中定义正确的接口,
  • 它仅适用于Linux和MacOS。 就我个人而言,我并不认为这是不利的:)

创建并测试您的第一个插件

现在,让我们创建第一个插件。 作为示例,我们将创建一个用于字符串加密的简单模块。 让我们回到基础,并实现两种简单的加密算法-Ceasar和Verman。

  • 凯撒密码是朱利叶斯·塞斯(Julius Ceases)最初使用的算法。 它将文本中的每个字母移动指定的位数。 例如,如果要使用密钥4加密单词golang,将得到ktpek。 解密的工作方式相同。 您所要做的就是将字母向相反方向移动。
  • 基于相同的转换思想,Verman密码类似于Ceaser密码。 区别在于您将每个字母移动不同的位数。 为了解密文本,您需要具有加密文本位置的密钥。 例如,如果您想用密钥[-1、4、7、20、4,-2 -2]加密golang一词,那么您将获得成功。

此示例的完整实现可在此处找到。

插件实现

以下代码段包含上述两种算法的实现。 对于每种方法,我们实现两种加密和解密文本的方法:

如您所见,我们在这里导出了3个不同的符号(Golang仅导出这些以上述字母开头的标识符):

  • EncryptCeasar-func(整数,字符串)使用Ceasar算法对文本进行加密的字符串。
  • DecryptCeaser-func(整数,字符串)使用Caeser算法解码文本的字符串,
  • VermanCipher-vermanCipher类型的变量,它实现2种方法:加密:func(字符串)字符串和解密:func()(*字符串,错误)

要编译此插件,您需要运行以下命令:

去构建-buildmode = plugin -o plugin / cipher.so plugin / cipher.go

现在没有什么特别的-仅创建了几个简单的函数,并通过添加-buildmode = plugin参数将模块编译为插件。

加载并测试插件

当我们想在应用程序中使用编译后的插件时,乐趣就开始了。 让我们创建一个简单的示例:

首先,您需要导入Golang插件包。 它仅包含两个功能-第一个功能是加载共享库,第二个功能是查找导出的符号。 要加载您的库,您必须使用Open函数,必须为此函数指定共享插件的路径和类型的插件的返回变量。 如果无法加载该库(例如路径错误或文件损坏),则此函数将返回需要处理的错误。

下一步是使用查找方法加载每个导出的符号。 一个小缺点是您必须分别加载每个导出的函数。 但是,您可以采用与VermanCipher符号相同的方式组合多个功能。 加载所有要使用的符号后,需要将它们转换为正确的类型。 Golang是一种静态类型的语言,因此没有其他方法可以不强制转换地使用这些符号。 请记住,如果要导出实现某些方法的变量,则必须将其强制转换为正确的接口类型(我必须定义encryptionEngine接口来处理此问题)。 \换行\换行

使用以下命令来编译和运行该应用程序:

去构建app.go ./app

在输出中,您应该看到加密和解密的文本,作为算法正常运行的证据。

在AWS Lambda中使用插件

为了在AWS Lambda中使用我们的插件,我们需要在应用程序中进行一些更改:

  • AWS Lambda在Lambda容器的/ opt目录中挂载层,因此我们必须从此目录加载插件。
  • 我们需要创建一个处理程序函数,Lambda引擎将使用该函数来处理测试事件。

以下代码段包含我们的应用程序,该应用程序已被改编以供Lambda使用:

如您所见,实现与上一个非常相似。 我们只是更改了加载插件的目录,并添加了函数响应,而不是打印出值。 有关使用Golang编写lambda的更多信息,请参阅AWS文档。

AWS Lambda部署

部署AWS Lambda函数和层有两种方法。 您可以手动创建和上载压缩包,也可以使用高级框架,这将使它变得更加容易和快捷。 对于我的大多数项目,我使用无服务器框架。 因此,我已经使用此工具准备了简单的配置文件serverless.yml:

服务:cipherService framework版本:“> = 1.28.0 <2.0.0”提供程序:名称:aws运行时:go1.x
层:cipherLayer:路径:bin / plugin兼容的运行时:-go1.x
函数:引擎:处理程序:bin / cipherEngine软件包:排除:-./**包括:-./bin/cipherEngine层:-{Ref:CipherLayerLambdaLayer}

在层区域中,我们定义了一个单层,其中包含已创建的插件路径-该层与Lambda函数一起提供。 您最多可以定义5个不同的级别,其顺序非常重要。 它们安装在相同的/ opt目录中,因此编号较大的图层可以覆盖先前安装的图层中的文件。 对于每个级别,您必须至少指定2个参数:具有级别源的目录的路径(在您的情况下,是插件二进制文件的路径)以及兼容的运行时列表。

下一个功能部分是定义要实现的功能列表的地方。 对于每个函数,您至少必须指定已编译应用程序的路径。 另外,我们需要参考上面定义的层来定义layer参数。 在部署过程中,这将自动将图层添加到我们的Lambda函数中。 有趣的是,如果要引用此资源,则必须将Lambda图层名称转换为TitleCased,并添加LambdaLayer后缀。 似乎无服务器团队以这种方式实现了它,以解决有关不同类型资源的冲突。

我们的配置文件serverless.yml准备就绪后,您要做的最后一件事就是编译,插入并部署我们的应用程序。 为此,我们可以使用简单的makefile:

.PHONY:Build BuildPlugin干净部署
构建:dep secure -v env GOOS = Linux go构建-ldflags =“ -s -w” -o bin / cipherEngine cipherEngine / main.go
buildPlugin:env GOOS = Linux go build -ldflags =“-s -w” -buildmode =插件-o bin / plugin / cipher.so ../plugin/cipher.go
清洁:rm -rf ./bin ./vendor Gopkg.lock
deploy:clean buildPlugin build sls deploy --verbose

您可以通过运行以下命令来构建和部署功能:

提供

试用AWS Lambda

如前所述,AWS Lambda代码在对事件的响应中运行。 但是,我们尚未配置任何事件触发器,因此在没有我们帮助的情况下无法调用它们。 我们必须使用无服务器框架或awscli工具手动进行操作:

sls调用-f函数名称aws lambda调用-函数名称函数名称输出文件

在答案中,您应该看到与以前相同的输出,这证明我们的lambda函数可以正常工作,并且插件可以从额外的层加载。 现在,您可以创建使用同一层的其他功能,甚至与其他AWS账户共享它。

概要

使用Golang模块并测试如何将它们与新发布的AWS Lambda Layers集成在一起非常有趣。 插件库确实很棒,但是由于其限制和Golang规范,它只能在某些情况下使用。 我认为对于大多数从事标准项目的开发人员来说,不需要甚至不可能使用插件。 我只能想到两个原因:

  • 实现可以由其他应用程序使用的复杂算法,例如 视频编码或加密算法。
  • 与他人共享您的算法,而无需发布代码。