【问题标题】:How do you install phantomjs on AWS lambda?你如何在 AWS lambda 上安装 phantomjs?
【发布时间】:2019-11-09 17:50:00
【问题描述】:

我找到了一个应该在 lambda 上安装 phantomjs 的 4 year old project,但要么我做错了,要么自从创建了 repo 后事情发生了变化,它不再起作用。当我克隆和部署此存储库时,尝试运行 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 二进制文件而不是这个 repo 附带的二进制文件,我会收到一个不同但类似的错误,即缺少不同的 .so 文件。

对于上下文,我想安装 phantomjs 的原因是因为我想在我的 lambda 中使用节点 html-pdf library

我在 Mac 上。

作为答案,我不希望通过这个特定的错误来发现下一个错误。我正在寻找一个能让我在 aws lambda 上工作的 phantomjs 的答案。如果有另一个节点“html 到 pdf”/“html 到 png”库不需要 phantomjs 即可工作并轻松在 AWS Lambda 上运行,那也是一个可以接受的解决方案。

【问题讨论】:

  • 似乎使用 docker 可能是使用本机应用程序的最佳选择
  • 你试过安装 phantom-prebuilt 吗?
  • @LuisEstevez 我在 Mac 上。我将如何以可以在 lambda linux 操作系统上运行的方式安装 phantom-prebuilt?
  • Phantom 相当老旧且不稳定。您可能尝试使用 puppet-chrome 代替,您可以查看 this guide
  • 感谢@Kane,但我认为这没有帮助,因为我的库被硬编码为使用 phantomjs。

标签: node.js amazon-web-services aws-lambda


【解决方案1】:

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

确定要包含哪些库

您的错误消息指出缺少共享库。让我们通过将 PhantomJS 安装在 Docker 容器中并检查其运行时依赖关系来准确找到它正在寻找的内容。 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 选项将符号链接存储为链接而不是引用的文件。为了节省空间,请确保 .zip 文件中不包含 .git 目录。

测试 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 文件吗?您概述的步骤是否会有很大不同?
  • phantomjs-prebuilt/bin/phantomjs 是一个运行可执行文件的脚本。可执行文件本身实际上是phantomjs-prebuilt/lib/phantom/bin/phantomjs
  • 这很有趣。我不知道。我今天要try试试这个。感谢您的帮助:)
  • 也许你的回答有一些我不理解的上下文,但我将process.env['LD_LIBRARY_PATH'] = path.join(process.env['LAMBDA_TASK_ROOT'], '...');设置为一个步骤,但你没有提到它。
  • 根据我的经验,我不必使用LAMBDA_TASK_ROOT 中的.so 文件显式设置LD_LIBRARY_PATH,即/var/task。如果您看到不同的行为,可以尝试将文件移动到 lib。我认为$LAMBDA_TASK_ROOT/lib 默认在LD_LIBRARY_PATH 中。
【解决方案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,只有边框等样式
  • @NaeemShaikh 你有没有解决过这个问题?我在呈现 PDF 但字体不显示的同一点。
  • @TomNijs 你需要添加字体,我在这里整理了一份需要做的事情:github.com/naeemshaikh27/phantom-lambda-fontconfig-pack
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-15
  • 2016-04-11
相关资源
最近更新 更多