はじめに
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でビルドコマンドを実行するだけです🍣。
ソース
説明はコメントに書くようにしています。
素晴らしいコーディングスタイルです。
…、え、少ないって?面倒くさがりですいません🍣。
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
にも書いておきます🍣。
{
"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) にもアップロードしております。
ただし、一切の責任を取りかねますのでご了承ください。
既にご存知かもしれませんが、私は大の面倒くさがりなのです。