Node.js + OpenCV の Dockerイメージを作成してアプリで利用する
概要
Node.js で OpenCV を使いたいという要件が発生した。現在動いている Node のアプリではベースイメージに node:14.15.3-slim
を利用していたため、こちらに OpenCV を追加して利用できる環境を整えることが望ましかった。軽量化やバージョンによって揃えるものが違かったり、公式通りうまくいかずと割とはまる部分があったので備忘として残しておく。
対象のモジュールは下記。
モジュール・バージョン | リンク | |
---|---|---|
ベースイメージ | node:14.15.3-slim |
https://hub.docker.com/_/node?tab=tags&page=1&ordering=last_updated&name=14.15.3-slim |
OpenCV | 4.5.2 |
https://github.com/opencv/opencv/releases/tag/4.5.2 |
ライブラリ | opencv4nodejs@5.6.0 |
https://www.npmjs.com/package/opencv4nodejs |
ゴール
Dockerを用いたNodeアプリでopencv4nodejs
ライブラリが使えるようになる
結論
下記Dockerfile
からDockerイメージを作成し、レジストリにpushしておく。このときopencv4nodejs
ライブラリをイメージ内でインストールしておく。
FROM node:14.15.3-slim
ENV OPENCV_VERSION 4.5.2
ENV OPENCV4NODEJS_DISABLE_AUTOBUILD=1
RUN apt-get update && \
apt-get install -y --no-install-recommends \
build-essential cmake git ca-certificates libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* && \
git clone https://github.com/opencv/opencv.git -b ${OPENCV_VERSION} --depth=1 && \
cd opencv && \
mkdir build && \
cd build && \
cmake_flags="-D CMAKE_BUILD_TYPE=RELEASE \
-D BUILD_EXAMPLES=OFF \
-D BUILD_DOCS=OFF \
-D BUILD_TESTS=OFF \
-D BUILD_PERF_TESTS=OFF \
-D BUILD_JAVA=OFF \
-D BUILD_opencv_apps=OFF \
-D BUILD_opencv_aruco=OFF \
-D BUILD_opencv_bgsegm=OFF \
-D BUILD_opencv_bioinspired=OFF \
-D BUILD_opencv_ccalib=OFF \
-D BUILD_opencv_datasets=OFF \
-D BUILD_opencv_dnn_objdetect=OFF \
-D BUILD_opencv_dpm=OFF \
-D BUILD_opencv_fuzzy=OFF \
-D BUILD_opencv_hfs=OFF \
-D BUILD_opencv_java_bindings_generator=OFF \
-D BUILD_opencv_js=OFF \
-D BUILD_opencv_img_hash=OFF \
-D BUILD_opencv_line_descriptor=OFF \
-D BUILD_opencv_optflow=OFF \
-D BUILD_opencv_phase_unwrapping=OFF \
-D BUILD_opencv_python3=OFF \
-D BUILD_opencv_python_bindings_generator=OFF \
-D BUILD_opencv_reg=OFF \
-D BUILD_opencv_rgbd=OFF \
-D BUILD_opencv_saliency=OFF \
-D BUILD_opencv_shape=OFF \
-D BUILD_opencv_stereo=OFF \
-D BUILD_opencv_stitching=OFF \
-D BUILD_opencv_structured_light=OFF \
-D BUILD_opencv_superres=OFF \
-D BUILD_opencv_surface_matching=OFF \
-D BUILD_opencv_ts=OFF \
-D BUILD_opencv_xobjdetect=OFF \
-D BUILD_opencv_xphoto=OFF \
-D CMAKE_INSTALL_PREFIX=/usr/local"; \
cmake $cmake_flags .. && \
make -j $(nproc) && \
make install && \
sh -c 'echo "/usr/local/lib" > /etc/ld.so.conf.d/opencv.conf' && \
ldconfig && \
cd ../../ && \
npm install -g opencv4nodejs@5.6.0 --unsafe-perm && \
rm -rf opencv && \
apt-get purge -y build-essential cmake git ca-certificates && \
apt-get autoremove -y --purge
上記イメージをベースイメージとし、opencv4nodejs
をアプリから利用する。
FROM fastlabel/fastlabel-application-api:0.1.1
WORKDIR /usr/src/api
COPY package.json ./
COPY yarn.lock ./
RUN yarn install
COPY . .
EXPOSE 4000
CMD ["/bin/sh", "entrypoint.sh"]
import * as cv from "/usr/local/lib/node_modules/opencv4nodejs";
// use cv
ざっくり解説
RUN instructionに関しては、OpenCVの公式とopencv4nodejsが提供するDockerfileを参考に書いた。一部うまくいかない部分があったのでOpenCVのv4.2.0の公式も参考にした。
ざっと下記のような構成になっている。
- OpenCVのインストールに必要なパッケージのインストール
- OpenCVのインストール
-
opencv4nodejs
をグローバルにインストール
ビルド時間を短くする工夫
git clone
OPENCV_VERSION
でOpenCVのバージョンを4.5.2
に指定し、Gitでクローンしてくる際に-b ${OPENCV_VERSION}
でタグを指定することで、必要なソースだけを取得する。
また、--depth=1
とすることで、shallow cloneを行い履歴を1つだけ、つまり最新版のみをダウンロードする。
これによってクローンサイズは 483.26MB から 83.40MB まで軽減されるため、それだけビルド時間は速くなる。
自動ビルドの抑制
今回は自分でOpenCVをビルドしているので、opencv4nodejs
付属の自動ビルドをOPENCV4NODEJS_DISABLE_AUTOBUILD=1
止めておく必要がある。
こうしておかないとOpenCVのビルドに7分かかる場合は2倍の14分かかってしまう。
ちなみに下記のように付属の自動ビルドをONにしてシンプルにやってもみたが意図したビルド成果物ができず泣く泣く諦めた。
FROM node:14.15.3-slim
ENV OPENCV4NODEJS_AUTOBUILD_OPENCV_VERSION 4.5.2
RUN apt-get update && \
apt-get install -y --no-install-recommends \
git cmake ca-certificates build-essential && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* && \
npm install -g opencv4nodejs@5.6.0 --unsafe-perm && \
apt-get purge -y git cmake ca-certificates build-essential
イメージを軽量にする工夫
ここら辺は基本的にベストプラクティスに則っている。
-
apt-get clean
で、apt-get install
によって、キャッシュされている全てのdebファイル(apt用のパッケージファイル)を削除 -
apt-get purge -y build-essential cmake git ca-certificates
で、ビルドに使用したパッケージを削除 -
apt-get autoremove -y --purge
で、apt-get update
で更新に伴い必要なくなったパッケージを削除 -
rm -rf opencv
で、ビルドに使用したGitプロジェクトを削除
参考
Dockerfile Tips
Dockerfile のベストプラクティス
なぜイメージ化しておくのか
イメージ化しておかないと、各開発者が最初のビルドでOpenCVのビルドに7分かかり絶対にイラついてしまうから。
イメージを一掃してクリーンな環境に戻したい、という気持ちになったときに遠慮なく実行してもらえないのは開発効率を下げてしまう。
opencv4nodejs
をイメージ内でインストールしておくのか
なぜpackage.json
に opencv4nodejs
を記述した状態で、ローカル開発の際に npm install
や yarn add
をして他のライブラリをインストールしたいとする。
この際 package.json
のチェックが入り、OpenCVがローカルにないためにインストールに失敗してしまう。これを防ぐためにイメージ内であらかじめインストールしておく。
どちらにせよ、ローカル開発においてはローカルにOpenCVがない限り開発に支障をきたすが、OpenCVによる開発担当以外も全員ローカルにOpenCV環境を作らなければならない状態は避けたほうがいい。
ただしグローバルにインストールしているのでアプリ側で import
する場合は下記のようにしなければならないので注意。
import * as cv from "/usr/local/lib/node_modules/opencv4nodejs";
Discussion