この記事の想定読者
- 私
- VagrantとDocker、どちらも名前だけは知ってるという方
- インフラ構成のコード化と共有に興味があるけどまだ触ってないという方
各種ソフトの概要と利用シーンについて軽く触れつつ、調べた内容をまとめておきました。
また、それぞれの実運用経験がない人間が書いておりますので、ご留意下さい。
ゆくゆくこうなるとカッコいいなぁ像
※この記事ではそんなレベルまでたどり着いてません
- チーム開発初期にはVagrantfileとDockerイメージを配布してスタート!
- チーム内でDockerレジストリを立て、ローカルテスト環境・結合テスト環境をDockerイメージとして共有!
2.1. Vagrant
これはなに?
仮想マシン(以下 "VM")を動かす仮想化ソフトの超すごいラッパーツール。
VirtualBoxなどの仮想化ソフトの操作を、ものすごく親切に代行してくれます。
VMの構成を Vagrantfile
というテキストに記述してVagrantに任せることで、ネットワークドライバの設定などを意識すること無く、ホスト環境に依存しない形で整備してもらえます。
なにに使う?
ゲストOSがインストールされたVMを整備するのに使います。
Vagrant Cloud にあらかじめ用意されている「box」というVMイメージを指定してコマンドを実行するだけで、OSインストール済みのVMを作成し、ネットワーク設定やSSH環境の整備までやってくれます。
また、VMの構成内容を Vagrantfile
というテキストファイルとしてコード化できます。
具体的に何がどう楽になる?
VMの構成を Vagrantfile
に記述して vagrant up
コマンドを実行するだけで、すぐに完全な環境を整備できます。
VirtualBoxでVMを作って、GuestAdditionsを入れて、ゲストOSをダウンロード&インストールして、sshdを立てて、SSHでログインして、ミドルウェアを入れて…といった大変な作業がバッサリカットできます。
何もない状態からスタートするとしても、Vagrantを使った環境整備は10分もかかりません。
2.2 Docker
これはなに?
OSからミドルウェア、果てはファイルシステム全体を「イメージ」という単位で取り扱い、まるごとやりとり出来るツール。
Dockerでは、OSとミドルウェアの環境構成を「Dockerイメージ」という形で保管します。イメージをベースに「Dockerコンテナ」を生成して、実際のOSとして稼働させます。
コンテナは、ファイルシステム全体をGitコミットオブジェクトのような感覚で履歴管理できます。コンテナの特定の履歴に名前を付けて、新しいイメージとして保存することもできます。
具体的に何がどう楽になる?
イメージという単位で 特定の環境全体をまるまるやりとりできます。
これはVagrantfileの効用にも似ていますが、Dockerイメージは直接稼働するVMではないという点が違います。
実際に稼働するのはイメージから生成されたコンテナであり、 その生成・起動と破棄のサイクルは超高速に行うことができます。
例えばアプリケーションのテストにおいて、Webサーバーやデータベース、テストデータなど全て準備済みの状態をイメージとして保存し、そこから生成したコンテナをテストに使うようにすれば、テストデータ準備済みの環境を何度でも・簡単に・高速に再現することができます。
また、コンテナは一つのVMと同じように扱うことができる完全な環境ですので、Chefのような構成管理ツールの試運転にも最適です。
レシピの実行に失敗したらそのコンテナは破棄して、また新しいコンテナを生成することで、常にまっさらな状態で試すことができます。
Vagrantでも似たようなサイクルは実現できるかもしれませんが vagrant up
で環境全体を整備するのは数分かかります。 Dockerコンテナの破棄と起動は、ものの数秒です。
VagrantとDockerをインストールして、Dockerイメージを作り、Dockerコンテナを起動させるところまでやってみます。
なぜDocker単体ではなくVagrantを挟むかというと、Dockerが64bit環境でしか動かないためです。完全にホスト環境依存を脱却するためにVagrantを挟みます。
また、VagrantにはゲストOS上でDockerを利用するためのサポート機能があり、Docker自体の導入がとても簡単になります。
3.1. Vagrant
おおまかな流れ
- VirtualBox, Vagrantのインストール
- VM用ディレクトリの作成
vagrant init
vagrant up
手順
1. VirtualBox, Vagrantのインストール
公式サイトからVirtualBox と Vagrant をそれぞれインストールします。
お手元の作業PC環境にあわせてインストーラーを選択して下さい。
2. VM用ディレクトリの作成
インストールできたらVM用ディレクトリを作ります。
ここでは ~/vm/project-dir
のような階層構造にしようと思います。
cd %UserProfile%
mkdir vm\hello-infra
cd vm\hello-infra
Windows以外の場合は適宜読み替えて下さい。
3. Vagrantfileの生成
次に、VMの構成を書く Vagrantfile
を生成します。
ここでは私の好みでUbuntu14.04を使います。
vagrant init --minimal ubuntu/trusty64
--minimal
は最小のVagrantfileを生成させます。
これをつけない場合は、記述例とコメントが入ったVagrantfileが生成されます。
ubuntu/trusty64
は Vagrant Cloud で公開されているUbuntu公式Boxの名前です。
【重要】ホストOSとゲストOSのCPUアーキテクチャが違う場合
ホストOSが32bitで、64bitのゲストOSを使用する、あるいはその逆を行う場合、次のようにVirtualBoxの設定を追記して、OSタイプを明示する必要があります。
Vagrantfile
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.box = "ubuntu/trusty64"
+ config.vm.provider "virtualbox" do |v|
+ v.customize ["modifyvm", :id, "--ostype", "Ubuntu_64"]
+ end
end
これにより、作成されたVMのOSタイプが「Ubuntu 64bit」に設定されます。特に32bitのホストでDockerを試してみたい場合に必要なことが多いと思います。
この設定がないと、VMのアーキテクチャとゲストOSの要件がマッチせずに様々なトラブルの元になります。例えばゲストOSがいつまでたっても起動しなかったり、SSHDが起動していない旨のエラーが表示される等々…
いずれも事象と原因が結びつきにくいモノが多く、かなり悩まされます。
(つまり筆者はハマりました)
ちなみにVMのカスタマイズを行う v.customize
ですが、VM名・CPU数・メモリサイズの3つについてはショートカットがあります。
v.name = "VM名"
… VMの名前v.cpus = 2
… VMのCPU数v.memory = 1024
… VMのメモリサイズ
v.customize
でカスタマイズ出来る内容はVirtualBoxの VBoxManage
に準拠しますので、詳細は VBoxManageのマニュアル を参照して下さい。
modifyvm --ostype <ostype ID>
で指定する値は、VirtualBoxのインストールディレクトリにある VBoxManage
コマンドを使用して、 VBoxManage list ostypes
で調べられます。特によく使われるであろうCentOSとUbuntuのものを下表に引用します。
ゲストOSの種類 | ostype ID |
---|---|
Ubuntu 32bit | Ubuntu |
Ubuntu 64bit | Ubuntu_64 |
CentOS 32bit | RedHat |
CentOS 64bit | RedHat_64 |
4. VMの起動とSSHログイン
それではVMを起動してみましょう。
初回はBoxのダウンロードとVM生成があるため時間がかかります。
起動が完了すると、既にSSHログインできる状態になっています。
Vagrantの機能を通してログインしてみましょう。
そのままコンソールがsshに切り替わります。
Welcome to Ubuntu 14.04.1 LTS (GNU/Linux 3.13.0-35-generic x86_64)
* Documentation: https://help.ubuntu.com/
System information disabled due to load higher than 2.0
Get cloud support with Ubuntu Advantage Cloud Guest:
http://www.ubuntu.com/business/services/cloud
Last login: Thu Sep 11 09:39:22 2014 from 10.0.2.2
vagrant@vagrant-ubuntu-trusty-64:~$
あるいは vagrant ssh-config
で表示される情報を使って、好みのSSHクライアントで接続することもできます。
VMのシャットダウンは vagrant halt
, 休止は vagrant suspend
です。
なにかトラブルがあって最初からやり直したい場合は、VMを削除してしまいましょう。
確認表示で y
と返答すればVMが削除されます。
default: Are you sure you want to destroy the 'default' VM? [y/N] y
==> default: Destroying VM and associated drives...
その後、改めて vagrant up
すればVMの生成から再スタートできます。
TIPS: ホストOSとのファイル共有
Vagrantでは、デフォルトではVagrantfileがあるホスト側ディレクトリがゲストOSの /vagrant
にマウントされます。ゲストOSで /vagrant
を見てみるとわかりやすいです。
vagrant@vagrant-ubuntu-trusty-64:~$ cd /vagrant
vagrant@vagrant-ubuntu-trusty-64:/vagrant$ ls -Al
total 1
drwxrwxrwx 1 vagrant vagrant 0 Sep 12 04:47 .vagrant
-rwxrwxrwx 1 vagrant vagrant 386 Sep 12 07:23 Vagrantfile
このマウント先はVagrantfileの config.vm.synced_folder
で指定できます。
詳細は VagrantマニュアルのSynced Folder を参照してください。
NOTE: Boxの取得について
Vagrant Cloud が立ち上がる以前に Vagrantbox.es という「みんなのBoxを持ち寄ってURLを共有する場」が広まりました。
導入解説サイトなどではこちらを利用している例も多く、Boxも多数登録済みですが、ここにあるのはあくまで 世界中の個人ユーザーが作ったBox です。
(各種BoxのダウンロードURLからもお分かりいただけるかと思います)
今後は特に理由がなければ Vagrant Cloud で始めましょう。
3.2. Docker
おおまかな流れ
- Docker導入のためにProvisionerをVagrantfileに追記
vagrant provision
でDockerインストール- Dockerイメージの構成記述ファイル
Dockerfile
の作成 - イメージをビルド
- コンテナを生成・起動
手順
1. Dockerの導入
Vagrantには、VMに自動で追加ソフトウェアをインストールする「Provisioner」という機構があります。この中にはDocker使うための「Docker Provisioner」がありますので、これを利用します。
先ほど作ったVagrantfileにProvisionerを追記します。
Vagrantfile
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.box = "ubuntu/trusty64"
config.vm.provider "virtualbox" do |v|
v.customize ["modifyvm", :id, "--ostype", "Ubuntu_64"]
end
+ config.vm.provision "docker"
end
2. Provisionerを実行してゲストOSにDockerをインストール
Provisionerは vagrant up
でVMを起動した時に実行されますが、起動中のVMにProvisionerを実行させることもできます。
しばらく待ちます。
==> default: Running provisioner: docker...
default: Installing Docker (latest) onto machine...
default: Configuring Docker to autostart containers...
これでゲストOSに最新のDockerがインストールされ、Dockerデーモンが稼働するようになりました。簡単ですねー。
3. Dockerイメージの作成
コンテナを起動するにはイメージが必要です。
イメージを作る時は ベースイメージ が必要です。ベースイメージとは、独自のDockerイメージを作成する時の基礎となる、まっさらなOSのイメージです。Vagrant CloudにあるベースBoxみたいなものですね。
Dockerには Docker Hub という公式レジストリ(イメージを公開するためのリポジトリ)があり、CentOSやUbuntuといったベースイメージはここから入手できます。
これを元に、どんなソフトウェアをインストールするか、何番のポートを開けるか、起動時に何を実行するかといったことを Dockerfile
に記述して ビルド することでイメージが完成します。
早速作りましょう。
Dockerfile
FROM ubuntu:trusty
MAINTAINER hidekuro
CMD ["/bin/bash"]
これはUbuntu trusty(14.04)のベースイメージと何も変わらないイメージです。
本来であればMAINTAINERのあとに RUN apt-get -y install nginx
といった記述で環境のセットアップをしていくところですが、その辺は他の記事にお任せして、今回はとりあえずイメージのビルドとコンテナ起動を目的としましょう。
このファイルを、ホストOSのVagrantfileと同じディレクトリ %UserProfile%\vm\hello-infra\
においておきます。
4. Dockerイメージのビルド
イメージをビルドするには docker build
コマンドを使います。
このコマンドにDockerfileが置いてあるディレクトリを渡してやります。
また、ビルドしたイメージにタグを付けて、名前で扱えるようにしておきます。
ゲストOS
vagrant@vagrant-ubuntu-trusty-64:~$ docker build -t hidekuro/my-first-container /vagrant
/vagrant
は、今回はホスト側の %UserProfile%\vm\hello-infra
フォルダがマウントされたディレクトリです。先ほどDockerfileをここに保管したので、それをビルドします。
-t
でタグを付けます。タグは USER/TAG という形式にする慣習があります。このルールはDocker Hubでイメージを公開することを考慮してのものです。
さて、しばらく待つとビルドが完了します。
vagrant@vagrant-ubuntu-trusty-64:~$ docker build -t hidekuro/my-first-container /vagrant
Sending build context to Docker daemon 11.78 kB
Sending build context to Docker daemon
Step 0 : FROM ubuntu:trusty
Pulling repository ubuntu
826544226fdc: Download complete
511136ea3c5a: Download complete
b3553b91f79f: Download complete
ca63a3899a99: Download complete
ff01d67c9471: Download complete
7428bd008763: Download complete
c7c7108e0ad8: Download complete
---> 826544226fdc
Step 1 : MAINTAINER hidekuro
---> Running in eb693c4b9dbc
---> 7046d5b306fc
Removing intermediate container eb693c4b9dbc
Step 2 : CMD["/bin/bash"]
---> Running in 536eed38a72d
---> 1767a92dba30
Removing intermediate container 536eed38a72d
Successfully built 1767a92dba30
vagrant@vagrant-ubuntu-trusty-64:/vagrant$
初回はベースイメージがpullされるので、ダウンロードに時間がかかります。
出力内容を見てみると、ステップごとにコミットハッシュのようなものがあります。また Removing intermediate container
「中間コンテナを削除」という表示が見えます。
Dockerがイメージをビルドする時はDockerfileの指示コマンドを一つ進めるごとにコンテナが作成&コミットされており、最終的に完成したコンテナにタグが付けられているということがわかります。
それでは、作成したコンテナを起動してみます。
vagrant@vagrant-ubuntu-trusty-64:/vagrant$ docker run -i -t -v /vagrant:/tmp/shared --name="hogehoge" hidekuro/my-first-container
root@246dc5e41ffd:/#
いま、 hidekuro/my-first-containerイメージから起動したhogehogeコンテナにて、rootユーザーでbashを起動した状態 になっています。ちょっと長いので順に見てみます。
docker run [OPTIONS] IMAGE [CMD]
というコマンドです。-i
で対話モードにしています。-t
は擬似ターミナル割り当てです。-v /vagrant:/tmp/shared
で、/vagrant
ディレクトリをコンテナ内の/tmp/shared
としてマウントしています。今回の場合、ゲストOSの/vagrant
はホストOSとも共有していますので、ホストOSのファイルを直接コンテナに共有することができます。--name="hogehoge"
でコンテナに名前を付けます。省略すると "condescending_colden" のようなランダム2語の名前がつきます。- 最後に
hidekuro/my-first-container
でイメージを指定しています。
[CMD]
は指定していませんが、さきほどビルドしたDockerfileの最後の行で CMD ["/bin/bash"]
と記述しています。
docker run
でコマンド省略時はこれが実行されるので、bashが起動するようになっています。
例えばこれを docker run -it hidekuro/my-first-container echo 'hello!!'
のようにすると、生成されたコンテナは echo 'hello!!'
を実行して終了します。
(フォアグラウンドプログラムが終了するとコンテナも終了します)
ここまでで、コンテナを起動するところまでこれました。
とりあえず現在のbashを終了します。
root@246dc5e41ffd:/# exit
vagrant@vagrant-ubuntu-trusty-64:~$
前述のとおり、フォアグラウンドのプログラムが終了するとコンテナも終了します。
今回はbashを実行するコンテナだったので exit
でbashとともにコンテナも終了します。
ここで、終了したコンテナを確認してみます。
vagrant@vagrant-ubuntu-trusty-64:~$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c149e0ff4fcf hidekuro/my-first-container:latest "/bin/bash" About a minute ago Exited (0) About a minute ago hogehoge
コンテナIDや名前、起動元のイメージ、ステータスなどが表示されました。
とりあえず試しただけのコンテナなので、捨ててみましょう。
vagrant@vagrant-ubuntu-trusty-64:~$ docker rm c149e0ff4fcf
c149e0ff4fcf
vagrant@vagrant-ubuntu-trusty-64:~$
消えました。
さて、Dockerコンテナを試せたまではいいのですが、このままだと
「Vagrantいれて、Vagrantfileをどっかに保存して、vagrant up
してね!!」
だけで済ますことができません。
わざわざ起動してからDockerを操作するのも面倒なので、Vagrantfileに追記して vagrant up
だけで全てやってもらえるようにします。
Vagrantfile
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.box = "ubuntu/trusty64"
config.vm.provider "virtualbox" do |v|
v.customize ["modifyvm", :id, "--ostype", "Ubuntu_64"]
end
- config.vm.provision "docker"
+ config.vm.provision "docker" do |d|
+ d.build_image "/vagrant", args: "-t hidekuro/my-image"
+ d.run "hidekuro/my-image", args: "-d -t -v /vagrant:/tmp/shared"
+ end
end
Docker Provisionerのブロックで、上でコマンドを使って行った「イメージのビルド」「コンテナの起動」をやっているだけです。
d.build_image
で docker build
に相当する処理を行います。
ゲストOS上での Dockerfileのパスと、引数でタグを指定しています。
d.run
で docker run
相当の処理を行います。
起動するイメージ名と、先ほどと似たような引数を与えています。
一点違うのは -d
で、これは入出力をデタッチしてバックグラウンドでコンテナを起動することを意味します。詳細は docker run -h
を参照してください。
これでVMを再起動してみましょう。
vagrant reload --provision
これはプロビジョナーの実行アリでVMを再起動する指示で、 vagrant halt
→ vagrant up
とほぼ同じです。
...略...
==> default: Building Docker images...
==> default: -- Path: /vagrant
==> default: Starting Docker containers...
==> default: -- Container: hidekuro/my-image
VMの起動時にコンテナが起動されました。
今回起動したコンテナはbashを実行しているだけなので、デタッチしたら全く意味がありませんが、実用の際はこのような方法でApacheやnginx, GlassFish, MySQLといったサーバー系ソフトウェアを動作させます。
ここまでは、あまりVagrant+Dockerの恩恵を受けられないような小規模なデモでしたが、実際にどのようなシーンで使っていけばいいでしょうか。
例えば…
- 開発環境、ローカル確認環境、ステージング環境、本番環境を全てイメージとして整備する。
- 開発環境・ローカル確認環境は随時 build & run
- ステージング環境は定期的に build & run
- 本番環境は特定のトリガーに基づいて build & run
…と言った体系を組み上げ、更にそれぞれの環境ごとのイメージについても
- ミドル環境を整えた基本イメージ
- ↑をベースにアプリを
git clone
してデプロイするアプリ基本イメージ - ↑をベースに最新版を
git pull
してデプロイする実行イメージ
という段階を設け、各段階を build & run する頻度を分けることで運用していくとか。
…と、ここまで↓こちらの記事のパクリです。
→ Docker をプロダクトのデプロイに使う - Wed, 08 Jan 2014 05:07:37 GMT
まだまだ私も学習が必要な段階ですが、この記事が皆様のスタートの手助けになれば幸いです。
以上です。