TL;DR
- Gradleを利用してDockerイメージを作成してみる
- SpringBootをjar形式にビルドし、java + jarファイルを含めたDockerイメージを作成する
- 基本的にはSpring公式のドキュメントに沿って試してみるだけ
実行環境構築
環境
以下の検証項目は、macOSで実施しています
利用しているライブラリなどのバージョンは以下になります
- JDK (1.8.0_121)
- Spring Boot (1.5.8)
- Gradle (3.3)
- Docker Version (17.06.2-ce-mac27)
プロジェクトを作成する
SPRING INITIALIZRを利用してプロジェクトを選択します
Generate a 「Gradle Project」 としてGradleでビルドするようにして、DependenciesにWebを含めてみます
出来上がったdemo.zip
を展開して、gradleでプロジェクトをビルドして実行してみましょう
$ unzip demo.jar
$ cd demo
$ ./gradlew build
$ java -jar build/libs/demo-0.0.1-SNAPSHOT.jar
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v1.5.8.RELEASE)
2017-11-10 10:04:09.107 INFO 41308 --- [ main] com.example.demo.DemoApplication : Starting DemoApplication on mac0137.local.furyu.jp with PID 41308 (/Users/moriokanaoki/Downloads/demo/build/libs/demo-0.0.1-SNAPSHOT.jar started by moriokanaoki in /Users/moriokanaoki/Downloads/demo)
2017-11-10 10:04:09.111 INFO 41308 --- [ main] com.example.demo.DemoApplication : No active profile set, falling back to default profiles: default
2017-11-10 10:04:09.193 INFO 41308 --- [ main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@45283ce2: startup date [Fri Nov 10 10:04:09 JST 2017]; root of context hierarchy
2017-11-10 10:04:10.577 INFO 41308 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http)
2017-11-10 10:04:10.591 INFO 41308 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2017-11-10 10:04:10.592 INFO 41308 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.23
2017-11-10 10:04:10.676 INFO 41308 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2017-11-10 10:04:10.676 INFO 41308 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1486 ms
2017-11-10 10:04:10.804 INFO 41308 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Mapping servlet: 'dispatcherServlet' to [/]
2017-11-10 10:04:10.809 INFO 41308 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*]
2017-11-10 10:04:10.810 INFO 41308 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2017-11-10 10:04:10.810 INFO 41308 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*]
2017-11-10 10:04:10.810 INFO 41308 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*]
2017-11-10 10:04:11.191 INFO 41308 --- [ main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@45283ce2: startup date [Fri Nov 10 10:04:09 JST 2017]; root of context hierarchy
2017-11-10 10:04:11.299 INFO 41308 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2017-11-10 10:04:11.300 INFO 41308 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2017-11-10 10:04:11.332 INFO 41308 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-11-10 10:04:11.333 INFO 41308 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-11-10 10:04:11.372 INFO 41308 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-11-10 10:04:11.509 INFO 41308 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2017-11-10 10:04:11.578 INFO 41308 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2017-11-10 10:04:11.583 INFO 41308 --- [ main] com.example.demo.DemoApplication : Started DemoApplication in 2.98 seconds (JVM running for 3.412)
動いてますが、分かりにくいのでHelloWorldくらい出力させてみときます
package com.example.demo;
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 DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@RequestMapping(value = "/")
String sayHello() {
return "Hello World!";
}
}
再度 demo.jar
を起動させてlocalhostの8080番ポートにアクセスすると "Hello World!" が表示されていると思います。
Dockerfileを用意する
上記 java -jar
を実行するDockerイメージを作成するために、プロジェクト直下にDockerfileを用意します
demo.jarの作成などは後述のbuild.gradle変更と連携しています
FROM openjdk:8-jdk-alpine
VOLUME /tmp
ADD target/demo.jar app.jar
ENV JAVA_OPTS=""
ENTRYPOINT exec java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar
gradle-dockerプラグインを追加
Dockerイメージ生成をGradleにて行うためにbuild.gradleを修正します。
buildscript {
ext {
springBootVersion = '1.5.8.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
classpath "se.transmode.gradle:gradle-docker:1.2"
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'docker'
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
compile('org.springframework.boot:spring-boot-starter-web')
testCompile('org.springframework.boot:spring-boot-starter-test')
}
jar {
baseName = 'demo'
archiveName = "${baseName}.jar"
}
task buildDocker(type: Docker, dependsOn: build) {
applicationName = jar.baseName
dockerfile = file('Dockerfile')
doFirst {
copy {
from jar
into "${stageDir}/target"
}
}
}
ビルド
早速ビルドしてみましょう。
ここでmacOSで Dockerを起動しておくこと
を忘れずに
$ ./gradlew build buildDocker
Starting a Gradle Daemon, 1 incompatible Daemon could not be reused, use --status for details
:compileJava
:processResources UP-TO-DATE
:classes
:findMainClass
:jar
:bootRepackage
:assemble
:compileTestJava
:processTestResources NO-SOURCE
:testClasses
:test
2017-11-10 22:27:45.286 INFO 43631 --- [ Thread-5] o.s.w.c.s.GenericWebApplicationContext : Closing org.springframework.web.context.support.GenericWebApplicationContext@697f2062: startup date [Fri Nov 10 22:27:43 JST 2017]; root of context hierarchy
:check
:build
:buildDocker
Sending build context to Docker daemon 14.5MB
Step 1/5 : FROM openjdk:8-jdk-alpine
---> xxxxxxxxxxxx
Step 2/5 : VOLUME /tmp
---> Using cache
---> xxxxxxxxxxxx
Step 3/5 : ADD target/demo.jar app.jar
---> xxxxxxxxxxxx
Removing intermediate container xxxxxxxxxxxx
Step 4/5 : ENV JAVA_OPTS ""
---> Running in xxxxxxxxxxxx
---> xxxxxxxxxxxx
Removing intermediate container xxxxxxxxxxxx
Step 5/5 : ENTRYPOINT exec java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar
---> Running in xxxxxxxxxxxx
---> xxxxxxxxxxx
Removing intermediate container xxxxxxxxxxxx
Successfully built xxxxxxxxxxxx
Successfully tagged com.example/demo:0.0.1-SNAPSHOT
BUILD SUCCESSFUL
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
com.example/demo 0.0.1-SNAPSHOT xxxxxxxxxxxx 1 minutes ago 116MB
うまく出来上がったようです
DockerによるSpringBootの起動
$ docker run -p 8080:8080 -d com.example/demo:0.0.1-SNAPSHOT
xxxxxxxxxxxxxxxcf54172bd224611a7a184d3d454ee06a289143c191041706
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
xxxxxxxxxxxx com.example/demo:0.0.1-SNAPSHOT "/bin/sh -c 'exec ..." 36 seconds ago Up 10 seconds 0.0.0.0:8080->8080/tcp friendly_murdock
起動しているようです。
localhostの8080番ポートにアクセスすると "Hello World!" が再び表示されています
まとめ
今回はイメージ名やタグについては調整してません
また、Dockerイメージも雑にローカルに配備しました
Gradleでjarファイルを作成するのと同じような感覚でDockerイメージまで作成出来ました
Java9やOpenJDKの採用も今後進んでいくと考えられるので、SpringBootを動かすのはDockerが第一候補みたいな未来もあるかもですね