LoginSignup
2
5

More than 5 years have passed since last update.

Dockerですか?Node.JSですか?ビルドスクリプトはJSですか?

Last updated at Posted at 2017-06-19

はじめに

Docker Toolboxがあるため、我々はDockerイメージをビルドする環境に特に制約を受けません。
会社支給のPCがLinuxではなく、macOSだろうと、Windowsだろうと、どこでもビルドできるのは良いことです。
ただ、Docker ToolboxでDockerイメージをビルドするには、Docker Machineを起動し、加えて環境変数を設定してあげる必要があります。

たった2行を打つだけですが、面倒なのです。

というわけで、ビルド用のBATファイルをよく書くようにしていたのですが(主環境はWindows PC)、BATだとLinuxでビルドできません。
LinuxではDocker Machineを起動する必要はなく、たった1行を打つだけですが、面倒なのです。

そこで、Node.JSを使った開発ならスクリプトもNode.JSで書こうと思った次第です。
結構気に入ったので、記事にしてみました🍣。

概要

通常のNode.JSプロジェクトの中に、scriptsフォルダを作り、ビルド用のスクリプトはそっちに詰めることにしました。
今回はビルドスクリプトなので、scripts/build.jsに書いていきます。

やることは単純です。
Docker Machineを起動して、環境変数を設定して、Dockerでビルドコマンドを実行するだけです🍣。

ソース

説明はコメントに書くようにしています。
素晴らしいコーディングスタイルです。
…、え、少ないって?面倒くさがりですいません🍣。

scripts/build.js
const spawn = require('child_process').spawn;
const meta = require('../package');

// 作業ディレクトリをパッケージのあるディレクトリにする。
process.chdir(__dirname);
process.chdir('..');

Promise.resolve()
  // Docker Machineがインストールされているか確認する。
  .then(() => (new Promise((resolve, reject) => {
    console.log('Check Docker Machine.')
    const machine = spawn('docker-machine', ['version']);
    machine.on('error', reject);
    machine.on('exit', () => {
      console.log('Docker Machine found.');
      return resolve();
    });
  })))
  // Docker Machineがインストールされている場合、Docker Machineを起動する。
  .then(() => (new Promise((resolve, reject) => {
    console.log('\nStart Docker Machine.');
    const machine = spawn('docker-machine', ['start'], {
      stdio: [null, process.stdout, process.stderr],
    });
    machine.on('error', reject);
    machine.on('exit', () => {
      return resolve();
    });
  })))
  // Dockerコマンドへ渡すための、Docker Machineの設定を取得する。
  .then(() => (new Promise((resolve, reject) => {
    console.log('\nGet configuration of Docker Machine.');
    const machine = spawn('docker-machine', ['config'], {
      stdio: [null, null, process.stderr],
    });
    let out = '';
    machine.stdout.on('data', (data) => { out += data; });
    machine.on('error', reject);
    machine.on('exit', (code) => {
      if (code !== 0) {
        return reject(new Error('Doccker Machine failed.'));
      }
      const config = out.split('\n').filter((item) => (item !== ''));
      return resolve(config);
    });
  })))
  // Docker Machineが見つからない場合のエラーを無視する。
  .catch((err) => {
    if (err.code === 'ENOENT') {
      return [];
    }
    throw err;
  })
  // 取得した設定を用いて、Dockerイメージをビルドする。
  .then((config) => (new Promise((resolve, reject) => {
    console.log('\nBuild Docker Image.');
    const machine = spawn('docker', [...config, 'build', '-t', `${meta.name}:${meta.version}`, '.'], {
      stdio: [null, process.stdout, process.stderr],
    });
    machine.on('error', reject);
    machine.on('exit', (code) => {
      if (code !== 0) {
        return reject(new Error('Docker failed.'));
      }
      return resolve(config);
    });
  })))
  .then(() => {
    console.log('\nBuild succeeded.\n')
    process.exit(0);
  })
  .catch((err) => {
    console.error(`\nBuild failed. Error: ${err}\n`);
    process.exit(1);
  });

スクリプトを簡単にキックできるように、package.jsonにも書いておきます🍣。

package.json
{
  "name": "docker-building",
  "version": "1.0.0",
  "scripts": {
    "build": "node ./scripts/build"
  }
}

使い方

簡単です。
面倒なことを減らすためにしたので当然です。
コンソールでnpm run buildもしくはnode scripts/build.jsと叩くだけです。

まず、Docker Machineがインストールされている環境であれば、Docker Machineの起動と設定値の取得を行います。
続いて、Dockerコマンドを使用してイメージをビルドする感じになります🍣。

工夫

最初は、Docker Machineから環境変数を取得して、それをDockerコマンド時に設定する方法しか考えていなかったのですが、docker-machine configで取得した設定値をdockerコマンドにたれ流せばよいことを知ったので、そちらを使っています。
また、Dockerodeなどのモジュールを使うことも考えましたが、.dockerignoreが参照されないなど少し面倒だったので、コマンドを直接実行するようにしました。
その結果、追加で必要なモジュールがなくなり、面倒なことも減ったので、とてもよかったと思います🍣。

さいごに

この記事で示したコードはWTFPL v2としておりますので、ご自由に使っていただいて大丈夫です。
一応、GitHub (https://github.com/leak4mk0/DockerBuilding) にもアップロードしております。
ただし、一切の責任を取りかねますのでご了承ください。
既にご存知かもしれませんが、私は大の面倒くさがりなのです。

2
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
2
5