Docker上でSpring Bootを動かしてみる

Docker上で、Spring Bootで作成したAPIを動かしてみます。
この記事は「スタートトゥデイ工務店 Advent Calendar 2017」の17日目の記事です。

#はじめに
DockerとSpring Bootの経験は非常に乏しいですが、Docker上でAPIを動かしてみたいと思い実際にやってみたら、思いのほかとってもお手軽でした。
またソフトウエアのコンテナ化の今後の流れは、KubernetesやMobyといった最先端のものの成長とともに、今後はますます成長すると思いますので、初めて触る方の手始めになればと思います。

#Dockerとは
コンテナ技術を用いて、軽量なアプリケーションをコンテナ化して実行環境を生成するオープンソフトウエアです。仮想マシンと比べると管理コストが抑えられ、豊富なオプションとコンテナ同士を組み合わせた運用が容易にできることで人気を集めています。
最近ではDockerのコンテナソリューションを加速させるために、Mobyプロジェクトが発表されています。
Mobyプロジェクトの情報はｺﾁﾗを参照：https://qiita.com/zembutsu/items/c8f33b5fbc3211f5be52

#Spring Bootとは
[Spring](https://projects.spring.io/spring-boot/)が提供するライブラリを非常に使いやすくしたフレームワークで、API開発に向いており、生成したjarにはTomcatが内包されているため、jarを実行するだけでTomcatが起動しAPIが動くというとても手軽にAPI開発が可能です。


#バージョン
OS：Win10pro
Docker：17.09.0
Spring Boot：1.5.7
開発環境：Spring Tool Suite 3.9.1.RELEASE

#API作成
まずはSpring BootでAPIを作成してみます。
Docker上でAPIを動かすだけなので、STSの[Springスタータープロジェクト]より作成したプロジェクトをそのまま利用します。
自動生成されたコードに下記の通りAPIのエンドポイントを追加します。

```java:StkApplication.java

package jp.stk;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@RestController
public class StkApplication {
    
	@RequestMapping("/")
    public String home() {
        return "Stk World";
    }
	public static void main(String[] args) {
		SpringApplication.run(StkApplication.class, args);
	}
}
```

コードを追加した後は、ビルドしてjarを作成します。
ビルド後は、target配下に「stk-0.0.1-SNAPSHOT.jar」といった感じでjarファイルが作成されていると思います。
とっても手軽に作成できますね。


#Dockerファイルを作成
STSのプロジェクトフォルダと同じ場所にDockerファイルを作成します。
Spring Bootのガイドに詳しい説明があるので、[こちら](https://spring.io/guides/gs/spring-boot-docker/)も合わせて見てください。

```dockerfile
FROM openjdk:8-jdk-alpine

COPY target/stk-0.0.1-SNAPSHOT.jar stk-0.0.1.jar

ENTRYPOINT ["java","-jar","/stk-0.0.1.jar"]
```

ベースのイメージには、alpineリナックスベースにjava8が含まれているものを指定します。
[openjdk:8-jdk-alpine](https://github.com/docker-library/openjdk/blob/2598f7123fce9ea870e67f8f9df745b2b49866c0/8-jdk/alpine/Dockerfile)ってどんなものをちょっと覗いてみました。


```dockerfile
#
# NOTE: THIS DOCKERFILE IS GENERATED VIA "update.sh"
#
# PLEASE DO NOT EDIT IT DIRECTLY.
#

FROM alpine:3.7

# A few reasons for installing distribution-provided OpenJDK:
#
#  1. Oracle.  Licensing prevents us from redistributing the official JDK.
#
#  2. Compiling OpenJDK also requires the JDK to be installed, and it gets
#     really hairy.
#
#     For some sample build times, see Debian's buildd logs:
#       https://buildd.debian.org/status/logs.php?pkg=openjdk-8

# Default to UTF-8 file.encoding
ENV LANG C.UTF-8

# add a simple script that can auto-detect the appropriate JAVA_HOME value
# based on whether the JDK or only the JRE is installed
RUN { \
		echo '#!/bin/sh'; \
		echo 'set -e'; \
		echo; \
		echo 'dirname "$(dirname "$(readlink -f "$(which javac || which java)")")"'; \
	} > /usr/local/bin/docker-java-home \
	&& chmod +x /usr/local/bin/docker-java-home
ENV JAVA_HOME /usr/lib/jvm/java-1.8-openjdk
ENV PATH $PATH:/usr/lib/jvm/java-1.8-openjdk/jre/bin:/usr/lib/jvm/java-1.8-openjdk/bin

ENV JAVA_VERSION 8u151
ENV JAVA_ALPINE_VERSION 8.151.12-r0

RUN set -x \
	&& apk add --no-cache \
		openjdk8="$JAVA_ALPINE_VERSION" \
	&& [ "$JAVA_HOME" = "$(docker-java-home)" ]

# If you're reading this and have any feedback on how this image could be
# improved, please open an issue or a pull request so we can discuss it!
#
#   https://github.com/docker-library/openjdk/issues
```

ベースは、alpineリナックスの3.7なんですね。
そして、java8をコンテナに内包してますね。


それでは、Dockerファイルをビルドして実際にコンテナを起動してみます。
まずはbuildコマンドでビルドし、イメージを作成します。

```
$ docker build ./ -t stk
```


次に、イメージをポート指定で起動します。

```
$ docker run -p 8080:8080 -t stk
```

環境変数を指定して、バックグラウンド起動する場合のコマンドはこちらです。
docker run リファレンスは[こちら](https://docs.docker.jp/engine/reference/commandline/run.html)を参照ください。

```
$ docker run --detach --env-file ./env.list -p 8080:8080 -t stk
```

これでビルドとコンテナの起動は終了です。

ブラウザでlocalhost:8080へアクセスしてみてください。
APIの戻り値で指定したワードが表示されるはずです。


#まとめ
Docker、Spring Bootの初心者でもとても手軽にはじめられることがご覧いただけましたでしょうか。
実際にやってみるとうまく動かない場合は、躓いてしまう場合もありますが、まずは手始めの参考にしていただければ幸いです。