Spring Boot 应用程序可以使用 Dockerfiles进行容器化,或者使用 Cloud Native Buildpacks 创建优化的 docker 兼容容器镜像,您可以在任何地方运行。
很容易将 Spring Boot fat jar 打包为 docker 镜像。然而,在 docker 镜像中复制和运行 fat jar 有很多缺点。在不打开包装的情况下运行 fat jar 总是有一定的开销,在容器化环境中这可能很明显。另一个问题是,将应用程序的代码及其所有依赖项放在 Docker 映像的一层中是次优的。由于您可能比升级您使用的 Spring Boot 版本更频繁地重新编译您的代码,因此通常最好将它们分开一点。如果你把jar文件放在你的应用程序类之前的层,Docker通常只需要改变最底层,就可以从它的缓存中提取其他的。
如果您从容器运行应用程序,则可以使用可执行 jar,但分解它并以不同的方式运行它通常也是一个优势。某些 PaaS 实现也可能会选择在运行前解压缩jar。例如,Cloud Foundry 就是这样运作的。运行解压jar的一种方法是启动适当的启动器,如下所示:
$ jar -xf myapp.jar
$ java org.springframework.boot.loader.JarLauncher
这实际上在启动时(取决于 jar 的大小)比从未分解的存档中运行要快一些。在运行时,您不应期望有任何差异。
解压 jar 文件后,您还可以通过使用其“自然”主方法而不是JarLauncher
. 例如:
$ jar -xf myapp.jar
$ java -cp BOOT-INF/classes:BOOT-INF/lib/* com.example.MyApplication
为了更容易创建优化的 Docker 镜像,Spring Boot 支持向 jar 中添加层索引文件。它提供了层列表和应包含在其中的 jar 的部分。索引中的层列表是根据应将层添加到 Docker/OCI 映像的顺序进行排序的。开箱即用,支持以下层:
dependencies
(对于定期发布的依赖项)spring-boot-loader
(对于 下的所有内容org/springframework/boot/loader
)snapshot-dependencies
(对于快照依赖项)application
(对于应用程序类和资源)下面显示了一个layers.idx
文件示例:
- "dependencies":
- BOOT-INF/lib/library1.jar
- BOOT-INF/lib/library2.jar
- "spring-boot-loader":
- org/springframework/boot/loader/JarLauncher.class
- org/springframework/boot/loader/jar/JarEntry.class
- "snapshot-dependencies":
- BOOT-INF/lib/library3-SNAPSHOT.jar
- "application":
- META-INF/MANIFEST.MF
- BOOT-INF/classes/a/b/C.class
此分层旨在根据应用程序构建之间更改的可能性来分离代码。库代码在构建之间不太可能发生变化,因此它被放置在自己的层中,以允许工具重新使用缓存中的层。应用程序代码更有可能在构建之间发生变化,因此它被隔离在一个单独的层中。
Spring Boot 还支持在layers.idx
.
对于 Maven,请参阅打包分层 jar 或 war 部分以获取有关将层索引添加到存档的更多详细信息。
虽然只需 Dockerfile 中的几行代码就可以将 Spring Boot fat jar 转换为 docker 镜像,但我们将使用分层功能来创建优化的 docker 镜像。当您创建一个包含层索引文件的 jar 时,该spring-boot-jarmode-layertools
jar 将作为依赖项添加到您的 jar 中。使用类路径中的这个 jar,您可以在特殊模式下启动应用程序,该模式允许引导代码运行与您的应用程序完全不同的东西,例如,提取层的东西。
以下是使用layertools
jar 模式启动 jar 的方法:
$ java -Djarmode=layertools -jar my-app.jar
该extract
命令可用于轻松地将应用程序拆分为要添加到 dockerfile 的层。这是一个使用jarmode
.
FROM adoptopenjdk:11-jre-hotspot as builder
WORKDIR application
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} application.jar
RUN java -Djarmode=layertools -jar application.jar extract
FROM adoptopenjdk:11-jre-hotspot
WORKDIR application
COPY --from=builder application/dependencies/ ./
COPY --from=builder application/spring-boot-loader/ ./
COPY --from=builder application/snapshot-dependencies/ ./
COPY --from=builder application/application/ ./
ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher"]
假设以上Dockerfile
内容在当前目录中,您的 docker 镜像可以使用 构建docker build .
,或者可选地指定应用程序 jar 的路径,如以下示例所示:
$ docker build --build-arg JAR_FILE=path/to/myapp.jar .
这是一个多阶段的 dockerfile。构建器阶段提取稍后需要的目录。每个COPY
命令都与 jarmode 提取的层相关。
当然,不使用 jarmode 也可以编写 Dockerfile。您可以使用unzip
和的某种组合mv
将事物移动到正确的层,但 jarmode 简化了这一点。
Dockerfiles 只是构建 docker 镜像的一种方式。构建 docker 镜像的另一种方法是直接从您的 Maven 或 Gradle 插件中使用 buildpacks。如果您曾经使用过 Cloud Foundry 或 Heroku 等应用程序平台,那么您可能使用过 buildpack。Buildpacks 是平台的一部分,它将您的应用程序转换为平台可以实际运行的东西。例如,Cloud Foundry 的 Java buildpack 会注意到您正在推送.jar
文件并自动添加相关的 JRE。
使用 Cloud Native Buildpacks,您可以创建可以在任何地方运行的 Docker 兼容镜像。Spring Boot 直接包含对 Maven 和 Gradle 的 buildpack 支持。这意味着您只需键入一个命令,就可以快速将合理的映像放入本地运行的 Docker 守护程序中。
请参阅单独的插件文档,了解如何将 buildpacks 与Maven和Gradle一起使用。
该spring-boot-actuator
模块提供了 Spring Boot 的所有生产就绪功能。spring-boot-starter-actuator
启用这些功能的推荐方法是添加对“Starter”的依赖。
要将执行器添加到基于 Maven 的项目中,请添加以下“Starter”依赖项:
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
dependencies>
执行器端点使您可以监视应用程序并与之交互。Spring Boot 包含许多内置端点,并允许您添加自己的端点。例如,health
端点提供基本的应用程序健康信息。
您可以启用或禁用每个单独的端点并通过 HTTP 或 JMX 公开它们(使它们可以远程访问)。当端点被启用和公开时,它被认为是可用的。内置端点仅在可用时才会自动配置。大多数应用程序选择通过 HTTP 公开,其中端点的 ID 和前缀/actuator
映射到 URL。例如,默认情况下,health
端点映射到/actuator/health
.
默认情况下,除了shutdown
启用之外的所有端点。要配置端点的启用,请使用其management.endpoint.
属性。以下示例启用shutdown
端点:
management:
endpoint:
shutdown:
enabled: true
如果您希望端点启用是选择加入而不是选择退出,请将management.endpoints.enabled-by-default
属性设置为false
并使用单个端点enabled
属性来选择重新加入。以下示例启用info
端点并禁用所有其他端点:
由于端点可能包含敏感信息,您应该仔细考虑何时公开它们。
要更改公开的端点,请使用以下技术特定include
和exclude
属性:
该include
属性列出了公开的端点的 ID。该exclude
属性列出不应公开的端点的 ID。exclude
财产优先于财产include
。您可以使用端点 ID 列表来配置include
和exclude
属性。
例如,要停止通过 JMX 公开所有端点并仅公开health
和info
端点,请使用以下属性:
management:
endpoints:
jmx:
exposure:
include: "health,info"
*
可用于选择所有端点。例如,要通过 HTTP 公开除env
和beans
端点之外的所有内容,请使用以下属性:
management:
endpoints:
web:
exposure:
include: "*"
exclude: "env,beans"
/health
出于安全目的,默认情况下禁用除此之外的所有执行器。您可以使用该management.endpoints.web.exposure.include
属性来启用执行器。
如果您希望为 HTTP 端点配置自定义安全性(例如,只允许具有特定角色的用户访问它们),Spring Boot 提供了一些方便RequestMatcher
的对象,您可以将它们与 Spring Security 结合使用。
典型的 Spring Security 配置可能类似于以下示例:
@Configuration(proxyBeanMethods = false)
public class MySecurityConfiguration {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.requestMatcher(EndpointRequest.toAnyEndpoint())
.authorizeRequests((requests) -> requests.anyRequest().hasRole("ENDPOINT_ADMIN"));
http.httpBasic();
return http.build();
}
}
如果您在防火墙后面部署应用程序,您可能希望无需身份验证即可访问所有执行器端点。您可以通过更改属性来做到这一点management.endpoints.web.exposure.include
,如下所示:
management:
endpoints:
web:
exposure:
include: "*"
此外,如果存在 Spring Security,您将需要添加自定义安全配置,以允许未经身份验证的访问端点,如以下示例所示:
@Configuration(proxyBeanMethods = false)
public class MySecurityConfiguration {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.requestMatcher(EndpointRequest.toAnyEndpoint())
.authorizeRequests((requests) -> requests.anyRequest().permitAll());
return http.build();
}
}
由于 Spring Boot 依赖于 Spring Security 的默认设置,因此默认开启 CSRF 保护。这意味着在使用默认安全配置时,需要POST
(关闭和记录器端点)、PUT
执行器端点DELETE
会收到 403(禁止)错误。
端点会自动缓存对不带任何参数的读取操作的响应。要配置端点缓存响应的时间量,请使用其cache.time-to-live
属性。以下示例将beans
端点缓存的生存时间设置为 10 秒:
management:
endpoint:
beans:
cache:
time-to-live: "10s"
添加了一个“发现页面”,其中包含指向所有端点的链接。默认情况下,“发现页面”可用/actuator
。
要禁用“发现页面”,请将以下属性添加到您的应用程序属性中:
management:
endpoints:
web:
discovery:
enabled: false
配置自定义管理上下文路径后,“发现页面”会自动从/actuator
管理上下文的根目录移动。例如,如果管理上下文路径是/management
,则发现页面可从/management
。当管理上下文路径设置为/
时,发现页面被禁用以防止与其他映射发生冲突的可能性。
跨域资源共享(CORS) 是一种W3C 规范,可让您以灵活的方式指定授权哪种跨域请求。如果您使用 Spring MVC 或 Spring WebFlux,则可以配置 Actuator 的 Web 端点以支持此类场景。
CORS 支持默认禁用,只有在您设置了management.endpoints.web.cors.allowed-origins
属性后才会启用。以下配置允许GET
和来自域POST
的调用:example.com
management:
endpoints:
web:
cors:
allowed-origins: "https://example.com"
allowed-methods: "GET,POST"
您可以使用健康信息来检查正在运行的应用程序的状态。当生产系统出现故障时,监控软件经常使用它来提醒某人。端点公开的信息health
取决于management.endpoint.health.show-details
和management.endpoint.health.show-components
属性,可以使用以下值之一进行配置:
名称 | 描述 |
---|---|
never |
从不显示细节。 |
when-authorized |
详细信息仅向授权用户显示。可以使用 配置授权角色management.endpoint.health.roles 。 |
always |
向所有用户显示详细信息。 |
默认值为never
。当用户处于一个或多个端点角色时,他们被认为是被授权的。如果端点没有配置角色(默认),则所有经过身份验证的用户都被认为是授权的。您可以使用该management.endpoint.health.roles
属性来配置角色。
在适当的时候,Spring Boot 会自动配置HealthIndicators
下表中列出的内容。
Key | 名称 | 描述 |
---|---|---|
cassandra |
CassandraDriverHealthIndicator |
检查 Cassandra 数据库是否已启动。 |
couchbase |
CouchbaseHealthIndicator |
检查 Couchbase 集群是否已启动。 |
db |
DataSourceHealthIndicator |
检查是否可以获得连接DataSource 。 |
diskspace |
DiskSpaceHealthIndicator |
检查磁盘空间不足。 |
elasticsearch |
ElasticsearchRestHealthIndicator |
检查 Elasticsearch 集群是否已启动。 |
hazelcast |
HazelcastHealthIndicator |
检查 Hazelcast 服务器是否已启动。 |
influxdb |
InfluxDbHealthIndicator |
检查 InfluxDB 服务器是否已启动。 |
jms |
JmsHealthIndicator |
检查 JMS 代理是否已启动。 |
ldap |
LdapHealthIndicator |
检查 LDAP 服务器是否已启动。 |
mail |
MailHealthIndicator |
检查邮件服务器是否已启动。 |
mongo |
MongoHealthIndicator |
检查 Mongo 数据库是否已启动。 |
neo4j |
Neo4jHealthIndicator |
检查 Neo4j 数据库是否已启动。 |
ping |
PingHealthIndicator |
始终以 响应UP 。 |
rabbit |
RabbitHealthIndicator |
检查 Rabbit 服务器是否已启动。 |
redis |
RedisHealthIndicator |
检查 Redis 服务器是否已启动。 |
solr |
SolrHealthIndicator |
检查 Solr 服务器是否已启动。 |
其他HealthIndicators
可用但默认情况下未启用:
key | 名称 | 描述 |
---|---|---|
livenessstate |
LivenessStateHealthIndicator |
公开“Liveness”应用程序可用性状态。 |
readinessstate |
ReadinessStateHealthIndicator |
公开“就绪”应用程序可用性状态。 |
要提供自定义健康信息,您可以注册实现该HealthIndicator
接口的 Spring bean。您需要提供该health()
方法的实现并返回Health
响应。Health
响应应包含状态,并且可以选择包含要显示的其他详细信息。以下代码显示了一个示例HealthIndicator
实现:
@Component
public class MyHealthIndicator implements HealthIndicator {
@Override
public Health health() {
int errorCode = check();
if (errorCode != 0) {
return Health.down().withDetail("Error Code", errorCode).build();
}
return Health.up().build();
}
private int check() {
// perform some specific health check
return ...
}
}
除了 Spring Boot 的预定义Status
类型之外,Health
还可以返回一个Status
表示新系统状态的自定义。在这种情况下,您还需要提供StatusAggregator
接口的自定义实现,或者您必须使用management.endpoint.health.status.order
配置属性配置默认实现。
例如,假设在您的一个实现中使用Status
了代码为的 new 。要配置严重性顺序,请将以下属性添加到您的应用程序属性中:FATAL``HealthIndicator
management:
endpoint:
health:
status:
order: "fatal,down,out-of-service,unknown,up"
响应中的 HTTP 状态代码反映了整体健康状况。默认情况下,OUT_OF_SERVICE
映射DOWN
到 503。任何未映射的健康状态,包括UP
,都映射到 200。如果您通过 HTTP 访问健康端点,您可能还需要注册自定义状态映射。配置自定义映射会禁用 和 的默认DOWN
映射OUT_OF_SERVICE
。如果要保留默认映射,则必须显式配置它们以及任何自定义映射。例如,以下属性映射FATAL
到 503(服务不可用)并保留 和 的默认DOWN
映射OUT_OF_SERVICE
:
management:
endpoint:
health:
status:
http-mapping:
down: 503
fatal: 503
out-of-service: 503
下表显示了内置状态的默认状态映射:
名称 | 映射 |
---|---|
DOWN |
SERVICE_UNAVAILABLE ( 503 ) |
OUT_OF_SERVICE |
SERVICE_UNAVAILABLE ( 503 ) |
UP |
默认没有映射,所以 HTTP 状态是 200 |
UNKNOWN |
默认没有映射,所以 HTTP 状态是 200 |
DataSource
运行状况指示器显示标准数据源和路由数据源 bean 的运行状况。路由数据源的健康状况包括其每个目标数据源的健康状况。在健康端点的响应中,每个路由数据源的目标都使用其路由键命名。如果您不想在指标的输出中包含路由数据源,请设置management.health.db.ignore-routing-data-sources
为true
。
部署在 Kubernetes 上的应用程序可以通过Container Probes提供有关其内部状态的信息。根据您的 Kubernetes 配置,kubelet 会调用这些探测器并对结果做出反应。
默认情况下,Spring Boot 管理您的应用程序可用性状态。如果部署在 Kubernetes 环境中,actuator 从ApplicationAvailability
接口收集“Liveness”和“Readiness”信息,并在专用的健康指标中使用该信息:LivenessStateHealthIndicator
和ReadinessStateHealthIndicator
。这些指标显示在全球健康端点 ( "/actuator/health"
) 上。它们还通过使用健康组:"/actuator/health/liveness"
和"/actuator/health/readiness"
.
然后,您可以使用以下端点信息配置 Kubernetes 基础架构:
livenessProbe:
httpGet:
path: "/actuator/health/liveness"
port: -port>
failureThreshold: ...
periodSeconds: ...
readinessProbe:
httpGet:
path: "/actuator/health/readiness"
port: -port>
failureThreshold: ...
periodSeconds: ...
只有当应用程序在 Kubernetes 环境中运行时,这些健康组才会自动启用。您可以使用management.endpoint.health.probes.enabled
配置属性在任何环境中启用它们。
如果您正在开发 Web 应用程序,Spring Boot Actuator 会自动配置所有启用的端点以通过 HTTP 公开。默认约定是使用id
带有前缀的端点的/actuator
作为 URL 路径。例如,health
公开为/actuator/health
.
有时,自定义管理端点的前缀很有用。例如,您的应用程序可能已经/actuator
用于其他目的。您可以使用该management.endpoints.web.base-path
属性更改管理端点的前缀,如以下示例所示:
management:
endpoints:
web:
base-path: "/manage"
前面的application.properties
示例将端点从更改/actuator/{id}
为/manage/{id}
(例如,/manage/info
)。
如果要将端点映射到不同的路径,可以使用该management.endpoints.web.path-mapping
属性。
以下示例重新映射/actuator/health
到/healthcheck
:
management:
endpoints:
web:
base-path: "/"
path-mapping:
health: "healthcheck"
使用默认 HTTP 端口公开管理端点是基于云的部署的明智选择。但是,如果您的应用程序在您自己的数据中心内运行,您可能更愿意使用不同的 HTTP 端口来公开端点。
您可以设置该management.server.port
属性以更改 HTTP 端口,如以下示例所示:
management:
server:
port: 8081
如果您不想通过 HTTP 公开端点,可以将管理端口设置为-1
,如以下示例所示:
management:
server:
port: -1
您也可以通过使用该management.endpoints.web.exposure.exclude
属性来实现此目的,如以下示例所示:
management:
endpoints:
web:
exposure:
exclude: "*
Spring Boot Actuator 为Micrometer提供依赖管理和自动配置,这是一个支持众多监控系统的应用程序指标外观,
Spring Boot 自动配置一个组合MeterRegistry
并为它在类路径上找到的每个受支持的实现添加一个注册表到组合中。在你的运行时类路径中有一个依赖就micrometer-registry-{system}
足以让 Spring Boot 配置注册表。
Spring Boot 为多种技术提供自动仪表注册。在大多数情况下,默认值提供了可以发布到任何受支持的监控系统的合理指标。
自动配置通过使用核心 Micrometer 类启用 JVM Metrics。JVM 指标以jvm.
计量名称发布。
提供了以下 JVM 指标:
自动配置通过使用核心 Micrometer 类启用系统指标。系统指标以system.
、process.
和disk.
计量名称发布。
提供了以下系统指标:
自动配置公开应用程序启动时间指标:
application.started.time
: 启动应用程序所用的时间。application.ready.time
:应用程序准备好为请求提供服务所需的时间。指标由应用程序类的完全限定名称标记。
自动配置为 Logback 和 Log4J2 启用事件指标。详细信息以log4j2.events.
或logback.events.
仪表名称发布。
只要底层可用,自动配置就可以检测所有可用的beanThreadPoolTaskExecutor
和bean 。指标由执行者的名称标记,该名称派生自 bean 名称。ThreadPoolTaskScheduler``ThreadPoolExecutor
自动配置启用对 Spring MVC 控制器和功能处理程序处理的所有请求的检测。默认情况下,生成的指标名称为http.server.requests
. 您可以通过设置management.metrics.web.server.request.metric-name
属性来自定义名称。
@Timed``@Controller
类和@RequestMapping
方法支持注释(有关详细信息,请参阅@Timed Annotation Support)。如果您不想记录所有 Spring MVC 请求的指标,则可以设置management.metrics.web.server.request.autotime.enabled
并false
专门使用@Timed
注释。
一旦 Spring Security 发挥作用,Spring Boot Actuator 就会有一个灵活的审计框架来发布事件(默认情况下,“身份验证成功”、“失败”和“访问被拒绝”异常)。此功能对于报告和实施基于身份验证失败的锁定策略非常有用。
AuditEventRepository
您可以通过在应用程序的配置中提供类型的 bean 来启用审计。为方便起见,Spring Boot 提供了一个InMemoryAuditEventRepository
. InMemoryAuditEventRepository
功能有限,我们建议仅将其用于开发环境。对于生产环境,请考虑创建您自己的替代AuditEventRepository
实现。
Spring Boot 的可执行 jar 已为大多数流行的云 PaaS(平台即服务)提供商提供了现成的。这些提供商倾向于要求您“自带容器”。他们管理应用程序进程(不是专门的 Java 应用程序),因此他们需要一个中间层,使您的应用程序适应云中运行进程的概念。
除了使用 运行 Spring Boot 应用程序之外java -jar
,还可以为 Unix 系统制作完全可执行的应用程序。完全可执行的 jar 可以像任何其他可执行二进制文件一样执行,也可以使用或注册init.d``systemd
。这有助于在常见的生产环境中安装和管理 Spring Boot 应用程序。
如果您配置 Spring Boot 的 Maven 或 Gradle 插件以生成完全可执行的 jar,并且您不使用 custom embeddedLaunchScript
,则您的应用程序可以用作init.d
服务。为此,将 jar 符号链接到init.d
以支持标准start
、stop
、restart
和status
命令。
该脚本支持以下功能:
/var/run//.pid
/var/log/.log
假设您在/var/myapp
中安装了 Spring Boot 应用程序,要将 Spring Boot 应用程序安装为init.d
服务,请创建一个符号链接,如下所示:
$ sudo ln -s /var/myapp/myapp.jar /etc/init.d/myapp
安装后,您可以按常规方式启动和停止服务。例如,在基于 Debian 的系统上,您可以使用以下命令启动它:
$ service myapp start
systemd
是 System V init 系统的继承者,现在被许多现代 Linux 发行版使用。尽管您可以继续使用init.d
脚本systemd
,但也可以使用systemd
“服务”脚本启动 Spring Boot 应用程序。
假设您在/var/myapp
中安装了 Spring Boot 应用程序,要将 Spring Boot 应用程序安装为systemd
服务,请创建一个名为的脚本并将myapp.service
其放置在/etc/systemd/system
目录中。以下脚本提供了一个示例:
[Unit]
Description=myapp
After=syslog.target
[Service]
User=myapp
ExecStart=/var/myapp/myapp.jar
SuccessExitStatus=143
[Install]
WantedBy=multi-user.target
请注意,与作为init.d
服务运行时不同,运行应用程序的用户、PID 文件和控制台日志文件由其systemd
自身管理,因此必须使用“服务”脚本中的适当字段进行配置。有关更多详细信息,请参阅服务单元配置手册页。
要将应用程序标记为在系统启动时自动启动,请使用以下命令:
$ systemctl enable myapp.service
运行man systemctl
以获取更多详细信息。
可以通过多种方式自定义由 Maven 或 Gradle 插件编写的默认嵌入式启动脚本。