【问题标题】:Can't run Bazel nodejs_image with Puppeteer (Error: libgobject-2.0.so.0)无法使用 Puppeteer 运行 Bazel nodejs_image(错误:libgobject-2.0.so.0)
【发布时间】:2021-09-27 14:39:38
【问题描述】:

我正在使用 Bazel 构建 Docker 容器:

ts_config(
    name = "tsconfig",
    src = "tsconfig.lib.json",
)

ts_project(
    name = "lib",
    srcs = ["index.ts"],
    declaration = True,
    tsconfig = "tsconfig",
    deps = [
        "@npm//@types/node",
        "@npm//puppeteer",
    ],
)

nodejs_binary(
    name = "server",
    data = [
        "lib",
    ],
    entry_point = "index.ts",
)

nodejs_image(
    name = "image",
    binary = "server",
)

运行nodejs_binary 工作正常。

但是运行nodejs_image“image”会抛出错误:

(node:44) UnhandledPromiseRejectionWarning: Error: Failed to launch the browser process!
/app/server.runfiles/node_puppeteer/node_modules/puppeteer/.local-chromium/linux-901912/chrome-linux/chrome: error while loading shared libraries: libgobject-2.0.so.0: cannot open shared object file: No such file or directory

TROUBLESHOOTING: https://github.com/puppeteer/puppeteer/blob/main/docs/troubleshooting.md

因此,我尝试像这样添加自定义 basethis 一个)图像:

nodejs_image(
    name = "base_image",
    base = "@nodejs_puppeteer//image",
    binary = "server",
)

WORKSPACE:

load("@io_bazel_rules_docker//container:container.bzl", "container_pull")

container_pull(
    name = "nodejs_puppeteer",
    digest = "sha256:22ec485fa257ec892efc2a8b69ef9a3a2a81a0f6622969ffe2d416d2a076214b",
    registry = "docker.io",
    repository = "drakery/node-puppeteer:latest",
)

但是运行更新的nodejs_image"base_image",会抛出这个错误:

[link_node_modules.js] An error has been reported: [Error: EACCES: permission denied, symlink '/app/server.runfiles/npm/node_modules' -> 'node_modules'] {
  errno: -13,
  code: 'EACCES',
  syscall: 'symlink',
  path: '/app/server.runfiles/npm/node_modules',
  dest: 'node_modules'
} Error: EACCES: permission denied, symlink '/app/server.runfiles/npm/node_modules' -> 'node_modules'

如何将缺少的依赖项添加到nodejs_image

可以在此处找到该问题的最小重现:https://github.com/flolu/bazel-node-puppeteer

【问题讨论】:

    标签: node.js docker puppeteer bazel bazel-rules-nodejs


    【解决方案1】:

    这是使用rules_nodejs 构建本机依赖项的长期问题。

    本机依赖项是在您的主机上构建和链接的。构建的版本由nodejs_image 复制到容器镜像中,但是像libgobject-2.0.so.0 这样的共享库的位置在镜像中通常与在您的开发机器上不同。

    对此没有通用的解决方案,但这里有一些可能的解决方法:

    1. 在映像的入口点运行 npm rebuild 这应该重建原生模块并根据运行容器中的共享库位置重新链接它们。缺点是它会增加你的容器启动时间,而且不一定适用于所有情况。环境特定的东西仍然可以从主机平台泄漏。

    2. 根本不要从主机复制node_modules而是在容器启动时运行npm installyarn。如果仅在容器启动时运行 npm rebuild 不能满足您的需要,这可能是必要的。但是,它会进一步增加启动时间。

    3. 严格控制您的开发环境,使其与您用于nodejs_image 的基本映像相匹配。例如,要求所有开发工作都在 Ubuntu 20.04 上进行,并使用与您所有nodejs_image 目标的基本映像。或者更进一步,使用相同的基础映像将您的开发环境容器化,然后在该容器中进行开发。

    最后一个选项是我在实践中实际所做的。我们的开发人员虚拟机运行与我们用作所有构建映像的基础的操作系统完全相同的操作系统,因此一切都“正常工作”。

    【讨论】:

    • 感谢您的全面回答,Rohan。解决方法 1 和 2 不是一个选项,因为 Bazel (rules_nodejs) 在后台处理这些事情。选项 3 听起来不错。我尝试使用与我的开发系统(Ubuntu 20.04)相同的基本映像。但我收到此错误:standard_init_linux.go:228: exec user process caused: exec format error。有任何想法吗?你可以自己试试:github.com/flolu/…
    • @FlorianLudewig 我认为他的意思是您使用基于 ubuntu 的 nodejs 映像,也许使用 this 或类似的 dockerfile 作为基础
    • 您可以使用 nodejs_image 目标作为层来构建 container_image。这就是您可以自定义入口点以添加诸如npm rebuild 之类的内容的方式。
    • 要解决 exec 格式问题等其他问题,请使用 docker CLI 检查构建的映像并查看它实际尝试运行的内容。我的猜测是,基于 Ubuntu 的映像正在尝试直接 exec 一个 JS 脚本。
    【解决方案2】:

    根据@Rohan Singh@Noam Yizraeli 的建议,我尝试将自定义基础映像更改为我的开发环境。 因此,我使用 Ubuntu 创建了一个 Docker 映像,它是基础,并安装了 Node.js 和 Chrome:

    FROM ubuntu:20.04
    
    # Install Node.js
    RUN apt-get update \
      && apt-get install -y curl
    RUN curl --silent --location https://deb.nodesource.com/setup_14.x | bash -
    RUN apt-get install --yes nodejs
    RUN apt-get install --yes build-essential
    
    # Install Chrome
    ENV DEBIAN_FRONTEND=noninteractive
    RUN apt-get update \
      && apt-get install -y wget gnupg \
      && wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \
      && sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' \
      && apt-get update \
      && apt-get install -y google-chrome-stable fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-kacst fonts-freefont-ttf libxss1 \
      --no-install-recommends \
      && rm -rf /var/lib/apt/lists/*
    

    我是这样在 Bazel 中拉出来的:

    load("@io_bazel_rules_docker//container:container.bzl", "container_pull")
    
    container_pull(
        name = "ubuntu",
        digest = "sha256:a1ceb3aac586b6377821ffe6aede35c3646649ee5ac38c3566799cd04745257f",
        registry = "docker.io",
        repository = "drakery/node-puppeteer",
    )
    

    并像这样使用它:

    nodejs_image(
        name = "custom_ubuntu",
        base = "@ubuntu//image",
        binary = "server",
    )
    

    这是最终的工作存储库:https://github.com/flolu/bazel-node-puppeteer/tree/050376d36bccb67a93933882a459f0af3051eabd

    【讨论】:

    • 如果您想更进一步,rules_docker 中有实验性的dockerfile_build 规则。您可以使用它来构建基础映像作为 Bazel 运行的一部分。但是,它需要一个工作的 Docker 安装并且不是密封的。
    • @RohanSingh 很乐意这样做!但我无法让它工作:从这个分支运行yarn bazelisk run //:bazel_ubuntugithub.com/flolu/bazel-node-puppeteer/tree/docker-bazel 不起作用。你有什么想法吗?
    • 那仍然使用container_image作为基础镜像。我的意思是将dockerfile_image 添加到您的WORKSPACE 以构建您的Dockerfile 基本映像。示例:github.com/bazelbuild/rules_docker/blob/…
    猜你喜欢
    • 2021-05-10
    • 2021-04-17
    • 2021-12-19
    • 2016-03-20
    • 1970-01-01
    • 1970-01-01
    • 2011-11-04
    • 2012-09-03
    • 1970-01-01
    相关资源
    最近更新 更多