LoginSignup
25
31

More than 5 years have passed since last update.

GradleでSpringBoot + Dockerイメージをビルドする

Last updated at Posted at 2017-11-10

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を含めてみます

screenshot_spring_init.png

出来上がった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くらい出力させてみときます

src/main/java/com/example/demo/DemoApplication.java
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変更と連携しています

Dockerfile
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を修正します。

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が第一候補みたいな未来もあるかもですね

参考文献

25
31
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
25
31