【问题标题】:AWS Lambda Node.js 10.x Runtime error with selenium-webdriver带有 selenium-webdriver 的 AWS Lambda Node.js 10.x 运行时错误
【发布时间】:2020-04-28 12:32:54
【问题描述】:

几天前,我们收到了有关“Lambda 操作通知”的通知,将我们的 Node.js 8.10 运行时更新为 Node.js 10.x 运行时。

为响应此通知,我们在开发系统中安装了 Node.js 版本 v10.16.3 并测试了我们现有的代码。 我们发现代码在我们的开发系统中运行良好,但是当我们在 AWS Lambda 中使用 Node.js 10.x 运行时测试相同的代码时,我们收到以下错误:

2019-10-28T12:03:31.771Z 8e2472b4-a838-4ede-bc70-a53aa41d9b79 信息错误:服务器提前终止,状态为 127 在 earlyTermination.catch.e (/var/task/node_modules/selenium-webdriver/remote/index.js:251:52) 在 process._tickCallback (internal/process/next_tick.js:68:7)

“aws-sdk”、“selenium-webdriver”npm 包和 google chrome 二进制文件是我们项目中使用的唯一依赖项。

我们的项目具有以下文件结构。

/var/task/
├── index.js
├── lib
│   ├── chrome
│   ├── chromedriver
│   ├── libgconf-2.so.4
│   ├── libORBit-2.so.0
│   └── libosmesa.so
└── node_modules
    ├── selenium-webdriver
    ├── ...

由于这段代码在我们的开发系统中没有抛出任何错误,我们怀疑它与新的运行时有关。

我们尝试使用 setChromeBinaryPath() 设置二进制路径

这是我们正在使用的代码。调用 build() 方法时发生错误。

var webdriver = require('selenium-webdriver');
var chrome = require('selenium-webdriver/chrome');
var builder = new webdriver.Builder().forBrowser('chrome');
var chromeOptions = new chrome.Options();
const defaultChromeFlags = [
    '--headless',
    '--disable-gpu',
    '--window-size=1280x1696', // Letter size
    '--no-sandbox',
    '--user-data-dir=/tmp/user-data',
    '--hide-scrollbars',
    '--enable-logging',
    '--log-level=0',
    '--v=99',
    '--single-process',
    '--data-path=/tmp/data-path',
    '--ignore-certificate-errors',
    '--homedir=/tmp',
    '--disk-cache-dir=/tmp/cache-dir'
];

chromeOptions.setChromeBinaryPath("/var/task/lib/chrome");
chromeOptions.addArguments(defaultChromeFlags);
builder.setChromeOptions(chromeOptions);

var driver = await builder.build();

【问题讨论】:

    标签: node.js selenium-webdriver aws-lambda selenium-chromedriver


    【解决方案1】:

    我们最近遇到了完全相同的问题。从 Node v8.x 升级到 AWS Lambda Node v10.x 后,chrome 和 chromedriver 停止工作。简而言之,根本原因是 Lambda Node 10.x 在 Amazon Linux 2 上运行,而 Lambda Node v8 在 Amazon Linux 上运行。与其前身相比,Amazon Linux 2 缺少许多软件包,使其更轻量级,但同时如果您想设置自定义运行时环境,这会很痛苦。在为您提供解决此问题的步骤之前,让我首先强调一些有用的链接,这些链接帮助我找到了我必须包含在我的 lambda 部署包中的正确二进制文件集。

    记住!解决此问题的方法是找出您的 Lambda 部署包中缺少哪些二进制文件并将它们添加进去。

    1. 如何在 AWS Lambda 部署包中使用 Amazon Linux 本机二进制包。一旦您知道您的 Lambda 环境中缺少一些二进制文件,AWS 的此链接将帮助您将它们包含到您的包中。出于我的目的,我使用 EC2 Amazon Linux 64 位 AMI 来下载包并解压缩它们。详细步骤如下...https://aws.amazon.com/premiumsupport/knowledge-center/lambda-linux-binary-package
    2. 除了 Amazon Linux 2 中缺少二进制文件外,还没有安装任何字体。此链接将告诉您如何在 AWS Lamda 上安装字体。 Chrome 无法在 Lambda 上运行的原因之一是缺少字体。 https://forums.aws.amazon.com/thread.jspa?messageID=776307
    3. 这是 github 上的一个很好的问题线程,它告诉我 LD_LIBRARY_PATH 环境变量中的路径顺序很重要。这是保存二进制文件所在路径的环境变量。https://github.com/alixaxel/chrome-aws-lambda/issues/37
    4. 现在这改变了游戏规则。如果没有令人惊叹的 docker 容器 lambci 创建尽可能接近地模拟 AWS Lambda,我永远也不会弄明白。在尝试了 Amazon Linux 2 EC2 服务器和 AWS Lambda 之间的各种事情之后,这最终成为了我的游乐场,在那里我可以非常快速地迭代尝试不同的包。 https://hub.docker.com/r/lambci/lambda/
    5. 在 AWS Lambda 中运行任意可执行文件。如果您想直接在 lambda 上运行可执行文件并查看其行为方式,请提供一些有用的链接。您从 selenium-webdriver 包中看到的错误消息实际上并没有显示 chrome 或 chromedriver 抛出的真正错误。尝试在 lambci docker 容器中直接运行 chrome 或 chromedriver 是我设法调试它并找出丢失的二进制文件的方法。 https://aws.amazon.com/blogs/compute/running-executables-in-aws-lambda/

    所以,这就是你需要做的:

    1. 启动 Amazon Linux 2 64 位服务器。一个 t3.micro 就足够了。
    2. SSH 到机器并安装 rmpdevtools:sudo yum install -y yum-utils rpmdevtools
    3. 创建一个临时目录用于下载丢失的包:
    4. cd /tmp
    5. mkdir lib
    6. cd lib
    7. 下载 AWS Lambda 节点 v10.x 中缺少的 RPM 包:yumdownloader --resolve GConf2 glibc glib2 libblkid libffi libgcc libmount libsepol libstdc++ libuuid pcre zlib libselinux dbus-glib mozjs17 polkit polkit-pkla-compat libX11 libX11-common libXau libxcb fontconfig expat fontpackages-filesystem freetype stix-fonts gnu-free-sans-fonts fontpackages-filesystem gnu-free-fonts-common nss nspr nss-softokn nss-softokn-freebl nss-util dbus-libs audit-libs bzip2-libs cracklib elfutils-libelf elfutils-libs libattr libcap libcap-ng libcrypt libdb libgcc libgcrypt libgpg-error libsepol lz4 pam systemd-libs xz-libs mesa-libOSMesa-devel mesa-libOSMesa mesa-libglapi sqlite
    8. 提取 RPM 包:rpmdev-extract *rpm
    9. 创建一些临时位置,用于从提取的 RPM 工件中复制二进制文件:
      • sudo mkdir -p /var/task
      • sudo chown ec2-user:ec2-user /var/task
      • cd /var/task
      • mkdir lib
      • mkdir fonts
    10. 将提取的二进制文件复制到新的临时位置:
      • /bin/cp /tmp/lib/*/usr/lib64/* /var/task/lib
      • /bin/cp /tmp/lib/*/lib64/* /var/task/lib
      • /bin/cp /tmp/lib/*/usr/share/fonts/*/*.ttf /var/task/fonts
    11. 压缩工件:zip -r ./lib.zip ./*
    12. 从服务器下载它们提取 zip 并包含您的 lambda 处理程序。此时,您应该有一个非常相似的结构,就像您在 lib 文件夹和一个新的字体文件夹中有更多二进制文件的结构一样。
    13. 在 /var/task/fonts 文件夹中包含以下配置文件“fonts.conf”:
    <?xml version="1.0"?>
    <!DOCTYPE fontconfig SYSTEM "fonts.dtd">
    <fontconfig>
      <dir>/var/task/fonts/</dir>
      <cachedir>/tmp/fonts-cache/</cachedir>
      <config></config>
    </fontconfig>
    
    1. 在您的 lambda 处理程序中添加以下代码 sn-p。这将为 LD_LIBRARY_PATH 环境变量设置正确的包含路径顺序,并将 FONTCONFIG_PATH 设置为新的 /var/task/fonts 目录。
    process.env.FONTCONFIG_PATH = `${process.env.LAMBDA_TASK_ROOT}/fonts`;
    if (process.env.LD_LIBRARY_PATH.startsWith("/var/task/lib:") !== true) {
      process.env.LD_LIBRARY_PATH = [...new Set(["/var/task/lib", ...process.env.LD_LIBRARY_PATH.split(':')])].join(':');
    }
    
    1. 在本地下载 lambci/lambda 映像。 docker pull lambci/lambda
    2. 通过运行像这样的 lambci 映像来调试 lamda 处理程序:
    docker run --rm -v "$THE_LOCAL_DIR_OF_YOUR_UNCOMPRESSED_LAMDA_PACKAGE":/var/task lambci/lambda:nodejs10.x index.handler
    
    1. 重复第 7 步到第 14 步,直到您可以在 lambci 容器上工作。使用给定的 RPM 包它应该可以工作,但如果它不能工作,您可以通过尝试在 lambda 中启动 chrome 来在本地调试正在发生的事情,如下所示:
    const childProcess = require('child_process');
    childProcess.execFileSync(`${process.env.LAMBDA_TASK_ROOT}/lib/chrome`);
    

    这是一个繁琐的过程,但归根结底,您所做的只是将更多的二进制文件添加到您的包中,并在您的处理程序中添加 3 行代码来更新 lib 和字体环境变量。

    以防万一,在下面添加我们正在使用的 chrome 标志:

    const defaultChromeFlags = [
      "--headless",
      "--disable-gpu",
      "--window-size=1280x1024",
      "--no-sandbox",
      "--user-data-dir=/tmp/user-data",
      "--hide-scrollbars",
      "--enable-logging",
      "--v=99",
      "--single-process",
      "--data-path=/tmp/data-path",
      "--ignore-certificate-errors",
      "--homedir=/tmp",
      "--disk-cache-dir=/tmp/cache-dir"
    ];
    

    祝你好运!

    【讨论】:

    • 感谢重播。我在第 12 步放弃了,这是一个繁琐的任务。所以我将项目迁移到 puppeteer。我使用 chrome-aws-lambda 包在 lambda 中运行 puppeteer。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-25
    • 2019-05-07
    • 1970-01-01
    • 1970-01-01
    • 2018-04-12
    • 2018-01-13
    相关资源
    最近更新 更多