用 Docker、Gradle 來構建、運行、發佈一個 Spring Boot 應用

如何用 Docker、Gradle 來構建、運行、發佈來一個 Spring Boot 應用。html

Docker 簡介

Docker 是一個 Linux 容器管理工具包,具有「社交」方面,容許用戶發佈容器的 image (鏡像),並使用別人發佈的 image。Docker image 是用於運行容器化進程的方案,在本文中,咱們將構建一個簡單的 Spring Boot 應用程序。java

有關 Docker 的詳細介紹,能夠移步至 《簡述 Docker》。git

前置條件

  • JDK 1.8+
  • Gradle 2.3+
  • Docker 最新版。有關 Docker 在的安裝,能夠參閱 《Docker 在 CentOS 下的安裝、使用》。 若是你的電腦不是 Linux 系統,最好裝個虛擬機,在虛擬機裏面裝個 Linux ,由於 Docker 的依賴 Linux。

用 Gradle 構建項目

建立目錄結構

項目的目錄結構因符合 Gradle 的約定。github

在 *nix 系統下執行 mkdir -p src/main/java/docker_spring_boot ,生產以下結構 :web

1spring

2docker

3apache

4json

5centos

6

└── src

    └── main

        └── java

            └── com

                └── waylau

                    └── docker_spring_boot

建立 Gradle 構建文件

build.gradle

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

buildscript {

    repositories {

        mavenCentral()

    }

    dependencies {

        classpath('org.springframework.boot:spring-boot-gradle-plugin:1.3.3.RELEASE')

// tag::build[]

        classpath('se.transmode.gradle:gradle-docker:1.2')

// end::build[]

    }

}

 

apply plugin: 'java'

apply plugin: 'eclipse'

apply plugin: 'idea'

apply plugin: 'spring-boot'

// tag::plugin[]

apply plugin: 'docker'

// end::plugin[]

 

// This is used as the docker image prefix (org)

group = 'gregturn'

 

jar {

    baseName = 'docker-spring-boot-gradle'

    version =  '1.0.0'

}

 

// tag::task[]

task buildDocker(type: Docker, dependsOn: build) {

  push = true

  applicationName = jar.baseName

  dockerfile = file('src/main/docker/Dockerfile')

  doFirst {

    copy {

      from jar

      into stageDir

    }

  }

}

// end::task[]

 

repositories {

    mavenCentral()

}

 

sourceCompatibility = 1.8

targetCompatibility = 1.8

 

dependencies {

    compile("org.springframework.boot:spring-boot-starter-web")

    testCompile("org.springframework.boot:spring-boot-starter-test")

}

 

task wrapper(type: Wrapper) {

    gradleVersion = '2.3'

}

Spring Boot gradle plugin 提供了不少方便的功能:

它收集的類路徑上全部 jar 文件,並構建成一個單一的、可運行的「über-jar」(德語,相關解釋能夠移步至 http://stackoverflow.com/questions/11947037/what-is-an-uber-jar),這使得它更方便地執行和傳輸服務。

編寫 Spring Boot 應用

編寫一個簡單的 Spring Boot 應用 :

src/main/java/com/waylau/docker_spring_boot/Application.java:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

package com.waylau.docker_spring_boot;

 

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;

 

/**

 * 主應用入口

 * @author <a href="http://waylau.com">waylau.com</a>

 * @date 2016年3月19日

 */

@SpringBootApplication

@RestController

public class Application {

 

    @RequestMapping("/")

    public String home() {

        return "Hello Docker World."

                + "Welcome to <a href='http://waylau.com'>waylau.com</a></li>";

    }

 

    public static void main(String[] args) {

        SpringApplication.run(Application.class, args);

    }

 

}

解釋下上面的代碼:

  • 類用 @SpringBootApplication @RestController 標識,可用 Spring MVC 來處理 Web 請求。
  • @RequestMapping 將 / 映射到 home() ,並將」Hello Docker World」 文本做爲響應。
  • main() 方法使用 Spring Boot 的 SpringApplication.run() 方法來啓動應用。

運行程序

使用 Gradle

編譯:

1

gradle build

運行:

1

java -jar build/libs/docker-spring-boot-gradle-1.0.0.jar

訪問項目

若是程序正確運行,瀏覽器訪問 http://localhost:8080/,能夠看到頁面 「Hello Docker World.」 字樣。

將項目容器化

Docker 使用 Dockerfile 文件格式來指定 image 層,

建立文件 src/main/docker/Dockerfile:

1

2

3

4

FROM frolvlad/alpine-oraclejdk8:slim

VOLUME /tmp

ADD docker-spring-boot-gradle-1.0.0.jar app.jar

ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]

解釋下這個配置文件:

  • VOLUME 指定了臨時文件目錄爲/tmp。其效果是在主機 /var/lib/docker 目錄下建立了一個臨時文件,並連接到容器的/tmp。改步驟是可選的,若是涉及到文件系統的應用就頗有必要了。/tmp目錄用來持久化到 Docker 數據文件夾,由於 Spring Boot 使用的內嵌 Tomcat 容器默認使用/tmp做爲工做目錄
  • 項目的 jar 文件做爲 「app.jar」 添加到容器的
  • ENTRYPOINT 執行項目 app.jar。爲了縮短 Tomcat 啓動時間,添加一個系統屬性指向 「/dev/urandom」 做爲 Entropy Source

構建 Docker Image

執行構建成爲 docker image:

1

gradle build buildDocker

運行

運行 Docker Image

1

docker run -p 8080:8080 -t waylau/docker-spring-boot-gradle

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

[root@waylau spring-boot]# docker run -p 8080:8080 -t waylau/docker-spring-boot-gradle

 

  .   ____          _            __ _ _

 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \

( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \

 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )

  '  |____| .__|_| |_|_| |_\__, | / / / /

 =========|_|==============|___/=/_/_/_/

 :: Spring Boot ::        (v1.3.3.RELEASE)

 

2016-03-20 08:45:51.276  INFO 1 --- [           main] c.waylau.docker_spring_boot.Application  : Starting Application v1.0.0 on 048fb623038f with PID 1 (/app.jar started by root in /)

2016-03-20 08:45:51.289  INFO 1 --- [           main] c.waylau.docker_spring_boot.Application  : No active profile set, falling back to default profiles: default

2016-03-20 08:45:51.722  INFO 1 --- [           main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@669af5fc: startup date [Sun Mar 20 08:45:51 GMT 2016]; root of context hierarchy

2016-03-20 08:45:54.874  INFO 1 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Overriding bean definition for bean 'beanNameViewResolver' with a different definition: replacing [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration$WhitelabelErrorViewConfiguration; factoryMethodName=beanNameViewResolver; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/boot/autoconfigure/web/ErrorMvcAutoConfiguration$WhitelabelErrorViewConfiguration.class]] with [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter; factoryMethodName=beanNameViewResolver; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/boot/autoconfigure/web/WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter.class]]

2016-03-20 08:45:57.893  INFO 1 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http)

2016-03-20 08:45:57.982  INFO 1 --- [           main] o.apache.catalina.core.StandardService   : Starting service Tomcat

2016-03-20 08:45:57.984  INFO 1 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/8.0.32

2016-03-20 08:45:58.473  INFO 1 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext

2016-03-20 08:45:58.473  INFO 1 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 6877 ms

2016-03-20 08:45:59.672  INFO 1 --- [ost-startStop-1] o.s.b.c.e.ServletRegistrationBean        : Mapping servlet: 'dispatcherServlet' to [/]

2016-03-20 08:45:59.695  INFO 1 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean  : Mapping filter: 'characterEncodingFilter' to: [/*]

2016-03-20 08:45:59.701  INFO 1 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean  : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]

2016-03-20 08:45:59.703  INFO 1 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean  : Mapping filter: 'httpPutFormContentFilter' to: [/*]

2016-03-20 08:45:59.703  INFO 1 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean  : Mapping filter: 'requestContextFilter' to: [/*]

2016-03-20 08:46:00.862  INFO 1 --- [           main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@669af5fc: startup date [Sun Mar 20 08:45:51 GMT 2016]; root of context hierarchy

2016-03-20 08:46:01.166  INFO 1 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/]}" onto public java.lang.String com.waylau.docker_spring_boot.Application.home()

2016-03-20 08:46:01.189  INFO 1 --- [           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)

2016-03-20 08:46:01.190  INFO 1 --- [           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)

2016-03-20 08:46:01.302  INFO 1 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]

2016-03-20 08:46:01.302  INFO 1 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]

2016-03-20 08:46:01.438  INFO 1 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]

2016-03-20 08:46:01.833  INFO 1 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup

2016-03-20 08:46:02.332  INFO 1 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)

2016-03-20 08:46:02.343  INFO 1 --- [           main] c.waylau.docker_spring_boot.Application  : Started Application in 13.194 seconds (JVM running for 15.828)

訪問項目

若是程序正確運行,瀏覽器訪問 http://localhost:8080/,能夠看到頁面 「Hello Docker World.」 字樣。

推送 image 到 Docker Hub

首先,你在 Docker Hub 要有註冊帳號,且建立了相應的庫;

其次,docker 推送前,先要登陸,不然報unauthorized: access to the requested resource is not authorized的錯誤

執行:

1

docker login

輸出爲:

1

2

3

4

5

6

[root@waylau spring-boot]# docker login

Username: waylau

Password:

Email: waylau521@gmail.com

WARNING: login credentials saved in /root/.docker/config.json

Login Succeeded

執行推送

1

docker push waylau/docker-spring-boot-gradle

1

2

3

4

5

6

7

8

[root@waylau spring-boot]# docker push waylau/docker-spring-boot-gradle

The push refers to a repository [docker.io/waylau/docker-spring-boot-gradle]

751d29eef02e: Layer already exists

4da3741f39c7: Pushed

5f70bf18a086: Layer already exists

7e4d0cb13643: Layer already exists

8f045733649f: Layer already exists

latest: digest: sha256:eb4d5308ba1bb27489d808279e74784bda6761b3574f4298d746abba59b35164 size: 9415

鏡像加速器

Docker Hub 在國外,有時候拉取 Image 極其緩慢,能夠使用國內的鏡像來實現加速

阿里雲

1

2

echo "DOCKER_OPTS=\"--registry-mirror=https://yourlocation.mirror.aliyuncs.com\"" | sudo tee -a /etc/default/docker

sudo service docker restart

其中 https://yourlocation.mirror.aliyuncs.com 是您在阿里雲註冊後的專屬加速器地址:

DaoCloud

1

2

sudo echo 「DOCKER_OPTS=\」\$DOCKER_OPTS –registry-mirror=http://your-id.m.daocloud.io -d\」」 >> /etc/default/docker

sudo service docker restart

其中 http://your-id.m.daocloud.io 是您在 DaoCloud 註冊後的專屬加速器地址:

源碼

獲取項目源碼, https://github.com/waylau/docker-demos 中的 samples/spring-boot-gradle

獲取項目鏡像, 執行

1

docker pull waylau/docker-spring-boot-gradle

參考引用

  • http://spring.io/guides/gs/spring-boot-docker/
  • https://hub.docker.com/r/waylau/docker-spring-boot-gradle/
相關文章
相關標籤/搜索