Docker で Java アプリをデプロイする。すごい!

Vagrant を用いた Java プロビジョニングに関して私が少し前に書いたブログを思い出す方もいらっしゃるかも知れません。今日ご案内するものは、そのライバルであり、同時にそれをしっかりと補完する役割も持っています。

今回は、Docker についてお話し、またそれがいかに素晴しいものであるかの説明もしたいと思います。Docker をご存じない方のために、開発者自身によるイントロダクションを次に紹介します:

「Docker は、高度に移植可能で自己充足的なコンテナーとしてアプリケーションのデプロイメントを自動化するオープンソースのエンジンであり、ハードウェアや言語、フレームワーク、パッケージングシステム、ホスティング・プロバイダーなどには依存しません。」

私が初めて Docker の名を聞いたとき、サイトにあったデモ使用例を見てみたのですが、大いに好奇心をかき立てられました。サービスのデプロイに使える簡単でペナルティのないコンテナーだって? 仮想マシンのオーバーヘッドがない仮想マシンだって?イメージ・スナップショットを簡単にリプレイしたりリセットしたりできるだって?これは是非使ってみなくては・・・

Docker は、洗練された lxc (Linuxコンテナー)aufs (アドバンスト・マルチレイヤード・ユニフィケーション・ファイルシステム) 上における効率的なユーザーインターフェイスと API を提供するものであり、それによって仮想マシンライクな軽量コンテナーの設定、起動、停止、セット、リプレイが可能です。

docker-logo

以下に、コンテナー内の Java アプリケーションをデプロイする場合の Docker の使用例を示します。ここでは私が使い慣れている 強力な Git リポジトリ管理ツールである Stash をサンプルアプリケーションとしています (他のアトラシアン製品や任意の Java アプリケーションに置き換えることは当然可能です)。

Mac ユーザーの場合に必要な準備

既に Linux 上で作業している場合はこのセクションを読み飛ばしても構いません。Docker は Linux 上でのみ動作する (他のプラットフォームへの対応は開発中ないしは計画中の段階です) ため、Mac 上で作業している場合は仮想マシンまたは Vagrant を経由して Docker を利用しなければなりません。

Vagrant を使用する場合、ターミナルにおいて次の Vagrantfile を作成し、端末において vagrant up と入力することにより、最新の Ubuntu ボックスを起動します:



1
2
3
4
5
6
7
Vagrant::Config.run do |config|
  config.vm.box = "raring"
  config.vm.box_url = "http://cloud-images.ubuntu.com/raring/current/raring-server-cloudimg-vagrant-amd64-disk1.box"
  config.vm.forward_port 7990, 7991
  config.vm.share_folder("vagrant-root", "/vagrant", ".")
  config.vm.customize ["modifyvm", :id, "--memory", 2048]
end

後でインストールのテストを Mac から行うことができるようにするため、このファイルでは 7990 番ポート (Stash のデフォルトポート) をホストの 7991 番ポートにマップしています。

これが完了すると、vagrant ssh を使用してボックスへの ssh アクセスが可能となり、Docker をインストールできるようになります。

(いつも使っているVagrant の簡便セットアップ方法を紹介してくださった Rob Knight さんに感謝します)

これで、Vagrant 仮想マシン環境に入りましたので Docker がインストールできます。

管理者の注意事項 (読み飛ばしても構いません)

新規ボックスの場合は、.dotfiles をデプロイする際に vimcurlgit が必要で、これらがないと正しく動作しません:



1
2
3
sudo apt-get install vim curl git

curl -Lks http://j.mp/durdn-cfg | bash

Docker のインストール

Docker のインストールは簡単にできます。最初にインストールを実行するためのカーネル拡張をインストールします:




1
sudo apt-get install linux-image-extra-$(uname -r)

次に、add-apt-repository を利用するために software-properties-common をインストールします:


1
sudo apt-get install software-properties-common

dotcloud ppa を追加します:


1
2
sudo add-apt-repository ppa:dotcloud/lxc-docker
sudo apt-get update

最後に次のコマンドを実行して Docker をインストールします:

1
sudo apt-get install lxc-docker

これで、今後のすべての作業の基礎となる base image を取得することが可能となります:

1
docker pull base

このコマンドの出力は次のようになります:


1
2
3
4
5
6
7
8
9
Pulling repository base from https://index.docker.io/v1
Pulling image 27cf784147099545 () from base
Pulling 27cf784147099545 metadata
Pulling 27cf784147099545 fs layer
Downloading 94863360/? (n/a)
Pulling image b750fe7[...]2b4accb2c21d589ff2f5f2dc (ubuntu-quantl) from base
Pulling b750fe79269d2[...]f05b433b1d1a02a62b4accb2c21d589ff2f5f2dc metadata
Pulling b750fe79269d2[...]3ef05b4332b1d1a02a62b4accb2c289ff2f5f2dc fs layer
Downloading 10240/? (n/a)

(ここで、すべての docker コマンドを実行するためには、マシン上で docker daemon が実行されている必要があることに注意してください。Docker daemon が実行されていない場合にそれをバックグラウンドで実行するためには、次のように入力します: sudo docker -d &).

これで、Index Docker に公開されたイメージや自分で公開したイメージなど、すべての公開イメージを取得することができます。

Docker が作成したすべてのイメージを確認するには次のコマンドを使用します:


1
docker images

このコマンドの出力は次のようになります:


1
2
3
4
5
REPOSITORY          TAG                 ID                  CREATED
base                ubuntu-quantl       b750fe79269d        10 weeks ago
base                latest              b750fe79269d        10 weeks ago
base                ubuntu-quantal      b750fe79269d        10 weeks ago
base                ubuntu-12.10        b750fe79269d        10 weeks ago

この結果は、Ubuntu 12.10 に基づく閲覧可能ベースイメージが存在することを示しています。

Java のインストール

これでイメージを作成して必要に応じてカスタマイズすることができるようになりました。最初に Java をインストールする必要があります。

ベースコンテナーのシェルを起動します:


1
docker run -i -t base /bin/bash

このコマンドは新規コンテナーを作成し、それにユニークな ID を付与し、IP アドレスを割り当て、ネットワーク設定を行います。

ルートシェルが起動されます:


1
root@298af82e71ef:/#

ここで、他の部分から隔離されたこの軽量で仮想マシンライクなコンテナーに対して従属するソフトウェアをインストールすることができます:


1
 apt-get install software-properties-common

Java のインストールに必要な ppa をインストールします:

1
2
add-apt-repository ppa:webupd8team/java
apt-get update

Java をインストールします:

1
apt-get install git curl oracle-java7-installer

(ライセンス条件の承諾を手動で行います。次のバージョンではこのプロセスは自動化される予定です)

ここまでうまくいきました。これでこのコンテナーの状態をイメージとして保存するためのコミットの作成が可能となりまた。

(exit または CTRL-d) を実行してコンテナーから抜け出し、docker ps -a を実行して使用可能か否かを問わずすべてのコンテナーのリストを作成すると次のような出力が得られます:



1
2
3
4
5
6
7
8
9
ID                  IMAGE                COMMAND             CREATED             STATUS              PORTS
8e07a84ea97a        base:latest          /bin/bash           12 minutes ago      Exit 0              
fecada4ce303        base:latest          /bin/bash           17 minutes ago      Exit 0              
9cb541022c5b        base:latest          /bin/bash           25 minutes ago      Exit 127            
a2914a38394d        durdn/base:latest    /bin/bash           26 minutes ago      Exit 0              
6fa304872025        durdn/base:latest    /bin/bash           30 minutes ago      Exit 0              
3e0241227129        durdn/base:latest    /bin/bash           30 minutes ago      Exit 0              
98b400fcb5dc        durdn/base:latest    /bin/bash           31 minutes ago      Exit 0              
88a113234c47        base:latest          /bin/bash           36 minutes ago      Exit 0

新規コンテナーの中から、すべての従属ソフトウェアをインストールした最新のコンテナーを見つけます。それに対して docker commit コマンドを実行することにより、新しいスナップショットまたはイメージのコミットが可能です:


1
docker commit 8e07a84ea97a durdn/java7

さらに、docker images と入力することにより、次に示すようなリストが取得できます:


1
2
3
4
5
6
7
8
docker images

REPOSITORY          TAG                 ID                  CREATED
durdn/java7         latest              ab6396541f9a        2 hours ago
base                ubuntu-quantal      b750fe79269d        10 weeks ago
base                ubuntu-quantl       b750fe79269d        10 weeks ago
base                latest              b750fe79269d        10 weeks ago
base                ubuntu-12.10        b750fe79269d        10 weeks ago

Stash のインストール

これで、新規に生成された durdn/java7 イメージに、Java アプリケーション (ここでは Stash) をインストールすることができます。

イメージにコンテンツを追加する方法はいくつかあり、docker insert コマンドがそのひとつですが、curlwget を使う方法もあります。

新規に生成された durdn/java7 イメージにおいてシェルを起動し、コンテナーからホストへの 7990 番ミラーポートをオープンするとともにデータを格納するための固定のホームを指定します:

1
2
3
docker run -i -t -p :7990 -v /opt/stash-home durdn/java7 /bin/bash

root@afbf1fd4f78d:/#

Stash をダウンロードします:


1
root@afbf1fd4f78d:/# curl -Lks http://www.atlassian.com/software/stash/downloads/binary/atlassian-stash-2.4.2.tar.gz -o /root/stash.tar.gz

Stash をアンパックし、STASH_HOME フォルダを作成してエクスポートします:


1
2
3
4
root@202bf30a3b19:/# mkdir /opt/stash
root@202bf30a3b19:/# tar zxf /root/stash.tar.gz --strip=1 -C /opt/stash
root@202bf30a3b19:/# mkdir /opt/stash-home
root@202bf30a3b19:/# export STASH_HOME=/opt/stash-home

起動エラーを回避するためには、他のホストに対するこのホストのユニーク ID、202bf30a3b19 を付加する必要があります。

これで Stash を起動することができます:


1
root@202bf30a3b19:/# /opt/stash/bin/start-stash.sh -fg

http://localhost:7991/stash にアクセスして Stash がコンテナー内で実行されていることを確認してください (ここで Vagrant がホストの OSX にデータを引き渡すポートとして、7991 番を指定しました)。これで期待通りに動作します:

stash-login

ここでこのコンテナーから exit し、これまでの作業結果を再度利用できるようにコミットを設定します:


1
2
vagrant@vagrant-ubuntu-raring-64:~] $ docker commit aec2feb8cdea durdn/stash
effd5d47b34f

ここで、aec2feb8cdea は、docker ps -a において最後に変更が行われたコンテナーの ID です。
その結果として、durdn/stash という名称の、Stash がインストールされた新たなイメージが生成されます:


1
2
3
4
5
6
7
8
9
[vagrant@vagrant-ubuntu-raring-64:~] $ docker images

REPOSITORY          TAG                 ID                  CREATED
durdn/java7         latest              ab6396541f9a        2 hours ago
durdn/stash         latest              effd5d47b34f        3 seconds ago
base                ubuntu-quantal      b750fe79269d        10 weeks ago
base                ubuntu-quantl       b750fe79269d        10 weeks ago
base                latest              b750fe79269d        10 weeks ago
base                ubuntu-12.10        b750fe79269d        10 weeks ago

コンテナーの一時性と継続的格納領域

コンテナーは一時的なものでそれを停止するとスナップショットの状態に完全にリセットされます!

このことは、コンテナーを停止するたびに Stash のインストールもリセットされることを意味します。実行するたびに生成されるデータを確実に保存するには、volumes を使用してコンテナー間での共有と継続的利用を可能にします。これを行うにあたって、我々は -volumes-from オプションを使用して以前のコンテナーのボリュームを再利用する簡便な方法を採用しました。

コンテナーの Stash をインタラクティブな状態で起動します (-i を指定するとインタラクティブな状態で起動し、-t を指定するとそれに端末を接続します):



1
docker run -i -t -p :7990 -volumes-from aec2feb8cdea durdn/stash /bin/bash -c 'STASH_HOME=/opt/stash-home /opt/stash/bin/start-stash.sh -fg'

上の場合 Stash アプリケーションはフォアグラウンドで起動されますが、コンテナーをバックグラウンドで実行する場合は、-d フラグを使用します:


1
docker run -d -p :7990 -volumes-from aec2feb8cdea durdn/stash /bin/bash -c 'STASH_HOME=/opt/stash-home /opt/stash/bin/start-stash.sh -fg'

ご覧ください。Stash インスタンスがバックグラウンドで実行され、しかもデータは失われません。このことは docker ps コマンドを実行すると確認できます。

次のステップ

試してみたいことは他にもたくさんあります。今後利用する可能性が高まった場合は、次のような様々な興味深い点でこの使用例の内容を拡張していきます:
Dockerfile (Vagrantfile や puppet recipe と同様なコンセプト) を利用して手順を効率化し、再現性を向上する。
– PostgreSQL を含むスタンドアローンのコンテナーを設定してみる。
– 他のアトラシアン製品とリンクさせる。
– イメージのエクスポートとインポートを行う。

結論

Docker の気に入った点は反応性が非常によく動作も機敏なこと、そしてその動作における高い時間再現性です。多数のコンテナーを生成する場合でも、ベアメタルで該当のコマンドを実行する時間と文字通りに同一の時間しかかかりません。今後を楽しみにして注目していきます!


*本ブログは Atlassian Blogs の翻訳です。本文中の日時などは投稿当時のものですのでご了承ください。
*原文 : 2013 年 6 月 13 日 "Deploy Java Apps With Docker = Awesome"