试用Spring Boot 2.3.0 M1版本中新引入的 使用原生云构建包构建Docker镜像的功能
引发事件的原因
SpringBoot 2.3.0 M1已发布。
有各种各样的改进和删除不必要的功能,但在查看发布说明时发现了一件令人关注的事情,我想尝试使用云原生构建包构建Docker镜像。
在发布说明中,包含了以下内容。
通过 spring-boot:build-image 目标和 bootBuildImage 任务,Maven 和 Gradle 插件已经支持使用 Cloud Native Buildpacks 构建 Docker 镜像。
据说可以使用Maven或Gradle插件创建Docker镜像。
我想立即尝试一下,并对这项活动进行总结。
如何开始
以前设定相同,
使用Spring Initializr创建应用模板。
创建之后,想要获取环境信息,所以也启用了SpringBoot Actuator。
立即创建DockerImage。在创建镜像的环境中需要启动DockerDeamon,请注意这一点。
以前构建Spring Boot应用程序的Docker镜像需要按照以下步骤进行:
1. 使用mvn package命令创建应用程序的Jar文件。
2. 在Dockerfile中记录要创建的Docker镜像的具体内容。
3. 使用docker build命令创建镜像。
- Dockerfileの設定例
FROM openjdk:8-jdk-alpine
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
使用Cloud Native Buildpacks可以在一步中构建Docker镜像,无需执行上述步骤。对于Maven,只需执行mvn spring-boot:build-image命令,对于Gradle,只需执行gradle bootBuildImage命令。Cloud Native Buildpacks的功能可以读取源代码并自动补充所需的Dockerfile配置信息。
$ mvn spring-boot:build-image
[INFO] Scanning for projects...
[INFO]
[INFO] --------------------------< com.example:demo >--------------------------
[INFO] Building demo 0.0.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] >>> spring-boot-maven-plugin:2.3.0.M1:build-image (default-cli) > package @ demo >>>
[INFO]
[INFO] --- maven-resources-plugin:3.1.0:resources (default-resources) @ demo ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 1 resource
[INFO] Copying 0 resource
[INFO]
[INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ demo ---
[INFO] Nothing to compile - all classes are up to date
中略
[INFO] > Running builder
[INFO] [builder]
[INFO] [builder] Cloud Foundry OpenJDK Buildpack v1.0.80
[INFO] [builder] OpenJDK JRE 11.0.5: Reusing cached layer
[INFO] [builder]
[INFO] [builder] Cloud Foundry JVM Application Buildpack v1.0.113
[INFO] [builder] Executable JAR: Reusing cached layer
[INFO] [builder] Process types:
[INFO] [builder] executable-jar: java -cp $CLASSPATH $JAVA_OPTS org.springframework.boot.loader.JarLauncher
[INFO] [builder] task: java -cp $CLASSPATH $JAVA_OPTS org.springframework.boot.loader.JarLauncher
[INFO] [builder] web: java -cp $CLASSPATH $JAVA_OPTS org.springframework.boot.loader.JarLauncher
[INFO] [builder]
[INFO] [builder] Cloud Foundry Spring Boot Buildpack v1.0.157
[INFO] [builder] Spring Boot 2.3.0.M1: Reusing cached layer
[INFO] [builder] Process types:
[INFO] [builder] spring-boot: java -cp $CLASSPATH $JAVA_OPTS com.example.demo.DemoApplication
[INFO] [builder] task: java -cp $CLASSPATH $JAVA_OPTS com.example.demo.DemoApplication
[INFO] [builder] web: java -cp $CLASSPATH $JAVA_OPTS com.example.demo.DemoApplication
[INFO] [builder]
[INFO] [builder] Cloud Foundry Spring Auto-reconfiguration Buildpack v1.0.159
[INFO] [builder] Spring Auto-reconfiguration 2.11.0: Reusing cached layer
[INFO]
[INFO] > Running exporter
[INFO] [exporter] Reusing layer 'app'
[INFO] [exporter] Reusing layer 'config'
[INFO] [exporter] Reusing layer 'launcher'
[INFO] [exporter] Reusing layer 'org.cloudfoundry.openjdk:openjdk-jre'
[INFO] [exporter] Reusing layer 'org.cloudfoundry.jvmapplication:executable-jar'
[INFO] [exporter] Reusing layer 'org.cloudfoundry.springboot:spring-boot'
[INFO] [exporter] Reusing layer 'org.cloudfoundry.springautoreconfiguration:auto-reconfiguration'
[INFO] [exporter] *** Images (89a7e99f9c15):
[INFO] [exporter] docker.io/library/demo:0.0.1-SNAPSHOT
[INFO]
[INFO] > Running cacher
[INFO] [cacher] Reusing layer 'org.cloudfoundry.openjdk:2f08c469c9a8adea1b6ee3444ba2a8242a7e99d87976a077faf037a9eb7f884b'
[INFO] [cacher] Reusing layer 'org.cloudfoundry.jvmapplication:executable-jar'
[INFO] [cacher] Reusing layer 'org.cloudfoundry.springboot:spring-boot'
[INFO] [cacher] Reusing layer 'org.cloudfoundry.springautoreconfiguration:46ab131165317d91fd4ad3186abf755222744e2d277dc413def06f3ad45ab150'
[INFO]
[INFO] Successfully built image 'docker.io/library/demo:0.0.1-SNAPSHOT'
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 01:01 min
[INFO] Finished at: 2020-02-08T15:30:43+09:00
[INFO] ------------------------------------------------------------------------
第一次可能需要花费一些时间来下载基础镜像,但第二次及之后就可以在上述的时间内完成。
现在,让我们确认一下Docker镜像是否已经创建成功。
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
demo 0.0.1-SNAPSHOT 89a7e99f9c15 About a minute ago 226MB
确保已经准备就绪,启动过程与普通的DockerImage相同。在这里,我们使用docker run -it -p8080:8080 demo:0.0.1-SNAPSHOT进行启动。
docker run -it -p8080:8080 demo:0.0.1-SNAPSHOT
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.3.0.M1)
2020-02-08 06:33:43.540 WARN 1 --- [ main] pertySourceApplicationContextInitializer : Skipping 'cloud' property source addition because not in a cloud
2020-02-08 06:33:43.570 WARN 1 --- [ main] nfigurationApplicationContextInitializer : Skipping reconfiguration because not in a cloud
2020-02-08 06:33:43.635 INFO 1 --- [ main] com.example.demo.DemoApplication : Starting DemoApplication on 40fbed8bc770 with PID 1 (/workspace/BOOT-INF/classes started by cnb in /workspace)
2020-02-08 06:33:43.636 INFO 1 --- [ main] com.example.demo.DemoApplication : No active profile set, falling back to default profiles: default
2020-02-08 06:33:48.387 INFO 1 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2020-02-08 06:33:48.456 INFO 1 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2020-02-08 06:33:48.466 INFO 1 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.30]
2020-02-08 06:33:48.738 INFO 1 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2020-02-08 06:33:48.740 INFO 1 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 4841 ms
2020-02-08 06:33:50.208 INFO 1 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2020-02-08 06:33:50.900 INFO 1 --- [ main] o.s.b.a.e.web.EndpointLinksResolver : Exposing 14 endpoint(s) beneath base path '/actuator'
2020-02-08 06:33:51.122 INFO 1 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2020-02-08 06:33:51.142 INFO 1 --- [ main] com.example.demo.DemoApplication : Started DemoApplication in 9.779 seconds (JVM running for 12.428)
一切正常,应用程序已成功启动。由于上次使用过该应用程序,Actuator仍然处于启用状态。让我们获取一下env的信息。
curl localhost:8080/actuator/env | jq
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 8753 0 8753 0 0 10130 0 --:--:-- --:--:-- --:--:-- 10130
{
"activeProfiles": [],
"propertySources": [
{
"name": "server.ports",
"properties": {
"local.server.port": {
"value": 8080
}
}
},
{
"name": "servletContextInitParams",
"properties": {}
},
{
"name": "systemProperties",
"properties": {
"awt.toolkit": {
"value": "sun.awt.X11.XToolkit"
},
"java.specification.version": {
"value": "11"
},
"sun.cpu.isalist": {
"value": ""
},
"sun.jnu.encoding": {
"value": "ANSI_X3.4-1968"
},
"java.class.path": {
"value": "/layers/org.cloudfoundry.springautoreconfiguration/auto-reconfiguration/java-buildpack-auto-reconfiguration-2.11.0.RELEASE.jar:/workspace/BOOT-INF/classes:/workspace/BOOT-INF/lib/HdrHistogram-2.1.11.jar:/workspace/BOOT-INF/lib/LatencyUtils-2.0.3.jar:/workspace/BOOT-INF/lib/jackson-annotations-2.10.1.jar:/workspace/BOOT-INF/lib/jackson-core-2.10.1.jar:/workspace/BOOT-INF/lib/jackson-databind-2.10.1.jar:/workspace/BOOT-INF/lib/jackson-datatype-jdk8-2.10.1.jar:/workspace/BOOT-INF/lib/jackson-datatype-jsr310-2.10.1.jar:/workspace/BOOT-INF/lib/jackson-module-parameter-names-2.10.1.jar:/workspace/BOOT-INF/lib/jakarta.annotation-api-1.3.5.jar:/workspace/BOOT-INF/lib/jakarta.el-3.0.3.jar:/workspace/BOOT-INF/lib/jul-to-slf4j-1.7.29.jar:/workspace/BOOT-INF/lib/log4j-api-2.12.1.jar:/workspace/BOOT-INF/lib/log4j-to-slf4j-2.12.1.jar:/workspace/BOOT-INF/lib/logback-classic-1.2.3.jar:/workspace/BOOT-INF/lib/logback-core-1.2.3.jar:/workspace/BOOT-INF/lib/micrometer-core-1.3.3.jar:/workspace/BOOT-INF/lib/slf4j-api-1.7.29.jar:/workspace/BOOT-INF/lib/snakeyaml-1.25.jar:/workspace/BOOT-INF/lib/spring-aop-5.2.3.RELEASE.jar:/workspace/BOOT-INF/lib/spring-beans-5.2.3.RELEASE.jar:/workspace/BOOT-INF/lib/spring-boot-2.3.0.M1.jar:/workspace/BOOT-INF/lib/spring-boot-actuator-2.3.0.M1.jar:/workspace/BOOT-INF/lib/spring-boot-actuator-autoconfigure-2.3.0.M1.jar:/workspace/BOOT-INF/lib/spring-boot-autoconfigure-2.3.0.M1.jar:/workspace/BOOT-INF/lib/spring-boot-starter-2.3.0.M1.jar:/workspace/BOOT-INF/lib/spring-boot-starter-actuator-2.3.0.M1.jar:/workspace/BOOT-INF/lib/spring-boot-starter-json-2.3.0.M1.jar:/workspace/BOOT-INF/lib/spring-boot-starter-logging-2.3.0.M1.jar:/workspace/BOOT-INF/lib/spring-boot-starter-tomcat-2.3.0.M1.jar:/workspace/BOOT-INF/lib/spring-boot-starter-web-2.3.0.M1.jar:/workspace/BOOT-INF/lib/spring-context-5.2.3.RELEASE.jar:/workspace/BOOT-INF/lib/spring-core-5.2.3.RELEASE.jar:/workspace/BOOT-INF/lib/spring-expression-5.2.3.RELEASE.jar:/workspace/BOOT-INF/lib/spring-jcl-5.2.3.RELEASE.jar:/workspace/BOOT-INF/lib/spring-web-5.2.3.RELEASE.jar:/workspace/BOOT-INF/lib/spring-webmvc-5.2.3.RELEASE.jar:/workspace/BOOT-INF/lib/tomcat-embed-core-9.0.30.jar:/workspace/BOOT-INF/lib/tomcat-embed-websocket-9.0.30.jar:/workspace"
},
"java.vm.vendor": {
"value": "AdoptOpenJDK"
},
"sun.arch.data.model": {
"value": "64"
},
"java.vendor.url": {
"value": "https://adoptopenjdk.net/"
},
"catalina.useNaming": {
"value": "false"
},
"user.timezone": {
"value": "GMT"
},
"os.name": {
"value": "Linux"
},
"java.vm.specification.version": {
"value": "11"
},
"sun.java.launcher": {
"value": "SUN_STANDARD"
},
"user.country": {
"value": "US"
},
"sun.boot.library.path": {
"value": "/layers/org.cloudfoundry.openjdk/openjdk-jre/lib"
},
"sun.java.command": {
"value": "******"
},
"jdk.debug": {
"value": "release"
},
"sun.cpu.endian": {
"value": "little"
},
"user.home": {
"value": "/home/cnb"
},
"user.language": {
"value": "en"
},
"java.specification.vendor": {
"value": "Oracle Corporation"
},
"java.version.date": {
"value": "2019-10-15"
},
"java.home": {
"value": "/layers/org.cloudfoundry.openjdk/openjdk-jre"
},
"file.separator": {
"value": "/"
},
"java.vm.compressedOopsMode": {
"value": "32-bit"
},
"line.separator": {
"value": "\n"
},
"java.specification.name": {
"value": "Java Platform API Specification"
},
"java.vm.specification.vendor": {
"value": "Oracle Corporation"
},
"java.awt.graphicsenv": {
"value": "sun.awt.X11GraphicsEnvironment"
},
"java.awt.headless": {
"value": "true"
},
"sun.management.compiler": {
"value": "HotSpot 64-Bit Tiered Compilers"
},
"java.runtime.version": {
"value": "11.0.5+10"
},
"user.name": {
"value": "cnb"
},
"path.separator": {
"value": ":"
},
"os.version": {
"value": "4.9.184-linuxkit"
},
"java.runtime.name": {
"value": "OpenJDK Runtime Environment"
},
"file.encoding": {
"value": "ANSI_X3.4-1968"
},
"spring.beaninfo.ignore": {
"value": "true"
},
"java.vm.name": {
"value": "OpenJDK 64-Bit Server VM"
},
"java.vendor.version": {
"value": "AdoptOpenJDK"
},
"java.vendor.url.bug": {
"value": "https://github.com/AdoptOpenJDK/openjdk-build/issues"
},
"java.io.tmpdir": {
"value": "/tmp"
},
"catalina.home": {
"value": "/tmp/tomcat.9057283283640867778.8080"
},
"java.version": {
"value": "11.0.5"
},
"user.dir": {
"value": "/workspace"
},
"os.arch": {
"value": "amd64"
},
"java.vm.specification.name": {
"value": "Java Virtual Machine Specification"
},
"PID": {
"value": "1"
},
"java.awt.printerjob": {
"value": "sun.print.PSPrinterJob"
},
"sun.os.patch.level": {
"value": "unknown"
},
"catalina.base": {
"value": "/tmp/tomcat.9057283283640867778.8080"
},
"java.library.path": {
"value": "/layers/org.cloudfoundry.openjdk/openjdk-jre/lib:/usr/java/packages/lib:/usr/lib64:/lib64:/lib:/usr/lib"
},
"java.vendor": {
"value": "AdoptOpenJDK"
},
"java.vm.info": {
"value": "mixed mode"
},
"java.vm.version": {
"value": "11.0.5+10"
},
"sun.io.unicode.encoding": {
"value": "UnicodeLittle"
},
"java.class.version": {
"value": "55.0"
}
}
後略
你们使用的是AdoptOpenJDK的11版本进行Java的实现,对吗?操作系统看起来是类似于Linux。
总结
由于不需要编写Dockerfile,即使没有Docker知识,也可以轻松地创建Docker镜像。虽然需要确认规范和细节才能立即投入生产环境,但能够轻松创建Docker镜像可能是一个优势,不是吗?
我已将所使用的源代码放在以下位置。
供参考使用。