LoginSignup
4
5

More than 5 years have passed since last update.

Dockerのnpm installをnode_modulesのシムリンクとボリュームを使って効率化する

Posted at

Node.jsアプリのDockerイメージを作っているとpackage.jsonのnpm installのときにnode-gypによるネイティブモジュールのビルドが走ることがあります。Node.jsのコードやDockerfileの構成を変更するたびにビルドされて長いときは数分かかります。なにか良い方法がないかググっているとnpm package.json and docker (mounting it…)という記事を見つけました。このソリューションを使っていまビルドに時間がかかっているMeshbluのDockerイメージ作成を修正します。

Meshblu

IoTプラットフォームのMeshbluは内部でMQTTブローカーにMoscaを使い、LebelDBなどのネイティブモジュールのビルドに時間がかかります。またMeshbluのリポジトリのはDockerfileのままではビルドに失敗してしまいます。いくつか修正しながらnode_modulesを効率的にビルドできるようにしていきます。まずgit cloneしてデフォルトのディレクトリ状態を確認します。

$ cd ~/docker_apps
$ git clone https://github.com/octoblu/meshblu.git
$ cd meshblu
$ tree -L 1
.
├── Dockerfile
├── LICENSE
├── README.md
├── app.json
├── app.yml
├── config.js
├── demo.html
├── docker
├── lib
├── meshblu.sublime-project
├── newrelic.js
├── package.json
├── public
├── server.js
└── test

Dockerイメージのビルド修正

アプリディレクトリの作成

デフォルトのリポジトリの状態だとDockerfileと同じ階層をそのまま/var/wwwにデプロイする形でイメージをビルドしています。server.jsなどのアプリケーションと、package.jsonをアプリディレクトリに移動します。このディレクトリでnpm installするので
node_modulesが配置されます。

$ mkdir -p ./var/www
$ mv demo.html lib newrelic.js public server.js test ./var/www
$ tree -L 3
.
├── Dockerfile
├── LICENSE
├── README.md
├── app.json
├── app.yml
├── config.js
├── docker
│   ├── config.js.docker
│   └── supervisor.conf
├── meshblu.sublime-project
├── package.json
└── var
    └── www
        ├── demo.html
        ├── lib
        ├── newrelic.js
        ├── public
        ├── server.js
        └── test

Dockerfileにパッケージ追加

リポジトリからcloneした状態のDockerfileでビルドするとzmq.hdns_sd.hがみつからないので失敗します。必要なパッケージをインストールします。

~/docker_apps/meshblu/Dockerfile
RUN apt-get install -y libzmq-dev libavahi-compat-libdnssd-dev

Dockerfileのディレクトリ修正

node_modulesディレクトリやSupervisor設定ファイルの管理を別にして修正後にDockerイメージを再ビルドしなくてもdocker restartできるようにします。アプリや設定をnpmやインフラのパッケージのインストールを分離することができます。

  • node_modulesをアプリディレクトリの外の/dist/node_modulesに作成して、アプリディレクトリにはシムリンクを作る
  • Dockerfileの最後にCOPYコマンドで、アプリケーションを変更してもnpmインストールが起きないようにする
  • Supervisorの設定ファイルはボリュームからアタッチするように変更する
~/docker_apps/meshblu/Dockerfile
...
#ADD . /var/www
#RUN cd /var/www && npm install
COPY ./var/www/package.json /var/www/
RUN mkdir -p /dist/node_modules && \
  ln -s /dist/node_modules /var/www/node_modules && \
  cd /var/www && npm install
#ADD ./docker/config.js.docker /var/www/config.js
#ADD ./docker/supervisor.conf /etc/supervisor/conf.d/supervisor.conf
...
CMD ["/usr/bin/supervisord", "-n", "-c", "/etc/supervisor/supervisord.conf"]
VOLUME /etc/supervisor/conf.d
COPY ./var/www/ /var/www

Meshbluの設定ファイルはDockerfile内でコメントアウトしたので、アプリディレクトリに移動します。

$ mv ./docker/config.js.docker ./var/www/config.js

アプリディレクトリのボリューム

最後に/var/wwwのアプリディレクトリもDockerイメージから分離してボリュームでアタッチできるようにします。Dockerホストには/dist/node_modulesディレクトリは存在しませんが、コンテナ内では存在するシムリンクを作成します。

$ ln -s /dist/node_modules ./var/www/node_modules

修正後のディレクトリ

Meshbluのリポジトリは以下のように修正しました。

$ tree -L 3
.
├── Dockerfile
├── LICENSE
├── README.md
├── app.json
├── app.yml
├── config.js
├── docker
│   └── supervisor.conf
├── meshblu.sublime-project
└── var
    └── www
        ├── config.js
        ├── demo.html
        ├── lib
        ├── newrelic.js
        ├── node_modules -> /dist/node_modules
        ├── package.json
        ├── public
        ├── server.js
        └── test

Dockerイメージのビルドと実行

Dockerイメージをビルドしてコンテナの起動を確認します。

$ docker build -t meshblu .
$ docker run -d --name meshblu \
  -p 3000 \
  -v $PWD/var/www:/var/www \
  -v $PWD/docker:/etc/supervisor/conf.d \
  meshblu
4
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
5