Vagrant で学ぶ Docker の基本
[履歴] [最終更新] (2015/02/25 11:22:25)
最近の投稿
注目の記事

概要

Vagrant を用いると Docker 関連の作業がはかどります。Vagrant と Docker は相容れない関係にあるのではなく、実は親和性が高くなるように作られています。Vagrant の基本については公式ドキュメント「GETTING STARTED」などをご参照ください。また以下の内容を理解するにあたり Docker のイメージをつかむには公式サイトのチュートリアルが有用です。本ページの内容を越えるものについては公式ドキュメントをご参照ください。Docker チートシートはこちらです

二種類の Docker

Vagrant と Docker の関係には二種類あります。Docker というものの概念は一定で、それに対して Vagrant がどう関わるかによる分類です。

Provisioner としての Docker

Vagrant は up 時に通常通り VirtualBox などの VM を起動します。Vagrant は更にその VM に docker コマンドを自動でインストールします。そして Vagrantfile で指定しておいた Docker の image を pull または build します。更にその image を run してコンテナを作成する設定まで Vagrantfile に記述することができます。公式ドキュメントはこちらです。

Provider としての Docker

Vagrant は既定では VirtualBox を provider として利用して VM を起動します。しかしながら、実は up 時に任意の provider を指定できます。Docker を指定するためには以下のようにします。

$ vagrant up --provider=docker

注意すべきは、Docker Provider で up した場合に VM は起動しないということです。つまり Vagrantfile では config.vm.box を指定しません。代わりに、どの Docker image を用いてコンテナを作成するかを指定する必要があります。Vagrant は up 時に Vagrantfile で指定された image をホストマシン上で直接 build または pull して run することでコンテナを作成します。Vagrant ssh でログインする対象は VM ではなく run して作成したコンテナです。

ホストマシンが Windows の場合 docker が動作せず、したがって Vagrantfile で指定された image を pull/build することも run することもできません。そのため Vagrant は自動で軽量の VM をホストマシン上にまず起動し docker コマンドをインストールします。その VM 上で Vagrantfile で指定された image を build/bull および run してコンテナを用意します。この軽量の VM 起動および docker のインストールは Vagrant がすべて自動で検知して実行するため、ユーザが Vagrantfile に明記することはありません。同じ Vagrantfile を Linux と Windows で使用できます。Provider としての Docker に関する公式ドキュメントはこちらです。

Boot2Docker との違い

上述の通り Vagrant によって Docker を扱うことが可能です。Windows などで Docker を Provider として使用する際には必要に応じて軽量の VM を VirtualBox などで起動します。これは Boot2Docker という Docker インストーラと似ているため、混同しないように注意してください。Windows および Mac OS X で Boot2Docker を使用すると軽量の VM が VirtualBox などを利用して起動して Docker を利用できるように初期設定がなされます。Windows および Mac OS X では直接 Docker が動作しないため VM を介する仕組みとなっています。どことなく Vagrant で Docker を操作する際の挙動と似ていますので注意してください。

Chef との違い

Chef は自動化を提供し Docker は抽象化を提供します。こちらのページで触れた Chef はプロビジョニング機能を提供します。しかしながら、必ずしも汎用的な記述がなされている保証がなく特定の OS や CPU に特化したレシピが作成できてしまいます。これは、開発環境には適用できて本番環境には適用できない、という事態を招きます。それに対して Docker ではコンテナがどのような環境でも Docker エンジンさえあれば動作することが保証されています。その代わり、シェルスクリプトのような簡単な手続きを記述することはできますが、自動化としての機能は Chef ほど充実していません。Chef によって Docker をインストールするためのレシピに関する記述はこちらです。

Provisioner としての Docker の使用例

Dockerizing a Node.js Web App」を Vagrant で再現します。ディレクトリ構成は以下の通りです。

$ tree .
.
├── Dockerfile
├── index.js
├── package.json
└── Vagrantfile

Vagrantfile

全体としては最後に示す通りです。その前にいくつかポイントを示します。

ポート転送

windows:8080 → vagrant:49160 → docker:8080

config.vm.network "forwarded_port", guest: 49160, host: 8080

Windows の 8080 ポートを仮想マシンの 49160 ポートに転送するための記述です。

d.run "qoosky/centos-node-hello", args: "-p 49160:8080 -d"

仮想マシンの 49160 ポートを Docker コンテナの 8080 ポートに転送するための記述です。

yum update

config.vm.provision "shell", inline: "yum update -y device-mapper-libs"

chef/centos-6.5 という Vagrant の BOX に Docker をインストールするためには device-mapper-libs をアップデートしておく必要があるためです。こちらのページを参考にしました。この記述がない場合は以下のエラーが出ます。

Cannot connect to the Docker daemon. Is 'docker -d' running on this host?

Vagrantfile

# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure(2) do |config|
  config.vm.box = "chef/centos-6.5"
  config.vm.network "forwarded_port", guest: 49160, host: 8080
  config.vm.provision "shell", inline: "yum update -y device-mapper-libs"
  config.vm.provision "docker" do |d|
    d.build_image "/vagrant", args: "-t qoosky/centos-node-hello"
    d.run "qoosky/centos-node-hello", args: "-p 49160:8080 -d"
  end
end

なお 2015/02/11 現在 Docker は 64bit のホスト OS にしか対応していません。Vagrantfile で指定する BOX は 64bit である必要があります。例えば "chef/centos-6.5-i386" を指定すると Docker をインストールできません。"chef/centos-6.5" を指定してください。お使いの PC によっては BIOS 設定で仮想化技術を有効にする必要があります。

Dockerfile

基本となるイメージ centos:centos6 に Express.js などをインストールします。

FROM centos:centos6

# Enable EPEL for Node.js
RUN rpm -Uvh http://download.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm

# Install Node.js and npm
RUN yum install -y npm

# Bundle app source
COPY package.json index.js /src/

# Install app dependencies
RUN cd /src; npm install

EXPOSE  8080
CMD ["node", "/src/index.js"]

package.json

npm install で Express.js をインストールするためのファイルです。

{
  "name": "docker-centos-hello",
  "private": true,
  "version": "0.0.1",
  "description": "Node.js Hello world app on CentOS using docker",
  "author": "Daniel Gasienica <[email protected]>",
  "dependencies": {
    "express": "3.2.4"
  }
}

index.js

Hello world と表示するだけの Express.js アプリケーションです。

var express = require('express');

// Constants
var PORT = 8080;

// App
var app = express();
app.get('/', function (req, res) {
  res.send('Hello world\n');
});

app.listen(PORT);
console.log('Running on http://localhost:' + PORT);

起動および確認

以下のコマンドで chef/centos-6.5 の起動および Docker のインストール、イメージのビルド、コンテナの作成まで自動で実行されます。

windows$ vagrant up

例えば以下のコマンドで Vagrant VM に SSH します。

windows$ vagrant ssh

あるいは以下のコマンドで確認した情報をもとに RLogin などのクライアントを使用してもよいです。

windows$ vagrant ssh-config

ログインしたら以下のコマンドでイメージがビルドされたことを確認できます。

vagrant$ docker images
REPOSITORY                     TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
qoosky/centos-node-hello       latest              a05c84307fab        53 minutes ago      433.8 MB

イメージが run されて作成されたコンテナは以下のコマンドで確認します。

vagrant$ docker ps
CONTAINER ID  IMAGE                           COMMAND              CREATED         STATUS          PORTS                    NAMES
3163e5cc3e55  qoosky/centos-node-hello:latest "node /src/index.js" 40 minutes ago  Up 35 minutes   0.0.0.0:49160->8080/tcp  qoosky-centos-node-hello

コンテナのログを確認してみましょう。

vagrant$ docker logs qoosky-centos-node-hello
Running on http://localhost:8080

HTTP リクエストを 49160 に対して発行してみます。正常に動作しているようです。

vagrant$ curl -i localhost:49160

HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: text/html; charset=utf-8
Content-Length: 12
Date: Sat, 07 Feb 2015 11:01:51 GMT
Connection: keep-alive

Hello world

最後に Windows のブラウザで http://127.0.0.1:8080/ にアクセスしてみます。

Uploaded Image

Provider としての Docker の使用例

DockerHubhttpdイメージ を pull して run する Vagrantfile の例を示します。

Vagrantfile

# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure(2) do |config|
  config.vm.provider "docker" do |d|
    d.image = "httpd"
  end
end

以下のコマンドでコンテナを作成します。

$ vagrant up --provider=docker

ログを取得してみましょう。

$ vagrant docker-logs
==> default: AH00558: httpd: Could not reliably determine the server's
fully qualified domain name, using 172.17.0.4. Set the 'ServerName'
directive globally to suppress this message

==> default: AH00558: httpd: Could not reliably determine the server's
fully qualified domain name, using 172.17.0.4. Set the 'ServerName'
directive globally to suppress this message

==> default: [Sat Feb 07 07:22:02.164451 2015] [mpm_event:notice]
[pid 1:tid 139768255600512] AH00489: Apache/2.4.12 (Unix) configured
-- resuming normal operations
関連ページ
    概要 Git を用いたプロジェクト開発を複数人で行う場合、サーバーでレポジトリ管理を行えると便利です。何らかの事情で GitHub や Bitbucket を利用できない場合は、サーバーを構築して GitLab をインストールします。ここでは特に CentOS 6 の場合についてインストール手順をまとめます。 コマンドを実行するサーバーの用意