使用Docker环境在GraalVM本地镜像中启动Spring Boot Web服务
在Docker环境中启动Spring Boot Web服务:使用GraalVM本地镜像。
你好,我是株式会社船井総研デジタル的 @fsdg-adachi_h。今天我来介绍一下如何在WSL Ubuntu的Docker环境中,将GraalVM原生镜像的Spring Boot Web应用程序作为容器来启动。
目标
在Windows 11上通过Linux进行云开发。
您可以通过点击这里查看文章的列表。
实现
在本地环境中的WSL Ubuntu的Docker环境中,使用Dockerfile构建的GraalVM本地映像Spring Boot Web服务的自定义容器映像来启动。
以原生形式启动应用作为容器。
执行环境
网络服务容器
技术话题
在Java中,什么是本地镜像构建?
Native Image Build 将Java代码编译成本地机器码。通常,Java代码被编译为一种中间语言称为Java字节码,并在Java虚拟机(JVM)上运行。然而,通过Native Image Build,可以直接将Java代码转换为可直接执行的本地机器码,从而实现更快的执行速度和更低的内存使用量。
Native Image Build的需求来自以下方面:
关键词 内容
性能提升 Java通常被认为是一种高级编程语言,并且由于在JVM上运行,执行速度可能较慢。通过Native Image Build,可以实现高速的执行速度。
内存优化 使用JVM执行Java代码通常需要大量内存。通过Native Image Build,可以使用更少的内存来运行程序。
本地程序集成 Java可以与其他编写的本地程序(如C语言或C++)集成。但是,为了进行集成,需要本地代码。通过Native Image Build,可以将这些本地程序和Java代码无缝集成在一起。
Dockerfile 是什么?
Dockerfile
Dockerfile是一个用于构建Docker容器的文本文件。Docker容器是包含运行应用程序和服务所需要的环境的轻量级可移植虚拟化单元。
关键词 内容
脚本格式 Dockerfile以简单的脚本格式编写,因此容器的构建过程可以轻松自动化。
层级结构 Docker镜像在执行Dockerfile的每个命令时以图层的形式生成,并且可以进行重用和缓存。
版本控制 Dockerfile以文本为基础,因此与代码一样容易使用版本控制系统进行管理。
可移植性 通过Dockerfile,应用程序及其依赖可以打包到一个容器镜像中,从而提高在不同环境之间的可移植性。
自动化与效率 通过使用Dockerfile,可以自动化应用程序的构建和环境设置。这样可以减少手动操作时间和人为错误,提高开发和部署过程的效率。
可重现性 Dockerfile完全定义了构建步骤,因此可以在不同环境中复制相同的应用程序。这样可以确保在开发、测试和生产环境之间的一致性。
环境隔离 Docker容器与主机系统分离,以避免应用程序的依赖关系和库的冲突,并在更安全的环境中运行。
可扩展性 通过使用Dockerfile,可以创建自定义镜像。因此,可以轻松创建根据特定需求定制的容器镜像。
开发环境
- Windows 11 Home 22H2 を使用しています。
> wsl –version
WSL版本:1.0.3.0
内核版本:5.15.79.1
WSLg版本:1.0.47安装Ubuntu。请从相关文章中查看安装方法。
$ lsb_release -a
没有可用的LSB模块。
发行商ID:Ubuntu
描述:Ubuntu 22.04.1 LTS
发布:22.04
安装Java JDK。请从相关文章中查看安装方法。
$ java -version
openjdk版本:“17.0.6” 2023-01-17
OpenJDK Runtime环境 GraalVM CE 22.3.1(构建17.0.6+10-jvmci-22.3-b13)
OpenJDK 64位服务器VM GraalVM CE 22.3.1(构建17.0.6+10-jvmci-22.3-b13,混合模式,共享)
安装Maven。请从相关文章中查看安装方法。
$ mvn -version
Apache Maven 3.6.3
Maven目录:/usr/share/maven
Java版本:11.0.18,供应商:Ubuntu,运行时:/usr/lib/jvm/java-11-openjdk-amd64
安装Docker。请从相关文章中查看安装方法。
$ docker –version
Docker版本23.0.1,构建a5ee5b1
制作网络应用的规格.
{“message”:”你好,世界!”}
显示 Hello World 的步骤
GraalVM的环境设置。
您可以在这篇相关文章中查看步骤确认。
确认JDK的版本
切换Java的版本。
$ sudo update-alternatives --config java
$ sudo update-alternatives --config javac
$ java -version
openjdk version "17.0.6" 2023-01-17
OpenJDK Runtime Environment GraalVM CE 22.3.1 (build 17.0.6+10-jvmci-22.3-b13)
OpenJDK 64-Bit Server VM GraalVM CE 22.3.1 (build 17.0.6+10-jvmci-22.3-b13, mixed mode, sharing)
创建Spring Boot Web服务。
您可以在这篇相关文章中确认步骤。
转到项目文件夹中
切换到项目文件夹。
※ 我们将~/tmp/hello-spring-boot定义为项目文件夹。
$ cd ~/tmp/hello-spring-boot
删除控制器类,修改应用程序类。
$ rm src/main/java/com/example/springboot/controller/HelloController.java
$ vim src/main/java/com/example/springboot/Application.java文件内容
Application.java
package com.example.springboot;
import java.util.Map;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@SpringBootApplication
@RequestMapping(“/api”)
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@GetMapping(“/data”)
public Map<String, String> getData() {
Map<String, String> map = Map.of(“message”, “你好世界!”);
return map;
}
}
修改 pom.xml
创建pom.xml文件。
$ vim 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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>hello-spring-boot</artifactId>
<version>1.0</version>
<name>hello-spring-boot</name>
<properties>
<java.version>17</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<finalName>app</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
<configuration>
<imageName>app</imageName>
</configuration>
</plugin>
</plugins>
</build>
</project>
构建一个以母语为基础的形象
构建一个本地镜像。
※将在target/app创建一个本地镜像。
$ mvn -Pnative native:compile
构建本地镜像容器。
修改Dockerfile。
$ vim Dockerfile
文件的内容 de
# because the native image app was built by Ubuntu 22.04.
FROM ubuntu:22.04
# create a work dir.
WORKDIR /app
# copy a native image app.
COPY target/app app
# open port 8080 for a native image app.
EXPOSE 8080
# startup a native image app.
ENTRYPOINT ["./app"]
启动 Docker 守护进程。
$ sudo service docker start
* Starting Docker: docker [ OK ]
构建容器镜像。
$ docker build \
--no-cache \
--tag app-hello-spring-boot-native:latest .
我要确认容器镜像。
$ docker images | grep app-hello-spring-boot-native
app-hello-spring-boot-native latest f0794df4d28c 23 minutes ago 149MB
启动容器
在本地启动容器。
※ 停止容器时,请按下 ctrl + C。
$ docker run --rm \
--publish 8080:8080 \
--name app-local \
app-hello-spring-boot-native:latest
与传统的JVM容器相比,启动时间大大缩短。
2023-03-14T11:09:55.330Z INFO 1 --- [main] com.example.springboot.Application : Started Application in 0.073 seconds (process running for 0.08)
$ docker run –rm –name app-local -p 8080:8080 app-hello-spring-boot-native:latest. ____ _ __ _ _
/\\ / ___’_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | ‘_ | ‘_| | ‘_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
‘ |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v3.0.4)
2023-03-14T11:09:55.275Z INFO 1 — [ main] com.example.springboot.Application : 使用Java 17.0.6和PID 1启动AOT-处理的应用程序(由cnb在/workspace中启动)
2023-03-14T11:09:55.275Z INFO 1 — [ main] com.example.springboot.Application : 未设置活动配置文件,回退到默认配置文件: “default”
2023-03-14T11:09:55.290Z INFO 1 — [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat使用8080端口初始化(http)
2023-03-14T11:09:55.291Z INFO 1 — [ main] o.apache.catalina.core.StandardService : 启动服务 [Tomcat]
2023-03-14T11:09:55.291Z INFO 1 — [ main] o.apache.catalina.core.StandardEngine : 启动Servlet引擎:[Apache Tomcat/10.1.5]
2023-03-14T11:09:55.298Z INFO 1 — [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : 初始化Spring嵌入式WebApplicationContext
2023-03-14T11:09:55.298Z INFO 1 — [ main] w.s.c.ServletWebServerApplicationContext : 根WebApplicationContext:初始化完成,耗时22毫秒
2023-03-14T11:09:55.329Z INFO 1 — [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat已启动,端口:8080(http),上下文路径:”
2023-03-14T11:09:55.330Z INFO 1 — [ main] com.example.springboot.Application : 应用程序已启动,耗时0.073秒(进程运行0.08秒)
容器的运行确认
使用curl命令从另一个终端进行确认。
$ curl -v http://localhost:8080/api/data -w '\n'
发力
* Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /api/data HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.81.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200
< Content-Type: application/json
< Transfer-Encoding: chunked
< Date: Fri, 04 Aug 2023 01:52:30 GMT
<
* Connection #0 to host localhost left intact
{"message":"Hello World!"}
连接到容器
从另一个终端连接到容器。
$ docker exec -it app-local /bin/bash
连接到容器后,请确认目录。
※ 当您要离开容器时,请按下ctrl + D。
# pwd
/app
# ls -lah
total 68M
drwxr-xr-x 1 root root 4.0K Mar 17 14:53 .
drwxr-xr-x 1 root root 4.0K Mar 17 14:53 ..
-rwxr-xr-x 1 root root 68M Mar 17 14:29 app
使用top命令来检查情况。
top - 14:58:43 up 10:17, 0 users, load average: 0.00, 0.00, 0.22
Tasks: 3 total, 1 running, 2 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.4 us, 0.2 sy, 0.0 ni, 99.3 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
MiB Mem : 7763.1 total, 4489.9 free, 1395.1 used, 1878.1 buff/cache
MiB Swap: 2048.0 total, 2046.5 free, 1.5 used. 6110.2 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1 root 20 0 1478396 108644 48388 S 0.0 1.4 0:00.21 app
35 root 20 0 4624 3748 3236 S 0.0 0.0 0:00.02 bash
43 root 20 0 7312 3424 2860 R 0.0 0.0 0:00.02 top
我尝试显示容器的信息。
# cat /etc/*-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=22.04
DISTRIB_CODENAME=jammy
DISTRIB_DESCRIPTION="Ubuntu 22.04.2 LTS"
PRETTY_NAME="Ubuntu 22.04.2 LTS"
NAME="Ubuntu"
VERSION_ID="22.04"
VERSION="22.04.2 LTS (Jammy Jellyfish)"
VERSION_CODENAME=jammy
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=jammy
总结
在 WSL Ubuntu 的 Docker 环境中,可以启动通过 Dockerfile 构建的 GraalVM 原生映像 Spring Boot Web 应用的自定义容器。
请问使用 WSL Ubuntu,在 Docker 环境中作为容器轻松启动 GraalVM 原生映像的 Spring Boot Web 应用程序的体验如何?请务必尝试一下。我们也会继续介绍 Java 的开发环境等相关内容,请敬请期待。
推荐内容
相关文章
让我们将其与常规的JAR文件格式构建进行比较吧!