hidemium's blog

日々学んだことをアウトプットする。

DockerでPlay Frameworkアプリケーションをデプロイする

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"]

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
  • 「FROM ubuntu-java:12.04」では、インフラレイヤーの箇所で作成したDockerイメージをベースにしています。
  • 「ADD myapp /myapp」では、Play Frameworkアプリケーションをコンテナに追加します。
  • 「ENTRYPOINT bin/$(ls bin) -DapplyEvolutions.default=true」では、Play Frameworkアプリケーションを本番モードで実行します。distファイルは、stage用と比べてパスがシンプルになっています。

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をインストールしている箇所を削除してしまっても問題ありません。