utamt engineer blog

アプリケーション開発について学んだことの備忘録です。

Intel Macで動作するDockerのNodeアプリを Apple Silicon Mac (M1) で動かすためにやったこと

Intel Mac で動作する Dockerfile を、Apple Silicon Mac (M1) で利用したら、イメージのビルドが失敗したり、docker 内の node のアプリ (react, gatsby, puppeteer) が動作しなくなったりしたので、その際に行った対処を書き残す。

サマリ

  • node のイメージタグを *-buster に変更する。
  • xdg-utils をインストールする。
  • (puppeteer を使う場合のみ)
    • chromium をインストールする。
    • node のイメージタグを *-alpine に変更する。

元ファイル

Intel Mac では動作する Dockerfile。

FROM node:14.17.0-slim

# Localize into Japanese
RUN apt-get update \
    && apt-get install -y locales \
    && locale-gen ja_JP.UTF-8 \
    && echo "export LANG=ja_JP.UTF-8" >> ~/.bashrc

# Install Chrome (only to use for puppeteer)
RUN 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

# Install wget and curl
RUN apt-get install -y \
    wget \
    curl \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

発生したエラー

spawn xdg-open ENOENT

npx create-react-app [project name] --template typescript が完了後、npm start コマンド実行時に以下が発生。

events.js:353
      throw er; // Unhandled 'error' event
      ^

Error: spawn xdg-open ENOENT
    at Process.ChildProcess._handle.onexit (internal/child_process.js:269:19)
    at onErrorNT (internal/child_process.js:467:16)
    at processTicksAndRejections (internal/process/task_queues.js:82:21)
Emitted 'error' event on ChildProcess instance at:
    at Process.ChildProcess._handle.onexit (internal/child_process.js:275:12)
    at onErrorNT (internal/child_process.js:467:16)
    at processTicksAndRejections (internal/process/task_queues.js:82:21) {
  errno: -2,
  code: 'ENOENT',
  syscall: 'spawn xdg-open',
  path: 'xdg-open',
  spawnargs: [ 'http://localhost:3000' ]
}
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! front@0.1.0 start: `react-scripts start`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the front@0.1.0 start script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /home/node/.npm/_logs/2022-04-10T07_46_46_139Z-debug.log

一部の deb パッケージが 404 Not Found

上記エラーの xdg-openxdg-utils パッケージに内包されているので、Dockerfile に RUN apt-get install -y xdg-utils を追加してみたが、docker compose build コマンド実行時に以下が発生。

E: Failed to fetch http://security.debian.org/debian-security/pool/updates/main/o/openssl/libssl1.1_1.1.0l-1~deb9u4_arm64.deb  404  Not Found [IP: 151.101.2.132 80]
E: Failed to fetch http://security.debian.org/debian-security/pool/updates/main/o/openssl/openssl_1.1.0l-1~deb9u4_arm64.deb  404  Not Found [IP: 151.101.2.132 80]
E: Unable to fetch some archives, maybe run apt-get update or try with --fix-missing?
1 error occurred:
        * Status: The command '/bin/sh -c apt-get install -y xdg-utils' returned a non-zero code: 100, Code: 100

調べてみると、元としているイメージ node:14.17.0-slim は、debian の通称 "stretch" (Debian 9) から作られているが、debian の現在の安定版は "buster" (Debian 10) とのこと。

https://www.debian.org/releases/index.ja.html

ついでに node のバージョンもアップデートしたいので、イメージとして node:16.14.2-buster-slim を選択してみた。

https://hub.docker.com/_/node

再度 docker compose build を実行するとエラーは出ず、npm start で問題なくアプリが起動した。

chrome がインストールできない

Puppeteer を実行するためにはコンテナに chrome をインストール必要があるが、docker compose build コマンド実行時に以下が発生。

E: Package 'google-chrome-stable' has no installation candidate

現状、arm64 Linux 用の Chrome は存在しない模様。代わりに chromium を使う必要があるとのこと。

https://askubuntu.com/questions/1383789/install-chrome-on-ubuntu-debian-with-arm64

そこで、Dockerfile を以下のように書き換えて、

...

# Install Chrome (only to use for puppeteer)
RUN apt-get install -y chromium chromium-browser

...

再度 docker compose build コマンド実行すると以下が発生。

E: Package 'chromium-browser' has no installation candidate

これに対して、snap コマンドを使ってインストールする方法がありそうだが、debianChromium を動かすことがあまり推奨されていないとのこと。

https://forum.pine64.org/showthread.php?tid=12497

特に Debian であることに拘りも無いため、alpine 版の node に chromium を追加して利用することにした。こちらは以下の追加のみで、pupeteer が問題なく動作した。

FROM node:16.14.2-alpine3.14

RUN apk add chromium

...

変更後のファイル

Docker on Apple Silicon Mac (M1) で動作確認済み。

通常用

FROM node:16.14.2-buster-slim

RUN apt-get update \
    && apt-get install -y locales \
    && locale-gen ja_JP.UTF-8 \
    && echo "export LANG=ja_JP.UTF-8" >> ~/.bashrc

# 追加部分
RUN apt-get install -y xdg-utils

RUN apt-get install -y \
    wget \
    curl \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

Puppeteer 用

# apt系 (Debian) から apk系 (alpine) に全面書き換え
FROM node:16.14.2-alpine3.14

ENV TZ=Asia/Tokyo
ENV LANG=C.UTF-8

RUN apk update \
    && apk add chromium \
    && apk add bash tzdata wget curl