Play Framework標準装備でdockerイメージを作る


Play Framework 2.3.4で試しました。dockerコマンドは別途インストールが必要だと思います。

いつも`activator dist`で本番用にビルドしていたのですが、https://www.playframework.com/documentation/2.3.x/ProductionDist を読んでいたら、[SBT Native Packager plugin](https://www.playframework.com/documentation/2.3.x/ProductionDist)が使われているとありました。

SBT Native Packager pluginのドキュメントを見てみると、[Docker Plugin](http://www.scala-sbt.org/sbt-native-packager/formats/docker.html)というのがありました。

## やり方

まずbuild.sbtにこれを追加します。`maintainer`だけは必須の設定項目です。

```
// for `activator docker:publishLocal`
// ref: http://www.scala-sbt.org/sbt-native-packager/formats/docker.html
import NativePackagerKeys._

maintainer in Docker := "Atsushi Takayama <taka.atsushi@gmail.com>"

dockerExposedPorts in Docker := Seq(9000, 9443)
```

（sbt 0.13.7からだとimportがbuild.sbtの **途中** に出てきてもシンタックスエラーにならなくなったみたいですが、それ以前のバージョンの人はbuild.sbtの **頭** に書かないといけないのでお気をつけ下さい）

それから

```
./activator docker:publishLocal
```

とやると、build.sbtの`name`と`version`に合わせた名前でdockerイメージが作成されます。例えば

```
name := "pploy"

version := "0.5.4"
```

の場合であれば`pploy:0.5.4`という名前です。このようにすれば実行できます。

```
docker run --net=host pploy:0.5.4
```

## 設定項目

[http://www.scala-sbt.org/sbt-native-packager/formats/docker.html](ドキュメント)にあり、数は多くないです。以下にいくつか書いてみます。

### Dockerfileだけ欲しい

```
./activator docker:stage
```

にすると、`target/docker/`以下にDockerfilesとfilesというディレクトリが作成されます。Dockerfileはこのようになっていました。

```
FROM dockerfile/java
MAINTAINER Atsushi Takayama <taka.atsushi@gmail.com>
EXPOSE 9000 9443
ADD files /
WORKDIR /opt/docker
RUN ["chown", "-R", "daemon", "."]
USER daemon
ENTRYPOINT ["bin/pploy"]
CMD []
```

### ベースイメージを変更したい

デフォルトでは`FROM dockerfile/java`になります。これを変更するにはbuild.sbtに

```
dockerBaseImage := "dockerfile/java:oracle-java8"
```

のように書きます。dockerfile/javaはubuntuベースなので、debianベースに変更するには自分で公式の[dockefile/debian](https://registry.hub.docker.com/_/debian/)から[dockerfile/javaのDockerfile](https://github.com/dockerfile/java/blob/master/oracle-java8/Dockerfile)を参考にイメージを作って、それを`dockerBaseImage`に指定するのが良いと思います。

### レジストリにpushしたい

`quay.io/edvakf/pploy`というレジストリにpushしたい場合は、build.sbtに

```
dockerRepository := Some("quay.io/edvakf")
```

と書いて

```
./activator docker:publish
```

とやると、`quay.io/edvakf/pploy:0.5.4`としてpushされるはずです。

### 起動オプションを変えたい

`dockerEntrypoint in Docker`を変えるのだと思いますが、Play 2.3.4だと`not found: value dockerEntrypoint`と言われるので、新しいオプションなのかもしれません。

`activator docker:stage`してからDockerfileの

```
ENTRYPOINT ["bin/pploy"]
CMD []
```

を例えばこのように置換してから

```
ENTRYPOINT ["bin/pploy"]
CMD ["-Dconfig.resource=prod.conf"]
```

`cd target/docker && docker build -t pploy .`とかやると一応できました。

（[Best practices for writing Dockerfiles](https://docs.docker.com/articles/dockerfile_best-practices/#entrypoint)を見る感じではどちらかというと`ENTRYPOINT`を消して`CMD ["bin/pploy", "-Dconfig.resource=prod.conf"]`とするほうが良いのかもしれません）

#### 実行時に起動オプションを変えたい

`docker run`でアプリケーションの起動オプションを変更するには、

```
docker run --entrypoint=/opt/docker/bin/pploy pploy:0.5.4 -Dconfig.resource=prod.conf
                        ~~~~~~~~~~~~~~~~~~~~~             ~~~~~~~~~~~~~~~~~~~~~~~~~~~
```

のようにします。`pploy:0.5.4`の部分がイメージ名とタグで、`--entrypoint=/opt/docker/bin/pploy`が起動コマンド、後ろの`-Dconfig.resource=prod.conf`が起動コマンドのオプションになります。順番がとてもわかりにくいですね。

こうすることもできます。

```
docker run --entrypoint=/bin/sh pploy:0.5.4 -c /opt/docker/bin/pploy -Dconfig.resource=prod.conf
                        ~~~~~~~             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
```

`/bin/sh`がコマンドで、後ろの`-c /opt/docker/bin/pploy -Dconfig.resource=prod.conf`がコマンドのオプションです。

### ビルドもdockerの中でやりたい

残念ながらそのような方法は提供されていません。ホストOS側のJDKでビルドされて、jarだけがdockerイメージに入ることになります。

僕の想定する用途ではJenkinsでビルドしたかったのですが、Jenkinsの入ってるサーバーのJDKを変えるのが面倒なのでビルドもdockerでやってしまおうかと思っているので、別途やり方を調べたいと思います。

追記：続きを書いた→[Dockerの中でPlay Frameworkのプロジェクトをビルドしてzipを取り出す](http://qiita.com/edvakf@github/items/b32da3917a123de763a3)