Docker、Puppet、Vagrantによる 軽量コンテナの管理

7
ORACLE.COM/JAVAMAGAZINE ///////////////////////////// JULY/AUGUST 2015 19 記事では、継続的デリバリ(CD)およびDevOpsパイプラインでの 普及が進んでいる軽量の仮想化コンテナ「Docker」を紹介します。 Dockerとインフラストラクチャ定義ツールのPuppetを統合し、Puppet に対応したDockerイメージをビルドして、Puppetモジュールを利用す るコンテナの作成方法について説明します。また、この一連のツールを Vagrantと統合して、CDプラットフォームをさらに効率化します。本記事を 最後まで読むことで、これらのツールを使用して開発およびデリバリのプ ロセスを改善する方法を理解できます。 Dockerとは Dockerは、デプロイとプロビジョニングを自動化し、アプリケーションを 移植可能な軽量コンテナ内に格納してその配布を効率化するオープン ソースのフレームワークです。これらのコンテナは、ラップトップやクラウ ド、仮想マシン(VM)を含む幅広い場所で実行できます。Dockerコンテナ はDockerイメージから作成され、DockerイメージはDockerfileからビル ドされます。Dockerイメージは階層化されており、開発者は他のイメージ を基に新しいイメージを簡単に作成できます。DockerイメージはDocker レジストリに格納されます。 Dockerは以下の点で、CDおよびDevOpsの作 業改善に役立ちます。 生産的なワークスペースの実現。ローカル・マ シンでのテスト、配布、チーム内での共有など の目的で、複数の再現可能なコンテナを作成 できる。 統合フローの向上。継続的インテグレーショ ンのパイプラインを、Docker対応のビルド・ス レーブを利用して効率化できる。 デリバリ・パイプラインの促進。インテグレーションからデリバリまでの パイプラインを動的で再現可能なものとするために、パイプラインの 一貫としてミドルウェア用のDockerイメージを作成し、それらのイメー ジを新規にビルドしたビジネス・アプリケーションとともにオーケスト レーションできる。 バリエーションの限定。インフラストラクチャとビジネス・ロジックの両 方をDockerコンテナに追加できる。このように収束させて独立性を確 保できることから、標準のデプロイメント・ユニット(通常はJAR、WAR、 EARファイル)だけでなくJavaランタイム、ミドルウェア、構成も提供でき るため、 Javaの遍在性が一層現実化する。 平均修復時間(MTTR)の向上。Dockerコンテナがパイプライン内で視 覚化される。このような視覚性の向上によって、問題の分離や検出、お よび適切な担当者の割り当てをより早く実施できる。 多くのツール(Jenkins、 Maven など)やエンタープライズ・リポジトリ・ マネージャ( JFrogのArtifactory など)との統合。 コンテナとVMの違い 従来のVMは、物理的なハードウェアのオーバーヘッドを削減するための 優れた手段です。最近では、プロジェクトの開始時に物理的なハードウェ アをセットアップする必要性はほぼなくなりました。VMを追加するという 形で動的なスケールアウトを適宜行い、リソースを追加していくのが一般 的です。しかし、VMは、特に開発者の立場からは相当大きな負荷と考えら れています。開発者は数分ごとにコーディング/ビルド/テストを行う必要 があり、仮想化のオーバーヘッドが繰り返し発生することは望んでいませ ん。以降のセクションでは、このオーバーヘッドの具体的な内容に着目し、 Dockerによる解決方法を説明します。 VM内の仮想化された各アプリケーションに含まれているのは、数メガ Docker、Puppet、Vagrantによる 軽量コンテナの管理 DevOpsにおいてDockerコンテナのビルド、利用、オーケストレーションを行う方法 MICHAEL HÜTTERMANN VagrantはVMの動的な プロビジョニン グと管理を行う ための無償 ツールです。 DevOps Michael Hüttermann CD、DevOps、 Agile ALM分野 で活躍する自営 の専門家。Oracle Java Champion。 Twitterア カウントは @huettermann。

Transcript of Docker、Puppet、Vagrantによる 軽量コンテナの管理

Page 1: Docker、Puppet、Vagrantによる 軽量コンテナの管理

ORACLE.COM/JAVAMAGAZINE ///////////////////////////// JULY/AUGUST 2015

19

本記事では、継続的デリバリ(CD)およびDevOpsパイプラインでの普及が進んでいる軽量の仮想化コンテナ「Docker」を紹介します。

Dockerとインフラストラクチャ定義ツールのPuppetを統合し、Puppetに対応したDockerイメージをビルドして、Puppetモジュールを利用するコンテナの作成方法について説明します。また、この一連のツールをVagrantと統合して、CDプラットフォームをさらに効率化します。本記事を最後まで読むことで、これらのツールを使用して開発およびデリバリのプロセスを改善する方法を理解できます。

DockerとはDockerは、デプロイとプロビジョニングを自動化し、アプリケーションを移植可能な軽量コンテナ内に格納してその配布を効率化するオープンソースのフレームワークです。これらのコンテナは、ラップトップやクラウド、仮想マシン(VM)を含む幅広い場所で実行できます。DockerコンテナはDockerイメージから作成され、DockerイメージはDockerfileからビルドされます。Dockerイメージは階層化されており、開発者は他のイメージを基に新しいイメージを簡単に作成できます。DockerイメージはDockerレジストリに格納されます。Dockerは以下の点で、CDおよびDevOpsの作業改善に役立ちます。 ■ 生産的なワークスペースの実現。ローカル・マシンでのテスト、配布、チーム内での共有などの目的で、複数の再現可能なコンテナを作成できる。 ■ 統合フローの向上。継続的インテグレーションのパイプラインを、Docker対応のビルド・スレーブを利用して効率化できる。

■ デリバリ・パイプラインの促進。インテグレーションからデリバリまでのパイプラインを動的で再現可能なものとするために、パイプラインの一貫としてミドルウェア用のDockerイメージを作成し、それらのイメージを新規にビルドしたビジネス・アプリケーションとともにオーケストレーションできる。 ■ バリエーションの限定。インフラストラクチャとビジネス・ロジックの両方をDockerコンテナに追加できる。このように収束させて独立性を確保できることから、標準のデプロイメント・ユニット(通常はJAR、WAR、EARファイル)だけでなくJavaランタイム、ミドルウェア、構成も提供できるため、Javaの遍在性が一層現実化する。 ■ 平均修復時間(MTTR)の向上。Dockerコンテナがパイプライン内で視覚化される。このような視覚性の向上によって、問題の分離や検出、および適切な担当者の割り当てをより早く実施できる。 ■ 多くのツール(Jenkins、Mavenなど)やエンタープライズ・リポジトリ・マネージャ(JFrogのArtifactoryなど)との統合。

コンテナとVMの違い従来のVMは、物理的なハードウェアのオーバーヘッドを削減するための優れた手段です。最近では、プロジェクトの開始時に物理的なハードウェアをセットアップする必要性はほぼなくなりました。VMを追加するという形で動的なスケールアウトを適宜行い、リソースを追加していくのが一般的です。しかし、VMは、特に開発者の立場からは相当大きな負荷と考えられています。開発者は数分ごとにコーディング/ビルド/テストを行う必要があり、仮想化のオーバーヘッドが繰り返し発生することは望んでいません。以降のセクションでは、このオーバーヘッドの具体的な内容に着目し、Dockerによる解決方法を説明します。VM内の仮想化された各アプリケーションに含まれているのは、数メガ

Docker、Puppet、Vagrantによる 軽量コンテナの管理DevOpsにおいてDockerコンテナのビルド、利用、オーケストレーションを行う方法

MICHAEL HÜTTERMANN

Vagrantは、 VMの動的な プロビジョニングと管理を行うための無償 ツールです。

DevOps

Michael Hüttermann:CD、DevOps、Agile ALM分野で活躍する自営の専門家。Oracle Java Champion。Twitterアカウントは@huettermann。

Page 2: Docker、Puppet、Vagrantによる 軽量コンテナの管理

ORACLE.COM/JAVAMAGAZINE ///////////////////////////// JULY/AUGUST 2015

20

バイト程度のアプリケーションと必要なバイナリ、ライブラリ、パッケージですが、それだけではありません。数ギガバイトもあるようなゲスト・オペレーティング・システム全体も含まれており、広範囲なスタックが形成されてしまいます(図1を参照)。DockerコンテナのメカニズムはVMとは異なり、アプリケーションとその依存先のファイルのみで構成されます。Dockerコンテナはホスト・オペレーティング・システムのユーザー領域内で、独立した1つのプロセスとして動作する一方で、カーネルを他のコンテナと共有します。そのため、VMが持つリソースの独立性と割当ての利点を得ながらも、負荷は大幅に小さくなります。Dockerスタックの概要図を図2に示します。この図には、ハイパーバイザもゲストOSも存在しません。DockerエンジンはLinuxの技術を基盤として構築されており、たとえば、カーネルのcgroupや、Linuxコンテナ(lxc)による名前空間の分離などを取り入れています。

Dockerスタックのビルド Dockerの軽量性により、今までにないような動きをするホスト、アプリケーション、サービスが可能になります。特に、実行時間が短く、破棄可能な単一のサービスをコンテナで提供できる点は注目に値します。数年前にサービス指向アーキテクチャ(SOA)と呼ばれていたものは、現在はマイクロサービスと呼ばれるようになりました。 次に、異なるサービスをスライスするDockerのユースケースを確認します。これらのサービスは、レイヤー、あるいはDockerコンテナとも呼ばれます。実環境では、アーキテクチャ・レイヤーに沿ったコンテナの分割か、あるいは変更の頻度に応じたコンテナの分割が適しています。たとえば、変更頻度の低い部分(ミドルウェアなど)に対して1つのDockerイメージを作成し、変更頻度の高い部分(ビジネス・アプリケーションなど)に対してはそれぞれ専用のDockerイメージを作成します。 筆者が作成したサンプルは、Ubuntu Linuxバージョン14.04のベース・イメージ上

でJava 7が稼働します。このサンプルは、インフラストラクチャ・コンポーネントを含む再利用可能なイメージとして想定しているため、infraイメージと呼んでいます。このイメージの上に、ミドルウェア(ここではTomcat 7)を実行するイメージを配置します(図

3を参照)。後でこのイメージの上にビジネス・アプリケーションをインストールします。 どうすればこの構成を実現できるでしょうか。前述のとおり、DockerイメージはDockerfileと呼ばれるDocker定義ファイルからビルドされます。このファイルはプレーン・テキスト・ファイルであり、専用のディレクトリに配置されます。次に、以降のDockerfileについて考察します。

リスト1:(前の行から連続して記述すべき行はインデント付きで表しています)FROM ubuntu:14.04 MAINTAINER Michael Huettermann# Update UbuntuRUN apt-get update && apt-get -y upgrade# Add oracle java 7 repositoryRUN apt-get -y install software-properties-commonRUN add-apt-repository ppa:webupd8team/javaRUN apt-get -y update# Accept the Oracle Java licenseRUN echo "oracle-java7-installer shared/accepted-oracle-license-v1-1 boolean true" | debconf-set-selections

図3.サンプルのスタック図2.典型的なDockerスタック図1.典型的なVMスタック

Page 3: Docker、Puppet、Vagrantによる 軽量コンテナの管理

ORACLE.COM/JAVAMAGAZINE ///////////////////////////// JULY/AUGUST 2015

21

# Install Oracle JavaRUN apt-get -y install oracle-java7-installer

リスト1では、ベース・イメージ(ubuntu:14.04)から派生したDockerイメージを定義しています。多数のDockerイメージが無償で提供されており、独自のDockerアクティビティの基本イメージとして使用できます。詳細については、Docker Hubレジストリを参照してください。 このイメージの作成者に関するメタタグ(MAINTAINER)の後に、一連のRUNステー

トメントが続きます。それぞれのステートメントには、ターゲット・システムに適用されるシェル・ステートメントが記述されています。Java 7がインストールされるこのイメージは、後のイメージの親イメージとして使用できます。このイメージをinfraと呼ぶことにします。この親イメージ(infra)を基に、Tomcat 7を実行する2つ目のイメージを作成します。さらに、このイメージは、標準のJavaデプロイメント・ユニット(ここではWARファイル)形式のビジネス・アプリケーションを実行します。対応するDockerfileを見てみます。

リスト2:(前の行から連続して記述すべき行はインデント付きで表しています)FROM infraMAINTAINER Michael Huettermann# Install curlRUN apt-get -y install curl# Install tomcatRUN apt-get -y install tomcat7RUN echo "JAVA_HOME=/usr/lib/jvm/java-7-oracle" >> /etc/default/tomcat7ADD run.sh /root/run.shRUN chmod +x /root/run.shRUN curl -o /var/lib/tomcat7/webapps/all.war http://dl.bintray.com/mh/meow/all-1.0.0-GA.warEXPOSE 8080CMD ["/root/run.sh"] リスト2の内容を簡単に確認します。最初に、親イメージを定義し、cURLをインストールして、ファイルのダウンロードを簡単に処理できるようにしています。次に、Tomcat 7をインストールしています。ADDステートメントで、ホストのシェル・スクリプトをイメージに追加した(つまりコピーした)後、リモート・ソース(Bintray)からWARファイルをダウンロードし、それをTomcatのデプロイメント・ディレクトリにドロップして、Webアプリケーションをインストールしています。また、ポートを公開しています(このサンプル

では、ポート8080をコンテナ内で使用して、ホスト・システムや他のコンテナからアクセスできるようにしています)。最後に、CMDステートメントを呼び出してDockerfile定義をクローズしています。このステートメントは、コンテナが作成されてイメージから起動されるときに実行されるコマンドです。 次に、参照先のシェル・スクリプト「run.sh」の詳細について考察します。

#!/bin/bash/etc/init.d/tomcat7 start# The container will run as long as the script is running, # which is why we need something long-lived hereexec tail -f /var/log/tomcat7/catalina.out

このスクリプトは単なるヘルパー・スクリプトです。手短に言えば、Dockerコンテナは、コンテナ内部でプロセスが実行されている限り実行し続けます。このシェル・スクリプトの実行で、Tomcat 7の起動とログ・ファイル「catalina.out」の監視のみを行います。ログ・ファイルの監視は終わりのないアクティビティですから、コンテナは稼働し続けます。このスクリプトは、コンテナの起動時に呼び出されます。次に、1つ目のイメージを(1行のみで)ビルドします。

mh@saturn:~/work/ws-git/sandbox/docker/Infra$ docker build -t infra .

このコマンドでは、Dockerクライアントのdockerを、イメージをビルドするためのbuildパラメータ付きで実行し、そのイメージにinfraという名前を付けています(注:本記事では、Docker 1.6.2、Puppet 3.4.3、Vagrant 1.7.2を使用しています)。この名前は、後でDockerイメージを参照するためのタグとして使用できます。このDockerfileはカレント・ディレクトリにあります(カレント・ディレクトリは、コマンド末尾のピリオドで表しています)。このビルド実行結果のコンソール出力(リスト3を参照)には、Dockerfileの個々のステップの実行状況が表示されます。Dockerは、ビルドの実行時に情報をキャッシュします。つまり、Dockerでは、再実行時、各ステップを1つづつやり直さないため、さらに軽量化されます。最後にイメージID(この例では「56763a4909fd」)が出力されています。この省略形の出力は、長い64桁の16進数文字列(内部的には256ビットの値)を12文字で表したバージョンです。このイメージIDを使用して、イメージの参照や操作を行うことができます。

Vagrant のユースケースとして、Docker のラッパーとして使用してDocker を簡単に利用できるようにすることも挙げられます。

Page 4: Docker、Puppet、Vagrantによる 軽量コンテナの管理

ORACLE.COM/JAVAMAGAZINE ///////////////////////////// JULY/AUGUST 2015

22

リスト3:(前の行から連続して記述すべき行はインデント付きで表しています)Step 0 :FROM ubuntu:14.04 ---> 96864a7d2df3Step 1 :MAINTAINER Michael Huettermann ---> Using cache ---> 3301dda0a0daStep 2 :RUN apt-get update && apt-get -y upgrade ---> Using cache ---> 7a12064df01fStep 3 :RUN apt-get -y install software-properties-common ---> Using cache ---> 8933d7229655Step 4 :RUN add-apt-repository ppa:webupd8team/java ---> Using cache ---> ea29295e48f5Step 5 :RUN apt-get -y update ---> Using cache ---> f5925321a8b4Step 6 :RUN echo "oracle-java7-installer shared/accepted-oracle-license-v1-1 boolean true" | debconf-set-selections ---> Using cache ---> eaa1489a641fStep 7 :RUN apt-get -y install oracle-java7-installer ---> Using cache ---> 56763a4909fdSuccessfully built 56763a4909fd

本記事のサンプルでは前述のとおり、1つ目のイメージを基に、Tomcat 7イメージをビルドします。

mh@saturn:~/work/ws-git/sandbox/docker/Tomcat7$ docker build -t tomcat7 .このコマンドは、もう1つのDockerfileが存在するディレクトリに移動して実行しています。実行結果の出力は1つ目の出力と似ていますが、言うまでもなく、2つ目のDockerfileに固有のステップに合った出力になります。また、最後に固有のイメージID

(この例では「84b753ed5e9d」)が出力されます。この時点で、docker imagesコマンドを実行

して利用可能なイメージを表示すると、このイメージIDを持つ、仮想サイズが801.9メガバイトのtomcat7の情報が表示されます。

イメージの実行次に、静的ビュー(イメージ)から動的ビュー(コンテナ)へと移ります。docker runコマンドによって、イメージを基にコンテナが実行されます。

docker run -p 8080:8080 -d tomcat7

このコマンドでは、tomcat7イメージからコンテナを生成しています。Dockerをデーモンとして実行し(-d)、ホストとゲスト・システム間でポートをマッピングしています(-p)。正常に稼働すれば、コンテナ識別子が得られます。その後、新しく作成したコンテナが実行されているかをdocker psによって確認すると、コンテナは実行中であり、ポート8080がマッピングされていることが分かります。アクティブなDockerプロセスをすべて表示すると、新しく作成されたDockerコンテナが表示されます。包括的で強力なDocker APIを本記事では詳しく扱いませんが、Dockerのコンテキストでは多くのシェル・コマンドを組み合わせることができることを覚えておいてください。たとえば、docker stop $(docker ps -a -q)と入力すると、すべてのコンテナが停止します。また、docker rm $(docker ps -a -q)と入力すると、すべてのコンテナが削除されます。サンプルのDockerを実行した結果、十分な機能を備えたDockerコンテナのもと、Java 7、Tomcat 7、デプロイ済みのWARファイルが実行されています。

DockerとPuppet以上で従来のDockerfileでDockerコンテナをセットアップしました。これを踏まえて、DockerコンテナをPuppetによってプロビジョニングする方法を詳しく学習します。ただし、この方法でも、Docker自体のホストへのインストール、管理、デプロイは必要です。また、そのホストの管理も必要になります。さらに、Dockerコンテナについても、外部のサービスやツールとともにオーケストレーション、管理、デプロイを行う必要があるかもしれません。

Docker の軽量コンテナは従来の VMと比較して高速であり、開発者の間で普及が進んでいます。

Page 5: Docker、Puppet、Vagrantによる 軽量コンテナの管理

ORACLE.COM/JAVAMAGAZINE ///////////////////////////// JULY/AUGUST 2015

23

Puppet、Chef[編集注:26ページのChef関連記事を参照]、Ansibleなどの構成管理ツールの利用は最近の主流となっています。これらの構成管理ツールは、ミドルウェア、サービス、ビジネス・アプリケーションを含めたターゲット・システムを、再現可能かつ信頼性のある方法でプロビジョニングします。これらの多様な管理ニーズと、Docker自体を管理する必要性が重なった結果、今後は多くの組織でDockerと構成管理ツールの両方がデプロイされるようになると筆者は見ています。実際、コンテナ、構成管理、継続的インテグレーション、継続的デリバリ、サービス・オーケストレーションを組み合わせた強力なツール・チェーンには大きな可能性があります。Puppetは、リリースから何年も経っており、システム管理者や開発者がシステムの

ターゲットの動作を宣言的に記述できるため、広く普及しています。

PuppetとTomcat 7によるサンプルTomcat 7をセットアップする先ほどのサンプルに戻ります。Puppetを使用した場合、このサンプルはどうなるでしょうか。図4に、このスタックの概要を示します。ここで、次のDockerfileについて確認します。

FROM infraMAINTAINER Michael Huettermann

RUN apt-get -y updateRUN apt-get -y install puppet librarian-puppet

RUN puppet module install puppetlabs-stdlibRUN puppet module install puppetlabs-tomcat RUN puppet module install puppetlabs-java ADD site.pp /root/site.ppRUN chmod +x /root/site.ppADD run.sh /root/run.shRUN chmod +x /root/run.sh

EXPOSE 8080

CMD ["/root/run.sh"]

この場合も、infraから派生したイメージを作成しています。準備作業として、新しいバージョンでシステムを更新し、さらにLibrarian-puppetをインストールして各種Puppetモジュールを異なる入力チャネルからシームレスにインストールできるようにし、その後、いくつかのPuppetモジュールをインストールしています。Puppetは、優れたモジュール性で知られており、プラグインして直接利用できる多数のモジュールが無償で提供されています。ここでは特に、Puppet Tomcatモジュールに注目します。このモジュールは、Tomcatのインストールと構成を行うものです。サンプルのDockerfileには、site.ppというPuppetのマニフェスト(リスト4)も埋め込まれています。

リスト4: class { 'tomcat':} ->class { 'java':} ->tomcat::instance { 'install': source_url => 'http://mirrors.ae-online.de/apache/tomcat/ tomcat-7/v7.0.62/bin/apache-tomcat-7.0.62.tar.gz'} ->exec { 'run': command => '/opt/apache-tomcat/bin/catalina.sh start' } ->tomcat::war { 'all.war': catalina_base => '/opt/apache-tomcat', war_source => 'http://dl.bintray.com/mh/meow/all-1.0.0-GA.war',}

Puppetマニフェストの基本については本記事では扱いませんが(この点についてはPuppetのドキュメントを参照してください)、Puppetでターゲット・システムの状態を宣言的に記述できるおかげで、Puppetマニフェストを見れば状況が直接伝わります。

図4.現時点のサンプルのスタック

Page 6: Docker、Puppet、Vagrantによる 軽量コンテナの管理

ORACLE.COM/JAVAMAGAZINE ///////////////////////////// JULY/AUGUST 2015

24

このマニフェストでは、Tomcatバージョン7をインストールした後に起動し、WARファイルをデプロイしています。リスト4の矢印(->)の連鎖に特に注目してください。ハイフンと大なり記号で書かれたこの順序付け用の矢印は、左側のリソースを適用してから右側のリソースを適用することを示します。この表記法の利用は重要です。Tomcatが起動するまではWARファイルをデプロイできず、TomcatがインストールされるまではそのTomcatの起動も実行できないためです。また、このファイルはデモに限定した目的で作成したものであり、その点に留意してください。実際のプロジェクトでは、たとえば、Tomcatインスタンスをサービスとして実行することになります。次に、run.shスクリプトを確認します。

#!/bin/bashpuppet apply /root/site.pp

# The container will run as long as the script is running, # i.e. starting a long-living process:exec tail -f /opt/apache-tomcat/logs/catalina.out

このスクリプトのおもな目的は2つあります。1つは、Puppetを呼び出すことです(Puppet Masterを使用せず、単にローカルで呼び出します)。もう1つは、先ほどと同じく長時間実行プロセスを起動することです。このサンプルでもTomcatのログを表示しています。コンテナのDockerログをdocker logs -f [container-id]で監視する場合、こうしたログ表示が役に立ちます。Do c k e rイメージのビルド(do c k e r b u i l d - t t om c a t 7 p u p p e t .)

によって新しいイメージが作成されます。このイメージはdocker run -p 8080:8080 -it tomcat7puppetによって起動できます。このサンプルでは、Dockerをインタラクティブに実行しています。この処理の途中で、PuppetによりTomcatがインストールされたことが直接出力されます。次に、Vagrantによってこのシステムの価値がどのように高められるかについて説明します。

VagrantとDockerVagrantは、VMの動的なプロビジョニングと管理を行うための無償ツールです。Dockerの登場により、VagrantはDockerプロビジョナおよびDockerプロバイダとともに使用できるようになりました。Dockerプロビジョナは、Dockerのインストール、Dockerコンテナの取得、Dockerコンテナの構成を自動的に行うことができます。

VagrantはOracle VM VirtualBoxをサポートすることで知られていますが、VirtualBox以外のマシンも管理できます。つまり、VirtualBox以外のプロバイダとVagrantの組み合わせです。Vagrantの最近のバージョンではDockerがプロバイダとしてサポートされているため、VMではなくDockerコンテナを基盤として開発環境を構築できます。さらに、VagrantはDockerfileの開発においても最適なワークフローを提供します。VagrantはVagrantfileに基づいて動作します。以下のVagrantfileは、Dockerを、tomcat7puppetイメージを参照するプロバイダとして定義しています。 Vagrant.configure("2") do |config| config.vm.provider "docker" do |d| d.image = "tomcat7puppet" d.ports = [ "8080:8080" ] endend

現時点でこのVagrantfileを使用してVagrantを起動すると、以下のように出力されます。

$ vagrant up --provider=dockerBringing machine 'default' up with 'docker' provider...==> default:Creating the container... default: Name:Vagrant_default_1432553691 default:Image: tomcat7puppet default:Volume:/home/mh/vagrant:/vagrant default: Port:8080:8080 default: default:Container created:92a523444abbd3c4==> default:Starting container...

Vagrantには、Dockerと併用した場合にいくつかの大きな利点があります。VagrantとDockerを併用する重要なユースケースの1つとして、VagrantをDockerのラッパーとして使用する方法が挙げられます。Dockerを簡単に利用できるようになり、複数のDockerコンテナのオーケストレーションと管理を行う場合に特に有効です(複数のコンテナを扱う手段は、Vagrant以外にも、Docker Compose、Docker Swarm、Kubernetes、fabric8など多数存在します)。 たとえば、リスト5のDockerfi leでは、本記事ですでに作成した2つのコンテナ

(Tomcatを起動するものと、TomcatをPuppetで起動するもの)を並行して起動しています。実行中のTomcatインスタンスの両方へホスト・システムからアクセスできるように(2つのコンテナの両方で、Tomcatインスタンスがポート8080で実行されてい

Vagrant は抽象化の面ではDockerよりも一段上にあり、ほとんどのケースで厳密には比較できません。

Page 7: Docker、Puppet、Vagrantによる 軽量コンテナの管理

ORACLE.COM/JAVAMAGAZINE ///////////////////////////// JULY/AUGUST 2015

25

る)、それぞれ固有のポートをフォワードしています。

リスト5: Vagrant.configure("2") do |config| config.vm.define "v1" do |a| a.vm.provider "docker" do |d| d.image = "tomcat7" d.ports = ["8081:8080"] d.name = "tomcat" end end config.vm.define "v2" do |a| a.vm.provider "docker" do |d| d.image = "tomcat7puppet" d.ports = ["8082:8080"] d.name = "puppet" end end end

見てのとおり、オーケストレーションは非常に簡単です。

本番環境に近いコンテナに向けてVagrantは、Dockerをネイティブにサポートするシステムでは、Dockerラッパーとして動作できます。それ以外のシステムでは、Vagrantは「ホストVM」を駆使してコンテナを実行します。Dockerがネイティブにサポートされているかを開発者が判断する必要はありません。同じ構成がすべてのオペレーティング・システムで動作するようになっています。その目的で、Tiny Core LinuxのVirtualBoxイメージであるboot2dockerが使用されます。ただし、このごく小さなイメージが、本番環境に近いセットアップを反映することはほぼありません。そのため、このイメージを本格的なLinuxディストリビューションに置き換えて、その状態でDockerとともにプロビジョニングする必要があります。リスト6を参照してください。Vagrantプロバイダとして、Ubuntu Trusty64上のVirtualBoxを定義し(本番環境に近いVMをセットアップするため)、さらにVagrantプロビジョナとして、シェル(ブートストラップ用)、Puppet(インフラストラクチャのセットアップ用)、およびDocker(ミドルウェアとビジネス・アプリケーションのセットアップ用)を定義しています。単純明快だと思いませんか。

リスト6: Vagrant.configure(2) do |config| config.vm.define "with-docker" config.vm.provider "virtualbox" do |v| v.name = "_withDocker" end config.vm.box = "ubuntu/trusty64" config.vm.box_check_update = false config.vm.provision :shell, path:"bootstrap.sh" config.vm.provision "puppet" do |puppet| puppet.manifests_path = "manifests" puppet.manifest_file = "default.pp" end config.vm.provision "docker" do |d| d.build_image "/vagrant/docker/Tomcat7PuppetFull", args:"-t tomcat7dockerfromvagrant" d.run "tomcat7dockerfromvagrant", args:"-p 8080:8080" end

まとめDockerの軽量コンテナは従来のVMと比較して高速であり、開発者の間で、CDやDevOpsに対する取組みの一貫として普及が進んでいます。独立性の確保を目的としている場合は、Dockerが最適な選択肢です。 Vagrantは、個々のVMの構成をスクリプトに記述でき、プロビジョニングも実行で

きるVMマネージャです。ただし、VagrantはVirtualBox(あるいはそれ以外のVMマネージャ)に依存するVMであり、比較的大きなオーバーヘッドが発生します。巨大化する可能性のあるハード・ディスクのファイルを管理する必要があり、大量のRAMが消費され、最適なパフォーマンスが得られない場合があります。Dockerはカーネルのcgroupと、lxcによる名前空間の分離を利用します。そのため、ホストと同じカーネルを利用し、同じファイル・システムを利用することになります。Vagrantは抽象化の面ではDockerよりも一段上にあり、厳密には比較できません。 Puppetなどの構成管理ツールは、ターゲット環境をプロビジョニングする目的で広

く利用されています。Dockerと併用すれば、既存のPuppetベースのソリューションの再利用が簡単になります。また、ソリューションをスライスすることも可能です。インフラストラクチャをPuppetによりプロビジョニングし、ミドルウェア、ビジネス・アプリケーション自体、またはその両方をDockerによりプロビジョニングして、さらにDockerをVagrantによってラップします。このような幅広いツールを利用して、各自のシナリオにもっとも適した構成を実現できます。</article>