使用--no-sandbox参数运行无头Chrome/Puppeteer

29

背景

我开发了一个使用 Puppeteer 的应用程序,它运行在我的本地主机上。现在我想把它部署到 Debian 环境中,但是运行 Puppeteer 的脚本超时了。经过调查我意识到这是一个普遍的问题。大多数 Debian 环境都缺少运行 Chromium 所需的依赖项。

问题

我在这里找到了一些使用 Docker 运行应用程序的推荐方法。

我可以使用 Docker 运行应用程序,但是一旦我将 Chrome 特定数据添加到我的 Docker 文件中,就会出现一些错误。

无法移动到新名称空间:PID 名称空间和网络名称空间已支持,但失败:errno = 操作不允许

建议在 Docker 文件中创建一个用户并以该用户身份运行应用程序。但是,当我添加该用户时,该用户会出现上述错误。

然后,当我尝试以 root 用户身份运行应用程序时,会出现一个新错误:

不支持以根身份运行而不使用 --no-sandbox。

虽然不建议这样做,但我想尝试使用 --no-sandbox 运行应用程序以查看它是否正常工作。

示例

我一直像这样运行应用程序:

docker run -p 3000:3000 user/app-name

Docker文件
FROM ubuntu:16.04

# Application parameters and variables
ENV NODE_ENV=production
ENV PORT=3000
ENV Root_Dir /
ENV application_directory /usr/src/app
ENV font_directory /usr/share/fonts/noto

# Configuration for Chrome
ENV CONNECTION_TIMEOUT=60000
ENV CHROME_PATH=/usr/bin/google-chrome

RUN mkdir -p $application_directory
RUN mkdir -p $font_directory

# Dependencies needed for packages downstream
RUN apt-get update && apt-get install -y \
  apt-utils \
  unzip \
  fontconfig \
  locales \
  gconf-service \
  libasound2 \
  libatk1.0-0 \
  libc6 \
  libcairo2 \
  libcups2 \
  libdbus-1-3 \
  libexpat1 \
  libfontconfig1 \
  libgcc1 \
  libgconf-2-4 \
  libgdk-pixbuf2.0-0 \
  libglib2.0-0 \
  libgtk-3-0 \
  libnspr4 \
  libpango-1.0-0 \
  libpangocairo-1.0-0 \
  libstdc++6 \
  libx11-6 \
  libx11-xcb1 \
  libxcb1 \
  libxcomposite1 \
  libxcursor1 \
  libxdamage1 \
  libxext6 \
  libxfixes3 \
  libxi6 \
  libxrandr2 \
  libxrender1 \
  libxss1 \
  libxtst6 \
  ca-certificates \
  fonts-liberation \
  libappindicator1 \
  libnss3 \
  lsb-release \
  xdg-utils \
  wget

# It's a good idea to use dumb-init to help prevent zombie chrome processes.
ADD https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64 /usr/local/bin/dumb-init
RUN chmod +x /usr/local/bin/dumb-init

# Install Node.js
RUN apt-get install --yes curl &&\
  curl --silent --location https://deb.nodesource.com/setup_8.x | bash - &&\
  apt-get install --yes nodejs &&\
  apt-get install --yes build-essential

# Install emoji's
RUN cd $font_directory &&\
  wget https://github.com/emojione/emojione-assets/releases/download/3.1.2/emojione-android.ttf &&\
  wget https://github.com/googlei18n/noto-cjk/blob/master/NotoSansCJKsc-Medium.otf?raw=true && \
  fc-cache -f -v

RUN apt-get update && apt-get install -y wget --no-install-recommends \
    && 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-unstable fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-kacst ttf-freefont \
        --no-install-recommends \
    && rm -rf /var/lib/apt/lists/* \
    && apt-get purge --auto-remove -y curl \
    && rm -rf /src/*.deb

# Cleanup
RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

# Install puppeteer so it's available in the container.
RUN npm i puppeteer

# Add user so we don't need --no-sandbox.
RUN groupadd -r pptruser && useradd -r -g pptruser -G audio,video pptruser \
   && mkdir -p /home/pptruser/Downloads \
   && chown -R pptruser:pptruser /home/pptruser \
   && chown -R pptruser:pptruser /node_modules

RUN cd $application_directory

WORKDIR $application_directory

# Install app dependencies
COPY package.json .

# Bundle app source
COPY . .

# Build
RUN npm install

USER pptruser

# Expose the web-socket and HTTP ports
EXPOSE 3000
ENTRYPOINT ["dumb-init", "--"]
CMD ["google-chrome-unstable", "npm", "start"]

问题

如何运行Docker并传递参数?

--no-sandbox

怎么样才能让参数允许我在 root 下运行?

或者说,我需要在当前的 Docker 文件中做哪些改变,这样我就可以将其作为用户 pptruser 运行呢?

当前存在的问题 -

以什么身份运行?

USER pptruser

无法移动到新的命名空间:支持PID命名空间,支持网络命名空间,但失败了:errno = 操作不允许

以以下身份运行:

root

不支持以 root 用户身份运行,如果没有使用 --no-sandbox 选项。

你尝试过使用 sudo sysctl -w kernel.unprivileged_userns_clone=1 命令来启用沙盒吗? - Skippy le Grand Gourou
1
这对Alpine用户来说不是一个选项。有什么解决方式吗?@SkippyleGrandGourou - Oxycash
@Oxycash 抱歉,我不了解Alpine,也已经有两年没有使用Puppeteer了。此外,我不明白为什么我在这里评论,因为我的评论似乎完全与主题无关,因为OP在问题标题中明确提到他们想要在没有沙盒的情况下运行。 - Skippy le Grand Gourou
4个回答

38

我遇到了类似的问题,尝试在Alpine Docker容器中运行Chromium headless,看起来很多其他人也有同样的问题(例如这里这里)。--no-sandbox选项是一个简单的解决方法,但显然是一种不良安全实践。对我起作用的是设置自定义的seccomp

下载这个文件(如果感兴趣,可以看作者的笔记这里)。然后在启动Docker时传递选项--security-opt seccomp=path/to/chrome.json,或者在您使用的docker-compose.yml中指定相同的选项。


1
有人找到了docker-compose的特定配置选项吗? - Tobias Mühl
4
有关docker-compose的示例,请参见此处。请注意,相对路径是相对于您的工作目录而不是yaml文件。 - usethe4ce
16
这个解决方案现在已经有6年了。有人找到了“更好”的替代方案吗? - c4k

22
在您的Node.js代码中,当您启动浏览器时,可以传递 --no-sandbox 参数。
例如:
const launchBrowser = async () => {
  puppetBrowser = await puppeteer.launch({
    args: ['--no-sandbox'],
    timeout: 10000,
  });
};

5
这是一个巨大的安全漏洞。 - Isaiah Norton
8
请问在以非root用户身份运行的Docker容器中,情况是否也一样? - Cyril N.
1
一个恶意网站有可能接管docker容器。虽然这不是世界末日,但攻击者将能够访问docker容器内的任何代码和数据。 - Civilian
1
@IsaiahNorton 为什么这是一个安全漏洞?你有什么替代方案吗?你是否有更好的想法或不同的参数来增加安全性? - GeorGios
@IsaiahNorton 这是因为木偶正在访问互联网,可能会被攻击吗? - rolling_codes

8

背景

我是原帖发布者。几个月过去了,我继续看到很多人在互联网上遇到类似的问题,包括Github和SO。因此,我想向大家展示我如何解决这个问题。

问题

在Debian上运行Puppeteer时,由于缺少库而失败。

解决方案

通过使用Docker文件并向Puppeteer添加配置选项,我能够成功地运行该应用程序。

示例

Docker文件

FROM node:8
ENV HOST 0.0.0.0
EXPOSE 8080
RUN apt-get update

# for https
RUN apt-get install -yyq ca-certificates
# install libraries
RUN apt-get install -yyq libappindicator1 libasound2 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 libnss3 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6
# tools
RUN apt-get install -yyq gconf-service lsb-release wget xdg-utils
# and fonts
RUN apt-get install -yyq fonts-liberation

RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY . /usr/src/app
RUN mkdir -p /usr/src/app/views

# install the necessary packages
RUN npm install

CMD npm run start

Puppeteer

const browser = await puppeteer.launch({
          args: ['--no-sandbox', '--disable-setuid-sandbox'],
          ignoreHTTPSErrors: true,
          dumpio: false
        });

希望这能帮到你。基本上,当你运行应用程序时,你需要通过配置Docker文件来安装缺失的库,然后在你的应用程序运行时,传递给Puppeteer对象的配置选项将允许你的应用程序在Debian上运行。


7

无需超时设置,

const browser = await puppeteer.launch({headless: true, args:['--no-sandbox']});


注:本文涉及it技术相关内容。

我并没有直接使用Puppeteer库,这让我实现任务变得困难,但不知何故,您的答案帮助我找到了与Node HTML-to-Image库有关的问题,并成功解决了它。 - Pragyanshu Sharma

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