White Box技術部

WEB開発のあれこれ(と何か)

Puppeteerがnodeコンテナで動かなかったから動かした

Puppeteerの実行エラー

puppeteerのJestサンプルをTypeScriptで書いて動かそうとしたら、コンテナ側のライブラリ不足エラーが出たので対処していました。

エラー内容

動かそうとしたサンプルは以下で、Dockerコンテナのベースはnode:14-slimです。

これを実行すると以下のようなerror while loading shared librariesのエラーが表示されます。

エラーをメモしてなかったので、検索履歴から引っ張ってきたものですが、こんな感じのエラーが出ていました。 実際にはエラーは1つずつしか出ないので、都度apt-get installしていました。(見やすく改行や加工をしています)

error while loading shared libraries:
    libatk-bridge-2.0.so.0: cannot open shared object file: No such file or directory
    libgobject-2.0.so.0: cannot open shared object file: No such file or directory
    libnss3.so: cannot open shared object file: No such file or directory
    libasound.so.2: cannot open shared object file: No such file or directory

実行環境

動作時の主なライブラリのバージョンは以下のとおりです。

  • puppeteer: 5.3.1
  • typescript: 4.0.3
  • jest: 26.4.2
  • node: 14.11.0(コンテナ node:14-slim)

不足しているライブラリの追加

以下のようにライブラリを入れるとエラーが消えます。

apt-get install -y libgtk-3.0 libgbm-dev libnss3 libatk-bridge2.0-0 libasound2

コンテナにはbuild-essentialも入れているので、もしかしたらこれも必要かもしれません。

ライブラリ不足解消後の問題

ライブラリ不足を解消してから実行すると、今度は以下のエラーが出たので、エラーメッセージの通り、--no-sandboxを使って実行するように変更して解消しました。

Running as root without --no-sandbox is not supported. See https://crbug.com/638180

まとめ

Puppeteerをnode:14-slimのコンテナで使うためにはlibgtk-3.0 libgbm-dev libnss3 libatk-bridge2.0-0 libasound2のライブラリをOSにインストールし、 TypeScriptの場合は以下のようなコードにする必要があります。

import { beforeAll, afterAll, describe, expect, test } from '@jest/globals';
import puppeteer, { Browser, Page } from 'puppeteer';

let browser: Browser;
let page: Page;

beforeAll(async () => {
  browser = await puppeteer.launch({
    args: ['--no-sandbox']
  });
  page = await browser.newPage();
});

describe('Google Homepage', () => {
  test('has title "Google"', async () => {
    await page.goto('https://google.com', { waitUntil: 'networkidle0' });
    const title = await page.title();
    expect(title).toBe('Google');
  });

  afterAll(async () => {
    await browser.close();
  });
});

追記

そもそもこのexamples配下のコードは非推奨になっているくさく、「theheadless.devの方を見てね」みたいなことがREADMEに書かれてますね。

あとちゃんとは見てないのですが、jestでの実行は以下を使うのが良いのかもしれないです。