DockerによるWebアプリのデプロイ方法をいくつか調べてみると、ビルド時間の短縮やメンテナンス性から、インフラレイヤーとアプリケーションレイヤーに分けて差分ビルドする方法が良さそうだったので、Play Frameworkアプリでデプロイを試してみました。
構成
- Ubuntu 12.04
- Docker 1.0.0
- Play Framework 2.2.3
インフラレイヤー
Java及びPlay Frameworkの実行環境までを構築します。
Dockerfileの構成
Dockerfileの構成は以下の通りです。
java ├──Dockerfile ├──id_rsa.pub ... 公開鍵 ├──play.sh ... 環境変数の定義ファイル ├──sources.list ... ミラーサイト一覧 └──supervisord.conf ... supervisorの定義ファイル
Dockerfile
Dockerfileを以下のように作成します。
$ cd java $ vi Dockerfile FROM ubuntu:12.04 MAINTAINER hidemium # Ubuntu update ADD sources.list /etc/apt/sources.list RUN apt-get -y update # ssh install RUN apt-get -y install openssh-server RUN apt-get -y install python-setuptools RUN apt-get clean RUN easy_install supervisor RUN mkdir /var/run/sshd RUN echo 'root:root' | chpasswd # sshd config ADD id_rsa.pub /root/id_rsa.pub RUN mkdir /root/.ssh/ RUN mv /root/id_rsa.pub /root/.ssh/authorized_keys RUN chmod 700 /root/.ssh RUN chmod 600 /root/.ssh/authorized_keys RUN sed -i -e '/^UsePAM\s\+yes/d' /etc/ssh/sshd_config # config supervisor RUN mkdir -p /var/log/supervisor RUN mkdir -p /etc/supervisor/conf.d/ ADD supervisord.conf /etc/supervisord.conf # Install Java RUN apt-get install -y software-properties-common python-software-properties RUN add-apt-repository ppa:webupd8team/java RUN apt-get update RUN echo "oracle-java7-installer shared/accepted-oracle-license-v1-1 boolean true" | debconf-set-selections ENV DEBIAN_FRONTEND noninteractive RUN apt-get install -y oracle-java7-installer # Install Play Framework ENV PLAY_VERSION 2.2.3 RUN apt-get install -y unzip RUN wget http://downloads.typesafe.com/play/$PLAY_VERSION/play-$PLAY_VERSION.zip RUN unzip play-$PLAY_VERSION.zip RUN mv play-$PLAY_VERSION /usr/local ADD play.sh /etc/profile.d/play.sh RUN sh /etc/profile.d/play.sh # Expose ports EXPOSE 22 9000 9999 # Define default command CMD ["supervisord", "-n"]
- 「RUN echo "oracle-java7-installer shared/accepted-oracle-..」と「ENV DEBIAN_FRONTEND noninteractive」は、Javaのライセンス承諾画面を飛ばすためにやっています。
- 「RUN wget http://downloads.typesafe.com/play/$PLAY_VERSION/play-$PLAY_VERSION.zip」は、Play Frameworkのパッケージをダウンロードしています。
Dockerfileの中で、読み込みを行っているファイルは以下の通りです。
sources.list
日本のミラーサイトを指定しています。
$ cat sources.list deb http://jp.archive.ubuntu.com/ubuntu precise main restricted deb-src http://jp.archive.ubuntu.com/ubuntu precise main restricted deb http://jp.archive.ubuntu.com/ubuntu precise-updates main restricted deb-src http://jp.archive.ubuntu.com/ubuntu precise-updates main restricted
play.sh
Java及びPlay Frameworkの環境変数を設定しています。
export JAVA_HOME=/usr/lib/jvm/java-7-oracle export PATH=$PATH:$JAVA_HOME/bin export CLASSPATH=.:$JAVA_HOME/jre/lib:$JAVA_HOME/lib:$JAVA_HOME/lib/tools.jar export PLAY_HOME=/usr/local/play-2.2.3 export PATH=$PATH:$PLAY_HOME
supervisord.conf
supervisorの設定とsshdの起動を定義しています。
$ cat supervisord.conf [unix_http_server] file=/tmp/supervisor.sock ; (the path to the socket file) [supervisord] logfile=/tmp/supervisord.log ; (main log file;default $CWD/supervisord.log) logfile_maxbytes=50MB ; (max main logfile bytes b4 rotation;default 50MB) logfile_backups=10 ; (num of main logfile rotation backups;default 10) loglevel=info ; (log level;default info; others: debug,warn,trace) pidfile=/tmp/supervisord.pid ; (supervisord pidfile;default supervisord.pid) nodaemon=false ; (start in foreground if true;default false) minfds=1024 ; (min. avail startup file descriptors;default 1024) minprocs=200 ; (min. avail process descriptors;default 200) [rpcinterface:supervisor] supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface [supervisorctl] serverurl=unix:///tmp/supervisor.sock ; use a unix:// URL for a unix socket [include] files = /etc/supervisor/conf.d/*.conf [program:sshd] command=/usr/sbin/sshd -D autostart=true autorestart=true
Dockerイメージのビルド
以下のコマンドで、Dockerfileからビルドし、ベースとなるDockerイメージを作成します。
$ sudo docker build -t ubuntu-java:12.04 .
アプリケーションレイヤー
上記のDockerイメージをベースに、Play Frameworkのアプリケーションをコンテナに追加し、本番モードで起動します。
なお、データベースはPlay Frameworkに内蔵しているH2 databaseを使用する想定です。
Dockerfileの構成
Dockerfileの構成は以下の通りです。
play ├──Dockerfile └──myapp ... Play Frameworkアプリケーションを格納したディレクトリ
上記の「myapp」には、git cloneなどでデプロイするPlay Frameworkアプリケーションをコピーしておきます。手元にPlay Frameworkアプリケーションがない場合は、ダウンロードしたPlay Frameworkのパッケージ内にsampleプログラムが格納されているため、こちらを使用することも可能です。
Dockerfile
Play Frameworkは、Play Frameworkのバージョンに依存しないように、単独で起動が可能なdistと呼ばれる配布パッケージを作成することができます。*1
以下では、stage向けとdist向けのDockerfileを用意しました。
stageデプロイ用
Dockerfileを以下のように作成します。
$ cd play $ vi Dockerfile FROM ubuntu-java:12.04 MAINTAINER hidemium RUN mkdir /myapp WORKDIR /myapp ADD myapp /myapp RUN bash -l -c 'play clean compile stage' RUN rm target/universal/stage/bin/*.bat EXPOSE 22 9000 CMD target/universal/stage/bin/$(ls target/universal/stage/bin) -DapplyEvolutions.default=true & \ supervisord -n
- 「FROM ubuntu-java:12.04」では、インフラレイヤーの箇所で作成したDockerイメージをベースにしています。
- 「ADD myapp /myapp」では、Play Frameworkアプリケーションをコンテナに追加します。
- 「ENTRYPOINT target/universal/stage/bin/$(ls target/universal/stage/bin) -DapplyEvolutions.default=true」では、Play Frameworkアプリケーションを本番モードで実行します。また、Evolutionsが自動実行されるようにオプションを指定しています。
distデプロイ用
Dockerfileを以下のように作成します。
distファイル(zipファイル)は、あらかじめ解凍し、myappをいうディレクトリにリネームしておきます。
$ cd play $ vi Dockerfile FROM ubuntu-java:12.04 MAINTAINER hidemium RUN mkdir /myapp WORKDIR /myapp ADD myapp /myapp RUN rm bin/*.bat EXPOSE 22 9000 CMD bin/$(ls bin) -DapplyEvolutions.default=true & \ supervisord -n
Dockerイメージのビルド
以下のコマンドで、Dockerfileからビルドし、Play FrameworkアプリケーションのDockerイメージを作成します。Play Frameworkの実行環境をベースに差分ビルドを行っているため、ビルド時間を短縮できます。
$ sudo docker build -t ubuntu-play:12.04 .
Play Frameworkアプリケーションのデプロイ
以下のコマンドで、Play Frameworkアプリケーションのコンテナを起動します。
$ sudo docker run -d -p 22 -p 9000 ubuntu-play:12.04
Dockerコンテナの9000番ポートにフォワードしているポート番号を確認します。
$ sudo docker port <コンテナID> 9000 0.0.0.0:<ポート番号>
「http://<サーバのIPアドレス>:<ポート番号>」にアクセスし、Play Frameworkアプリケーションに接続できることを確認します。
*1:distを使用する場合は、インフラレイヤーからPlay Frameworkをインストールしている箇所を削除してしまっても問題ありません。