spring-boot 和 docker 集成


描述

java 的 Spring是一個很火的框架,Spring boot 這個也不用說了,Docker 近年也很火熱, 本文就介紹下我在 Spring boot + Docker的集成一些經驗 :) 其實官網已經有一個手冊介紹了 這里

可能會用到的東西

  • JDK 1.8 或者更高
  • Maven 3.0+ 或者是 Gradle 2.3+
  • 一個IDE或者一個記事本
  • 一個本地或者遠程的Docker服務
  • 充滿好奇心的你

對沒錯,你至少需要一個Docker,可以安裝在本地也可以安裝在服務器上,具體安裝方式請移步 這里

整個Spring boot的項目

我這邊用的是IDEA 創建的 

 

create

 

➜  sping-boot-docker  tree
.
├── mvnw
├── mvnw.cmd
├── pom.xml
├── sping-boot-docker.iml
└── src
    ├── main
    │   ├── java
    │   │   └── org
    │   │       └── beyondblog
    │   │           ├── DemoApplication.java
    │   │           ├── controller
    │   │           │   └── HelloController.java
    │   │           └── model
    │   │               └── Hello.java
    │   └── resources
    │       ├── application-dev.yml
    │       └── application.yml
    └── test
        └── java
            └── org
                └── beyondblog
                    └── DemoApplicationTests.java

12 directories, 10 files

 

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.beyondblog</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>demo</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.3.2.BUILD-SNAPSHOT</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>spring-snapshots</id>
            <name>Spring Snapshots</name>
            <url>https://repo.spring.io/snapshot</url>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </repository>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>
    <pluginRepositories>
        <pluginRepository>
            <id>spring-snapshots</id>
            <name>Spring Snapshots</name>
            <url>https://repo.spring.io/snapshot</url>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </pluginRepository>
        <pluginRepository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </pluginRepository>
    </pluginRepositories>

</project>

程序很簡單創建了一個Controller,然后映射了一個/hello的路由 運行之后如下

➜  target  java -jar demo-0.0.1-SNAPSHOT.jar
➜  sping-boot-docker  http "http://127.0.0.1:8080/hello"
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Date: Sun, 20 Dec 2015 23:41:14 GMT
Server: Apache-Coyote/1.1
Transfer-Encoding: chunked

{
    "code": 200,
    "messge": "Hello spring! profile=production"
}

可以正常允許,然后配置下pom集成docker (也可以用Dockerfile)

<build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>com.spotify</groupId>
                <artifactId>docker-maven-plugin</artifactId>
                <version>0.3.8</version>
                <executions>
                    <execution>
                        <phase>deploy</phase>
                        <goals>
                            <goal>build</goal>
                            <goal>tag</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <dockerHost>http://172.16.0.17:2375</dockerHost>
                    <imageName>registry.****.com/demo:${project.artifactId}</imageName>
                    <baseImage>docker.io/java:latest</baseImage>
                    <registryUrl>https://registry.****.com</registryUrl>
                    <env>
                        <TZ>'Asia/Shanghai'</TZ>
                        <LC_ALL>en_US.UTF-8</LC_ALL>
                    </env>
                    <resources>
                        <resource>
                            <targetPath>/</targetPath>
                            <directory>${project.build.directory}</directory>
                            <include>${project.build.finalName}.jar</include>
                        </resource>
                        <!--<resource>-->
                            <!--<targetPath>/web</targetPath>-->
                            <!--<directory>${project.build.directory}/web</directory>-->
                        <!--</resource>-->
                    </resources>
                    <exposes>
                        <expose>8080</expose>
                    </exposes>
                    <cmd>["java", "-jar", "/${project.build.finalName}.jar"]</cmd>
                    <image>registry.****.com/demo:${project.artifactId}</image>
                    <newName>registry.****.com/demo</newName>
                    <forceTags>true</forceTags>
                    <pushImage>false</pushImage>
                </configuration>
            </plugin>
        </plugins>
    </build>

 

描述下這段的意思

這兒用到的是spotify公司(就是那個做音樂的)的 docker-maven-plugin 插件用的是目前最新的0.3.8 之前的幾個版本有一些目錄拷貝的bug。

configuration 節點

有個dockerHost 就是docker服務器的地址 (必選)

imageName 就是生成的鏡像名稱的東西

baseImage 就是容器基於那個鏡像跑 這兒用的是官方的 docker.io/java:latest(可以直接 docker pull 下來,也可以用自己做的。官方的是OpenJDK Java 7 JRE 可以去看它的項目主頁 這里 ) 就是一個JRE的環境

registryUrl 這個就是docker自建的私服地址 (可空) 這個填了之后可以觸發push 到倉庫的指令

env 不解釋 默認的時區啊 字符集啊別忘記了 (自制鏡像的可以忽略它)

resources 里面包含需要將那些東西包裝到鏡像里面去,注意我注釋的這段

<resource>
    <targetPath>/web</targetPath>
    <directory>${project.build.directory}/web</directory>
</resource>

這個是為了舉例如何包含整個目錄(通過看源代碼發現 不寫include就是copy整個目錄 目前插件的0.38版本是,之前的版本好像拷貝目錄下的所有文件囧。。。)

exposes 是暴露出容器的那個端口出來,這兒填的是8080 Spring boot 默認就這端口

cmd 是鏡像在run的時候默認執行的命令,這兒默認直接run (ps:這塊可以指定profile 做生產環境和開發環境的切換)

image 同imageName

newName 是Tag的時候生成的名字 (可選) 強烈推薦加這個 這樣默認會把新的容器的tag 設置成latest

forceTags 是否強制tag (強行喲)

pushImage 是否自動push到倉庫

基本上需要用的就這么多,當然還有一些其他的參數可以去它的項目主頁看

配置完了之后可以用 mvn的一些指令了 如下

docker:build 應該是編譯鏡像(強烈建議跟 mvn install 不然會有一個坑)

-DpushImage 加這個參數可以強制push鏡像到倉庫

DOCKER_HOST 加這個環境變量可以設置默認的docker主機地址 不過上面dockerHost已經填了

docker:removeImage 刪除鏡像吧

-DimageName=xxx 設置鏡像名稱

docker:tag 打tag

還有一些設置認證的介紹可以去看它的項目主頁或者讀源代碼

下面就執行下

    mvn install docker:build docker:tag

可以看到類似下面的輸出

[INFO] Copying /Users/xxx/Documents/code/github/sping-boot-docker/target/demo-0.0.1-SNAPSHOT.jar -> /Users/xxx/Documents/code/github/sping-boot-docker/target/docker/demo-0.0.1-SNAPSHOT.jar
[INFO] Building image registry.****.com/demo:demo
Step 0 : FROM docker.io/java:latest
 ---> e9de8c6faf15
Step 1 : ENV LC_ALL en_US.UTF-8
 ---> Using cache
 ---> 8600ba9f5363
Step 2 : ENV TZ 'Asia/Shanghai'
 ---> Using cache
 ---> 9416efd6b55a
Step 3 : ADD /demo-0.0.1-SNAPSHOT.jar //
 ---> 8cf7cbbd260e
Removing intermediate container 9a53dfb28f52
Step 4 : EXPOSE 8080
 ---> Running in 4f640acaf303
 ---> 3a4400f72be5
Removing intermediate container 4f640acaf303
Step 5 : CMD java -jar /demo-0.0.1-SNAPSHOT.jar
 ---> Running in e8ff98f7e9ce
 ---> 6834dbb25c33
Removing intermediate container e8ff98f7e9ce
Successfully built 6834dbb25c33
[INFO] Built registry.****.com/demo:demo

通過這個輸出可以知道這個插件的原理大致是 install成功jar之后根據pom文件的配置去生成一個dockerfile的文件然后把jar包和dockerfile打包調用docker的api去build去push

可以看到它生成的dockerfile來驗證

➜  sping-boot-docker  cd target/docker
➜  docker  ls
Dockerfile              demo-0.0.1-SNAPSHOT.jar
➜  docker  cat Dockerfile
FROM docker.io/java:latest
ENV LC_ALL en_US.UTF-8
ENV TZ 'Asia/Shanghai'
ADD /demo-0.0.1-SNAPSHOT.jar //
EXPOSE 8080
CMD ["java", "-jar", "/demo-0.0.1-SNAPSHOT.jar"]
➜  docker

這個時候去docker服務器上看看鏡像的情況

[root@172-16-0-17 cache]# docker images | grep "demo"
registry.****.com/demo                              demo                          6834dbb25c33        5 minutes ago       655.3 MB
registry.****.com/demo                              latest                        6834dbb25c33        5 minutes ago       655.3 MB

可以看到有兩個但是通過看它的 digest 其實是同一個鏡像不同的名字而已。 因為我們有docker:tag 這樣就會在生成一個latest

可以看到鏡像還挺大的這主要是那個java的基礎鏡像大(可以自制一個小的)不過docker每次都是有cache和增量更新所以速度還是很快的

然后驗證下能不能正常工作 

docker run -p 6666:8080 registry.****.com/demo

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::  (v1.3.2.BUILD-SNAPSHOT)

2015-12-21 08:30:05.303  INFO 1 --- [           main] org.beyondblog.DemoApplication           : Starting DemoApplication v0.0.1-SNAPSHOT on a734ef04ef23 with PID 1 (/demo-0.0.1-SNAPSHOT.jar started by root in /)
2015-12-21 08:30:05.307  INFO 1 --- [           main] org.beyondblog.DemoApplication           : No active profile set, falling back to default profiles: default
2015-12-21 08:30:05.463  INFO 1 --- [           main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@429e6a3d: startup date [Mon Dec 21 08:30:05 CST 2015]; root of context hierarchy
2015-12-21 08:30:06.471  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]]
2015-12-21 08:30:07.725  INFO 1 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http)
2015-12-21 08:30:07.745  INFO 1 --- [           main] o.apache.catalina.core.StandardService   : Starting service Tomcat
2015-12-21 08:30:07.746  INFO 1 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/8.0.30
2015-12-21 08:30:07.834  INFO 1 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2015-12-21 08:30:07.835  INFO 1 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 2386 ms
2015-12-21 08:30:08.106  INFO 1 --- [ost-startStop-1] o.s.b.c.e.ServletRegistrationBean        : Mapping servlet: 'dispatcherServlet' to [/]
2015-12-21 08:30:08.110  INFO 1 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean  : Mapping filter: 'characterEncodingFilter' to: [/*]
2015-12-21 08:30:08.110  INFO 1 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean  : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2015-12-21 08:30:08.110  INFO 1 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean  : Mapping filter: 'httpPutFormContentFilter' to: [/*]
2015-12-21 08:30:08.111  INFO 1 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean  : Mapping filter: 'requestContextFilter' to: [/*]
2015-12-21 08:30:08.523  INFO 1 --- [           main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@429e6a3d: startup date [Mon Dec 21 08:30:05 CST 2015]; root of context hierarchy
2015-12-21 08:30:08.566  INFO 1 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/hello],methods=[GET]}" onto public java.lang.Object org.beyondblog.controller.HelloController.hello()
2015-12-21 08:30:08.568  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)
2015-12-21 08:30:08.568  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)
2015-12-21 08:30:08.587  INFO 1 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2015-12-21 08:30:08.587  INFO 1 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2015-12-21 08:30:08.613  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]
2015-12-21 08:30:08.714  INFO 1 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2015-12-21 08:30:08.782  INFO 1 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2015-12-21 08:30:08.794  INFO 1 --- [           main] org.beyondblog.DemoApplication           : Started DemoApplication in 5.045 seconds (JVM running for 7.068)
這個命令 有個 -p 是容器的端口和主機的端口映射 也就是通過6666訪問容器的8080端口 可以在加個-d 使它能在后台跑(不過哪有就看不到輸出)

先看看數據能不能出來

➜  docker  http "http://172.16.0.17:6666/hello"
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Date: Mon, 21 Dec 2015 00:32:20 GMT
Server: Apache-Coyote/1.1
Transfer-Encoding: chunked

{
    "code": 200,
    "messge": "Hello spring! profile=production"
}

 

好了大致是ok。先這樣工頭喊我去搬磚了下次在介紹如果處理日志和k8s集群管理


參考文章:

[0] https://spring.io/guides/gs/spring-boot-docker/

[1] https://github.com/spotify/docker-maven-plugin


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM