Docker初心者がimageファイルを開発してみる[Mac]



## はじめに

最近、Dockerを勉強しはじめたので、実際に自分でもimageファイルとかいうものを作成してみたいと思った。
最終的には、Elastic BeanstalkにScala & Play2で作ったWEBアプリをデプロイしたい。

## 開発サイクル

imageファイルの開発は、細かくわけてやったほうが良さそうに思われる。

たとえば、javaやscalaやplayをインストールしたimageを最初に用意しておき、[Docker Hub](https://hub.docker.com/)に登録してしまう。
次に、それをもとにplayアプリケーションを構築していけばいいのではなかろうか…。

> [Docker Hub](https://hub.docker.com/)は、ユーザーが作ったimageファイルを公開できる場所…と思われる。

scalaやplayをバージョンアップしたいときには、最初のimageを更新すれば、それに依存するimageもDockerfileを書き換えることなく更新できそう。

## 準備

### １．Dockerのインストール

まずは、Dockerをインストールしておきます。
Macの場合は、[https://github.com/boot2docker/osx-installer/releases](https://github.com/boot2docker/osx-installer/releases)から、緑色のボタン(Boot2Docker-X.X.X.pkg)を押してインストーラーをダウンロードするのが早そうです。

### ２．Docker Hubへの登録

[Docker Hub](https://hub.docker.com/)に会員登録しておきます。

### ３．AWSへの登録（必要なら）

Elastic Beanstalkを使いたい場合には、[AWS](http://aws.amazon.com/jp/)に登録しておきましょう。

### ４．VirtualBoxにUbuntu環境を構築

Macの場合、インストーラーを使うとVirtualBoxがインストールされます。
せっかくVirtualBoxがありますし、Ubuntuも簡単に使えるようにしておいたほうが、imageファイルの構築のときに役に立つので、出来ればインストールしておいたほうが良いと思います。

>apt-get とかに不慣れな人は練習用におすすめ

インストール方法は、↓この辺を参考に。

[VirtualBoxにUbuntu 14.04 LTSをインストールする（準備編）](http://zakkiweb.net/a/20/)
[VirtualBoxにUbuntu 14.04 LTSをインストールする（インストール編）](http://zakkiweb.net/a/21/)

## セットアップ

Dockerをセットアップしておきます。

```shell:
$ boot2docker init
$ boot2docker up
```

上記を実行すると、shellに変数をexportするように指示されますので、そのとおりにexportしておきます。
（これをしないとエラーがでます。）

```shell:
$ export DOCKER_HOST=tcp://localhost:2375
```

# 実例

## Ubuntu14.04にjava,scala,play2をインストールしたイメージを作る

すでに、そういうイメージはDocker Hubで公開されているでしょうが、それでは勉強にならないので１から構築していきます。

#### １．必要なパッケージを選ぶ

・Javaの実行環境
・Scala開発環境
・Play2 Framework

が動く環境を構築できればオッケーですので、java & scala & play2 をインストールするDockerfileを書いて、エラーがでたら足りないコマンドをapt-getするように、Dockerfileを修正していく方法をとりました。

#### ２．Dockerfileを書く

空のディレクトリを作成して、そこにDockerfileというテキストファイルを作成します。

```shell:
$ mkdir java8-scala211-play23
$ cd java8-scala211-play23/
```

```text:Dockerfile
FROM ubuntu:14.04
MAINTAINER Jun Suzuki

# Update apt-get sources AND install packages
RUN        apt-get update
RUN        apt-get install wget unzip aptitude dpkg debconf -yy
RUN        aptitude install software-properties-common -yy

## Java
RUN sudo add-apt-repository -y ppa:webupd8team/java \
&& sudo apt-get -y update \
&& yes | sudo apt-get install oracle-java8-installer

## Scala
RUN wget http://downloads.typesafe.com/scala/2.11.2/scala-2.11.2.tgz -P /home/docker \
&& tar zxvf /home/docker/scala-2.11.2.tgz -C /home/docker \
&& sudo mv /home/docker/scala-2.11.2 /usr/local \
&& ln -s /usr/local/scala-2.11.2 /usr/local/scala

## Play
RUN mkdir -p /home/docker/bin \
&& wget http://downloads.typesafe.com/typesafe-activator/1.2.2/typesafe-activator-1.2.2.zip -P /home/docker \
&& unzip /home/docker/typesafe-activator-1.2.2.zip -d /home/docker \
&& ln -s /home/docker/activator-1.2.2/activator /home/docker/bin/activator

# Set Environment
ENV        HOME         /home
ENV        PATH         /bin:/usr/bin:/usr/local/scala/bin:/home/docker/bin/
ENV        JAVA_HOME    /usr/lib/jvm/java-8-oracle
ENV        SCALA_HOME   /usr/local/scala

# Timezone Setting
RUN     echo "Asia/Tokyo" > /etc/timezone
RUN     /usr/sbin/dpkg-reconfigure -f noninteractive tzdata
```

>参考： [Docker開発環境 - Typesafe ActivatorでScalaをインストール](http://masato.github.io/2014/06/29/docker-devenv-scala-typsafe-activator/)



※ Dockerfileの作成途中でdpkg-reconfigureが見つからなかったので、下記を実行してどこにあるのか調べました。

```shell:
$ docker run junsuzuki/java8-scala211-play23 which dpkg-reconfigure
/usr/sbin/dpkg-reconfigure
```

'docker run イメージ名' に続けてLinuxのコマンドが使えるので、困ったときには役立ちます。

#### ３．ビルド

Dockerfileを書いたら、ビルドしてimageファイルを作ります。

```shell:
$ docker build -t junsuzuki/java8-scala211-play23 ./
```

>junsuzukiのところは、Docker Hubでの自分のユーザー名を使います。

#### ４．作成したimageファイルをDocker Hubにアップする

```shell:
$ docker login
$ docker push junsuzuki/java8-scala211-play23
```

>参考： [Dockerコンテナをクラウドサービス上で共有できる「Docker Hub」を使ってみる](http://knowledge.sakura.ad.jp/tech/2210/)


## play2のサンプルアプリケーションをElastic Beanstalkにデプロイ

上記のimageファイルにplayサンプルアプリケーションを追加したimageファイルを作ります。

#### １．Playのサンプルアプリケーションを作成する

```shell:
$ cd ..
$ activator new play-sample play-scala
```

#### ２．Playアプリのコンパイル

作成したplayサンプルアプリケーションのディレクトリに移動して、playアプリをコンパイルしておきます。

```shell:
$ cd play-sample/
$ activator clean compile stage
```

#### ３．Dockerfileを書く

Dockerfileを書きます。
さきほどDocker Hubにアップしたimageを元にするので、'FROM'にさきほどのイメージを指定します。

>イメージは、[Docker Hubに公開](https://registry.hub.docker.com/u/junsuzuki/java8-scala211-play23/)していますのでご自由にお使いください。

```text:Dockerfile
FROM junsuzuki/java8-scala211-play23
MAINTAINER Jun Suzuki

# Copy the app into the image.
ADD ./target /opt/playapp

# Start	app
EXPOSE     80
CMD /opt/playapp/universal/stage/bin/play-sample -Dhttp.port=80
```


#### ４．ビルド

Dockerfileを書いたら、ビルドしてimageファイルを作ります。

```shell:
$ docker build -t junsuzuki/play-sample ./
```

#### ５．作成したimageファイルを実行してみる

Macの場合、ポートフォワーディングの設定をしておきます。
ここでは説明しないので、詳しくは、[こちらのサイト](http://dev.classmethod.jp/tool/docker/getting-started-docker-on-osx/)を参考にしてください。

```shell:
$ docker run -p 80:80 junsuzuki/play-sample
```

あとは、ブラウザで http://localhost:8080 にアクセスすればplayサンプルアプリが表示されます。


#### ６．作成したimageファイルをElastic Beanstalkにデプロイする

まずは、Dockerrun.aws.jsonファイルを作成します。

```json:Dockerrun.aws.json
{
  "AWSEBDockerrunVersion": "1",
  "Ports" : [{ "ContainerPort": "2375" }]
}
```

>Tip: zipに固めるときには、"Image"タグは入れてはいけないらしいです。Dockerfileですでに指定あるから、という理由っぽい。

次に、Dockerfile, Dockerrun.aws.json, targetディレクトリをまとめてzipに固めます。

>targetディレクトリを含めるのは、DockerfileのADDで指定しているため。

```shell:
$ zip -r app.zip target/ Dockerfile Dockerrun.aws.json
```

できたzipファイルをブラウザで、AWSコンソールからElastic Beanstalkにデプロイします。
t1.microインスタンスだとメモリが少なくてデプロイに失敗することがあるので注意。とりあえず、t2.smallで動かしてます（t1.micro & t2.micro だとデプロイできなかったので…）。

これで５〜１０分ぐらいでElastic Beanstalkが起動してブラウザからアクセス可能になるはずです。
お疲れ様でした。

>参考：
>[Deploying an Application from a Docker Container to AWS Elastic Beanstalk Using Eb](http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/create_deploy_docker_eb.html)
>[AWS Elastic BeanstalkでDockerコンテナをデプロイしてみた](http://dev.classmethod.jp/tool/docker/aws-elastic-beanstalk-for-docker-1/)
>[PentahoをDocker+EC2にデプロイする](http://qiita.com/ikuo/items/f08c72373dd5808e72ec)
>[(AWS/EC2) t1.micro はすごくメモリが少ない・・・！！](http://blog.yoslab.com/entry/2014/03/10/182701)


## 開発サイクル

ここまでくれば、後は、

１．ローカル環境でPlayアプリ開発

２．Playアプリのコンパイル

```shell:
$ activator clean compile stage
```

３．Dockerイメージファイルをビルドしてローカルで動作確認

```shell:
$ docker build -t junsuzuki/play-sample ./
```

４．Elastic Beanstalkにデプロイ

のサイクルを繰り返せばよいでしょう。


## 補足

Playアプリだから、DockerイメージにもPlayをいれとこう、と思ってたんですが、よく考えると実行時にはJava実行環境だけあればいい気がしたので、java8だけいれたimageを作成しました。
そのときのDockerfileが以下。

>[こちらのイメージも公開](https://registry.hub.docker.com/u/junsuzuki/java8/)しています。

### java8環境作成用Dockerfile


```text:Dockerfile
FROM ubuntu:14.04
MAINTAINER Jun Suzuki

# Update apt-get sources AND install packages
RUN        apt-get update
RUN        apt-get install wget unzip aptitude dpkg debconf -yy
RUN        aptitude install software-properties-common -yy

## Java
RUN sudo add-apt-repository -y ppa:webupd8team/java \
&& sudo apt-get -y update \
&& yes | sudo apt-get install oracle-java8-installer

# clean up
RUN     apt-get autoclean && aptitude autoclean

# Set Environment
ENV        HOME         /home
ENV        PATH         /bin:/usr/bin:
ENV        JAVA_HOME    /usr/lib/jvm/java-8-oracle

# Timezone Setting
RUN     echo "Asia/Tokyo" > /etc/timezone
RUN     /usr/sbin/dpkg-reconfigure -f noninteractive tzdata
```

### java8だけでplayアプリを動かすDockerfile

上記のimageを元にplayアプリを動かすDockerfileが以下。

```text:Dockerfile
FROM junsuzuki/java8
MAINTAINER Jun Suzuki

# Copy the app into the image.
ADD ./target /opt/playapp

# Start app
EXPOSE     80
CMD /opt/playapp/universal/stage/bin/play-sample -Dhttp.port=80
```

これでもきちんと動きました。
なるべく軽い環境を作りたい方はご参考まで。