如何在AWS Lambda上安装PhantomJS?

5
我发现了一个4年前的项目,该项目旨在在Lambda上安装PhantomJS,但可能是我操作有误,或者自从这个仓库创建以来,事物已经发生了变化,导致它不再有效。当我克隆并部署这个仓库时,尝试运行PhantomJS会出现以下错误:

{
  "errorType": "Error",
  "errorMessage": "write EPIPE",
  "code": "EPIPE",
  "stack": [
    "Error: write EPIPE",
    "    at WriteWrap.afterWrite [as oncomplete] (net.js:779:14)"
  ],
  "errno": "EPIPE",
  "syscall": "write"
}

{
  "errorType": "Error",
  "errorMessage": "html-pdf: Received the exit code '127'\n./phantomjs_lambda/phantomjs_linux-x86_64: error while loading shared libraries: libfreetype.so.6: cannot open shared object file: No such file or directory\n",
  "stack": [
    "Error: html-pdf: Received the exit code '127'",
    "./phantomjs_lambda/phantomjs_linux-x86_64: error while loading shared libraries: libfreetype.so.6: cannot open shared object file: No such file or directory",
    "",
    "    at ChildProcess.respond (/var/task/node_modules/html-pdf/lib/pdf.js:121:31)",
    "    at ChildProcess.emit (events.js:189:13)",
    "    at Process.ChildProcess._handle.onexit (internal/child_process.js:248:12)"
  ]
}

如果我使用最新的Linux二进制文件而不是与此存储库一起提供的文件,则会出现有关不同但类似的错误,指出缺少不同的.so文件。
为了背景,我想安装phantomjs是因为我想在我的lambda中使用node html-pdf library
我使用的是Mac。
作为答案,我不是要解决这个具体的错误,只是要找到一个能在AWS Lambda上运行的可用的phantomjs。如果有另一个不需要phantomjs工作并且可以轻松在AWS Lambda上运行的节点“html to pdf” /“html to png”库,那也是可以接受的解决方案。

似乎使用Docker可能是您使用本地应用程序的最佳选择。 - Luis Estevez
你尝试过安装phantom-prebuilt吗? - Luis Estevez
谢谢@Kane,但我认为这并没有帮助,因为我的库是硬编码使用phantomjs的。 - Daniel Kaplan
你有考虑使用 Puppeteer 进行 PDF 转换/截图吗?由于它得到了积极的维护,Lambda 支持可能比 Phantom 更好。https://github.com/RafalWilinski/serverless-puppeteer-layers - m90
@m90 我没有。我们正在服务器上生成一个HTML文件,然后尝试将其转换为PDF。不确定是否会引入问题。 - Daniel Kaplan
显示剩余2条评论
2个回答

39

一种解决方案是将PhantomJS所需的库包含在Lambda函数的.zip文件中。我将把这个过程分解为几个步骤。

确定需要包含哪些库

您的错误信息表明缺少共享库。让我们通过在Docker容器中安装PhantomJS并检查其运行时依赖项来确定它确切地正在寻找什么。 nodejs10.x AWS Lambda Runtime使用Amazon Linux 2,但较早的运行时步骤类似。

在您的主机系统上,运行Amazon Linux 2 Docker容器:

$ docker run -it --rm amazonlinux:2.0.20190508
在容器中安装PhantomJS并检查其依赖项:
bash-4.2$ yum install -y bzip2 tar
bash-4.2$ curl -LO https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-2.1.1-linux-x86_64.tar.bz2
bash-4.2$ tar xf phantomjs-2.1.1-linux-x86_64.tar.bz2
bash-4.2# ldd ./phantomjs-2.1.1-linux-x86_64/bin/phantomjs 
        linux-vdso.so.1 (0x00007ffdd251f000)
        libz.so.1 => /lib64/libz.so.1 (0x00007f35d0439000)
        libfontconfig.so.1 => not found
        libfreetype.so.6 => not found
        ...

我们可以看到缺少libfontconfig和libfreetype库。

安装这些库

接下来,我们将下载并提取所需的库,然后将它们复制到主机系统中。请注意,libfontconfig依赖于libexpat,因此我们也会安装它。

在容器中:

bash-4.2$ yum install -y yum-utils rpmdevtools
bash-4.2$ cd /tmp
bash-4.2$ yumdownloader fontconfig.x86_64 freetype.x86_64 expat.x86_64
bash-4.2$ rpmdev-extract *.rpm

将库复制到一个目录中:

bash-4.2$ mkdir -p /deps
bash-4.2$ cp /tmp/*/usr/lib64/* /deps

同时复制fontconfig配置文件:

bash-4.2$ cp /tmp/*/etc/fonts/fonts.conf /deps

接下来,在主机上获取Docker容器的ID,并将文件从容器复制到主机。下面的lambda-node-phantom是您克隆https://github.com/TylerPachal/lambda-node-phantom存储库的目录:

$ cd lambda-node-phantom
$ docker ps
$ docker cp <CONTAINER_ID>:/deps/ .
$ mv deps/* . && rmdir deps

更新Lambda

将您目录中的PhantomJS二进制文件更新为上面Docker容器中下载的版本。确保index.js引用了最新版本的正确名称;在2.1.1版本中,它的名称为phantomjs

接下来,在index.js中添加以下行,以便fontconfig可以在Lambda根目录中找到fonts.conf

process.env['FONTCONFIG_PATH'] = process.env['LAMBDA_TASK_ROOT'];

最后,重新创建Lambda函数的.zip文件,包括本地库和font.conf

$ zip -y /path/to/lambda-node-phantom-dist.zip .

-y选项将符号链接存储为链接,而不是引用的文件。为了节省空间,请确保.git目录未包含在.zip文件中。

测试Lambda函数

在AWS Lambda控制台中,上传新的Lambda函数.zip文件并测试Lambda函数。PhantomJS现在应该可以无错误运行,并且您的函数应该返回"hello from phantom!"如果没有,则检查PhantomJS子进程返回的stderr以获取信息。

很可能您需要修改fonts.conf并/或包含其他字体文件以使字体正确呈现。


不错!原来这个库使用phantomjs-prebuilt而不是只有phantomjs。当我在/node_modules/phantomjs-prebuilt/bin上运行ldd phantomjs时,它显示“不是动态可执行文件”。虽然我对C不太了解,但您知道为什么执行预构建文件会查找.so文件吗?你所列出的步骤是否会有显著不同? - Daniel Kaplan
@Diego,我在这里有这些文件 https://github.com/naeemshaikh27/phantom-lambda-fontconfig-pack - Naeem Shaikh
@Diego,请检查一下你的HTML使用了哪种字体,或者检查一下计算出来的字体族,如果没有指定的话,它可能是Times New Roman。还有一件事,如果你没有使用Lambda层,那么请更改font..conf文件以正确设置路径,同时环境变量也应该正确指向。在我的情况下,我创建了一个名为nodejs的文件夹,它是Lambda层,在其中创建了一个名为fonts的文件夹,并在其中放置了我在git上共享的所有内容。所以我的路径是opt/nodejs/fonts。 - Naeem Shaikh
你有默认字体吗?因为我不使用字体,无法检查 PDF 字体。 - Diego
在解决依赖和字体问题后,我可以获得正确的图像(png、jpg),但pdf无法正常工作。有人遇到过没有生成pdf的情况吗?我的环境:aws Lambda,node 12(基本上任何节点都会得到相同的结果)。我在lambda容器中进行了全局搜索,但找不到该文件。 - Yurii Maksimov
显示剩余12条评论

2
根据您的日志错误,看起来您的Lambda执行运行时缺少libfreetype.so.6。
您可能需要创建一个自定义Lambda层,嵌入此共享库。之后,您可能需要更新LD_LIBRARY_PATH,以便它也指向共享库所在的目录。或者,您也可以将其包含在Lambda部署包中。
根据AWS官方文档:
要在层中包含库,请将它们放置在运行时支持的文件夹之一中。 全部 - bin(PATH),lib(LD_LIBRARY_PATH)
链接在这里:https://docs.aws.amazon.com/lambda/latest/dg/configuration-layers.html 请确保嵌入了专为Amazon Linux(或Amazon Linux 2)编译的libfreetype.so.6。
执行运行时在这里:https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html 祝你好运!

谢谢,这很有帮助。在设置了LD_LIBRARY_PATH之后,我能够生成PDF,但是我得到的只是一个没有任何文本的PDF,只有边框等样式。 - Naeem Shaikh
@NaeemShaikh 你解决了那个问题吗?我也遇到了同样的问题,PDF正在渲染但字体没有显示出来。 - Tom Nijs
1
@TomNijs 你需要添加字体,我在这里编译了一个需要完成的列表:https://github.com/naeemshaikh27/phantom-lambda-fontconfig-pack - Naeem Shaikh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接