Spring Native打包本地映象,無需透過Graal的maven外掛buildtools

南瓜慢說發表於2023-02-05

簡介

在文章《GraalVM和Spring Native嚐鮮,一步步讓Springboot啟動飛起來,66ms完成啟動》中,我們介紹瞭如何使用Spring Native和buildtools外掛,打包出本地映象,也打包成Docker映象。本文探索一下,如果不透過這個外掛來生成映象。這樣我們可以控制更多、瞭解更多。

建立Spring Boot專案

建立Spring Boot專案,引入Spring Native,我們主要使用的是Spring Native提供的AOT功能。如下:

<dependencies>
  <dependency>
    <groupId>org.springframework.experimental</groupId>
    <artifactId>spring-native</artifactId>
    <version>${spring-native.version}</version>
  </dependency>

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

<build>
  <plugins>
    <plugin>
      <groupId>org.springframework.experimental</groupId>
      <artifactId>spring-aot-maven-plugin</artifactId>
      <version>${spring-native.version}</version>
      <executions>
        <execution>
          <id>test-generate</id>
          <goals>
            <goal>test-generate</goal>
          </goals>
        </execution>
        <execution>
          <id>generate</id>
          <goals>
            <goal>generate</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

Build image的時候,我們需要引用依賴庫,所以加上下面的外掛:

<plugin>
  <artifactId>maven-dependency-plugin</artifactId>
  <executions>
    <execution>
      <phase>package</phase>
      <goals>
        <goal>copy-dependencies</goal>
      </goals>
      <configuration>
        <outputDirectory>${project.build.directory}/lib</outputDirectory>
      </configuration>
    </execution>
  </executions>
</plugin>

接著先編譯出Java class,命令如下:

$ mvn clean package

打包本地映象

前面的命令打包完,在target目錄下會有一個lib目錄,我們需要用上。透過native-image命令來生成映象,如下:

$ native-image -cp ./target/classes/:target/lib/* com.pkslow.springboot.SpringbootGraalVMNativeMain Pkslow.SpringbootGraalVMNativeMain

這樣就會生成一個可執行檔案:Pkslow.SpringbootGraalVMNativeMain

執行如下:

$ ./Pkslow.SpringbootGraalVMNativeMain

使用了93ms來啟動,還是很快的。

訪問服務是正常的:

$ curl -i http://localhost:8080/hi-graalvm
HTTP/1.1 200 
Content-Type: text/plain;charset=UTF-8
Content-Length: 67
Date: Wed, 02 Nov 2022 15:08:44 GMT

This message is from Spring Boot built/run by GraalVM/Spring Native

建立Docker映象

先拉取基礎映象:

$ docker pull springci/graalvm-ce:java11-0.12.x

進入容器看一下里面的狀況:

$ docker run -it --rm --entrypoint bash springci/graalvm-ce:java11-0.12.x
root@d9b54bdce70a:/# pwd
/
root@d9b54bdce70a:/# java --version
openjdk 11.0.15 2022-04-19
OpenJDK Runtime Environment GraalVM 22.1.1.0-dev (build 11.0.15+10-jvmci-22.1-b06)
OpenJDK 64-Bit Server VM GraalVM 22.1.1.0-dev (build 11.0.15+10-jvmci-22.1-b06, mixed mode, sharing)
root@d9b54bdce70a:/# which java
/opt/java/bin/java
root@d9b54bdce70a:/# which native-image
/opt/java/bin/native-image

準備一下Dockerfile如下:

FROM springci/graalvm-ce:java11-0.12.x
VOLUME /tmp

ARG PORT=8080
ARG TIME_ZONE=Asia/Shanghai

ENV TZ=${TIME_ZONE}
EXPOSE ${PORT}
RUN pwd

RUN mkdir /pkslow-application
WORKDIR /pkslow-application/
RUN cd /pkslow-application
COPY target/classes/ /pkslow-application/classes/
COPY target/lib/ /pkslow-application/lib/

RUN native-image -cp /pkslow-application/classes/:/pkslow-application/lib/* \
    com.pkslow.springboot.SpringbootGraalVMNativeMain \
    Pkslow.SpringbootGraalVMNativeMain


ENTRYPOINT ["/pkslow-application/Pkslow.SpringbootGraalVMNativeMain"]

打包Docker映象:

$ docker build . -t pkslow/spring-boot-native-without-buildtools:1.0-SNAPSHOT -f src/main/dker/Dockerfile

完成後透過下面命令啟動,57ms完成啟動:

$ docker run -it -p 8080:8080 --rm pkslow/spring-boot-native-without-buildtools:0-SNAPSHOT
2022-11-02 23:48:40.918  INFO 1 --- [           main] o.s.nativex.NativeListener               : AOT mode enabled

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.6.2)

2022-11-02 23:48:40.920  INFO 1 --- [           main] c.p.s.SpringbootGraalVMNativeMain        : Starting SpringbootGraalVMNativeMain using Java 11.0.15 on 12528bd45fd7 with PID 1 (/pkslow-application/Pkslow.SpringbootGraalVMNativeMain started by root in /pkslow-application)
2022-11-02 23:48:40.920  INFO 1 --- [           main] c.p.s.SpringbootGraalVMNativeMain        : No active profile set, falling back to default profiles: default
2022-11-02 23:48:40.934  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2022-11-02 23:48:40.935  INFO 1 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2022-11-02 23:48:40.935  INFO 1 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.56]
2022-11-02 23:48:40.940  INFO 1 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2022-11-02 23:48:40.940  INFO 1 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 19 ms
2022-11-02 23:48:40.963  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2022-11-02 23:48:40.964  INFO 1 --- [           main] c.p.s.SpringbootGraalVMNativeMain        : Started SpringbootGraalVMNativeMain in 0.057 seconds (JVM running for 0.061)
2022-11-02 23:48:57.098  INFO 1 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2022-11-02 23:48:57.098  INFO 1 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2022-11-02 23:48:57.098  INFO 1 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 0 ms

測試正常啟動:

$ curl -i http://127.0.0.1:8080/hi-graalvm
HTTP/1.1 200 
Content-Type: text/plain;charset=UTF-8
Content-Length: 67
Date: Wed, 02 Nov 2022 15:49:05 GMT

This message is from Spring Boot built/run by GraalVM/Spring Native

為了整合打包映象到CI/CD中,在pom新增以下外掛:

<plugin>
  <groupId>org.codehaus.mojo</groupId>
  <artifactId>exec-maven-plugin</artifactId>
  <version>3.0.0</version>
  <executions>
    <execution>
      <phase>install</phase>
      <goals>
        <goal>exec</goal>
      </goals>
      <configuration>
        <skip>${docker.skip}</skip>
        <executable>docker</executable>
        <arguments>
          <argument>build</argument>
          <argument>.</argument>
          <argument>-t</argument>
          <argument>pkslow/${project.artifactId}:${project.version}</argument>
          <argument>-f</argument>
          <argument>src/main/docker/Dockerfile</argument>
        </arguments>
      </configuration>
    </execution>
  </executions>
</plugin>

透過以下命令即可生成Docker映象:

$ mvn clean install -Ddocker.skip=false

程式碼

程式碼請看GitHub: https://github.com/LarryDpk/p...

相關文章