应用程序元数据
Spring Boot 支持在可执行 jar 中捆绑有关应用程序配置属性的元数据,用于工具和文档生成。在本节中,我们将讨论如何配置和构建应用程序,包括如何提供应用程序配置元数据作为容器镜像中的标签,以便与 Data Flow 配合使用。
对于您自己的应用程序,您可以轻松地生成应用程序配置元数据,方法是使用 spring-boot-configuration-processor
库从使用 @ConfigurationProperties
注释的类中生成。该库包含一个 Java 注释处理器,当您编译项目以生成配置元数据文件时,该处理器将被调用,该文件存储在 uber-jar 中,名为 META-INF/spring-configuration-metadata.json
。
要使用配置处理器,请在应用程序的 pom.xml
中包含以下依赖项
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
公开数据流的应用程序属性
Stream 和 Task 应用程序是 Spring Boot 应用程序,它们提供通用的应用程序属性,以及数据流使用的通用属性,以及应用程序依赖项中包含的其他属性。对于典型的应用程序,可用的完整属性集可能非常庞大。这对数据流工具的可用性提出了挑战。因此,数据流 UI 和 shell 中的应用程序配置功能依赖于额外的配置属性元数据,以确保在提供上下文帮助(例如列出可用属性、处理自动完成和执行前端验证)时,默认情况下仅包含最相关的配置属性。
数据流配置元数据
要定义哪些应用程序属性与数据流最相关,请在项目资源目录中创建一个名为 META-INF/dataflow-configuration-metadata.properties
的文件。此文件必须包含以下一个或两个属性
configuration-properties.classes
,包含以逗号分隔的完全限定@ConfigurationProperties
类名列表。configuration-properties.names
,包含以逗号分隔的属性名称列表。这可以是完整的属性名称(例如server.port
)或前缀(例如spring.jmx
),以包含所有相关属性。
Spring Cloud Stream 应用程序 Git 存储库是查找示例的好地方。例如,jdbc sink 的 dataflow-configuration-metadata.properties 文件包含
configuration-properties.classes=org.springframework.cloud.fn.consumer.jdbc.JdbcConsumerProperties
configuration-properties.names=\
spring.datasource.url,\
spring.datasource.driver-class-name,\
spring.datasource.username,\
spring.datasource.password,\
spring.datasource.schema,\
spring.datasource.data,\
spring.datasource.initialization-mode
在这里,我们希望公开 sink 使用的特定 @ConfigurationProperties
,以及配置 JDBC 数据源所需的一些标准 spring.datasource
配置属性。
打包配置元数据
在可执行 jar 或容器镜像中打包配置属性的常见步骤如下:
- 如上文所述,将 Boot 的配置处理器添加到您的 pom.xml 中
- 如上文所述,指定要公开的属性
- 如有必要,请按照此处的说明配置
spring-cloud-app-starter-metadata-maven-plugin
在容器镜像中使用应用程序元数据创建标签的附加步骤如下:
- 按照此处的说明配置
properties-maven-plugin
,以将META-INF/spring-configuration-metadata-encoded.properties
加载为 maven 属性。 除其他步骤外,它还将加载org.springframework.cloud.dataflow.spring.configuration.metadata.json
属性。 - 如有必要,请按照此处的说明扩展
jib-maven-plugin
(或docker-maven-plugin
)配置。
专用元数据工件
将应用程序元数据包含在 uber jar 中的缺点是需要下载可能非常大的 uber jar 才能检查元数据。 这会导致在调用需要此元数据的某些数据流操作时出现明显的延迟。 创建一个仅包含应用程序元数据的单独 jar 文件有几个优点
- 元数据工件通常只有几 KB,而实际应用程序则有几 MB。 因此,它的下载速度更快,在使用数据流的 UI 和 shell 时可以实现快速响应时间。
- 较小的尺寸也有助于资源受限的环境,例如 Cloud Foundry,在这些环境中,本地磁盘大小通常受到限制。
对于使用容器镜像的环境(例如 Kubernetes),数据流通过 REST API 访问已配置的容器注册表以查询元数据,而无需下载镜像。 或者,如果您选择创建专用的元数据 jar,数据流将使用它。
创建元数据工件
spring-cloud-app-starter-metadata-maven-plugin
插件有助于为您的应用程序准备所有必要的元数据文件。根据运行时的不同,元数据要么打包为单独的伴随工件 jar,要么打包为应用程序容器映像内的配置标签。要使用该插件,请将以下内容添加到您的 pom.xml
中
<plugin>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dataflow-apps-metadata-plugin</artifactId>
<version>1.0.2</version>
<configuration>
<storeFilteredMetadata>true</storeFilteredMetadata>
</configuration>
<executions>
<execution>
<id>aggregate-metadata</id>
<phase>compile</phase>
<goals>
<goal>aggregate-metadata</goal>
</goals>
</execution>
</executions>
</plugin>
您必须将此插件与创建 spring-configuration-metadata.json
文件的 spring-boot-configuration-processor
插件结合使用。请确保同时配置了这两个插件。
注意:Spring Boot 的 Cloud Native 构建包(强烈建议使用 Spring Boot 2.4.1 版及以上版本 的 Maven 插件的 build-image 目标)会自动为配置正确的应用程序提供此元数据。
元数据 Jar 文件
对于 uber-jar 打包的应用程序,该插件将创建一个包含元数据的伴随工件。具体来说,它包含有关配置属性元数据的 Spring Boot JSON 文件以及上一节中描述的数据流配置元数据文件。以下示例显示了此类工件的内容,以规范日志接收器为例
jar tvf log-sink-rabbit-3.0.0.BUILD-SNAPSHOT-metadata.jar
373848 META-INF/spring-configuration-metadata.json
174 META-INF/dataflow-configuration-metadata.properties
spring-cloud-app-starter-metadata-maven-plugin
插件会生成一个随时可用的应用程序 metadata.jar
工件。请确保在应用程序的 pom 中配置了该插件。
元数据容器映像标签
对于打包为容器映像的应用程序,spring-cloud-app-starter-metadata-maven-plugin
会将 spring-configuration-metadata.json
文件的内容作为配置标签复制到生成的应用程序容器映像中,并将数据流的公开属性复制到 org.springframework.cloud.dataflow.spring.configuration.metadata.json
标签下。所有配置元数据都包含在容器映像中,因此不需要伴随工件。
在编译时,该插件会生成一个 META-INF/spring-configuration-metadata-encoded.properties
文件,其中包含一个属性:org.springframework.cloud.dataflow.spring.configuration.metadata.json
。属性值是字符串化的、公开的配置元数据子集。以下清单显示了一个典型的元数据 JSON 文件
org.springframework.cloud.dataflow.spring.configuration.metadata.json={\n \"groups\": [{\n \"name\": \"log\",\n \"type\": \"org.springframework.cloud.stream.app.log.sink.LogSinkProperties\",\n \"sourceType\": \"org.springframework.cloud.stream.app.log.sink.LogSinkProperties\"\n }],\n \"properties\": [\n {\n \"name\": \"log.expression\",\n \"type\": \"java.lang.String\",\n \"description\": \"A SpEL expression (against the incoming message) to evaluate as the logged message.\",\n \"sourceType\": \"org.springframework.cloud.stream.app.log.sink.LogSinkProperties\",\n \"defaultValue\": \"payload\"\n },\n {\n \"name\": \"log.level\",\n \"type\": \"org.springframework.integration.handler.LoggingHandler$Level\",\n \"description\": \"The level at which to log messages.\",\n \"sourceType\": \"org.springframework.cloud.stream.app.log.sink.LogSinkProperties\"\n },\n {\n \"name\": \"log.name\",\n \"type\": \"java.lang.String\",\n \"description\": \"The name of the logger to use.\",\n \"sourceType\": \"org.springframework.cloud.stream.app.log.sink.LogSinkProperties\"\n }\n ],\n \"hints\": []\n}
Properties Maven 插件
要将此属性转换为 Docker 标签,我们首先需要使用 properties-maven-plugin
插件将其加载为 Maven 属性。
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>properties-maven-plugin</artifactId>
<version>1.0.0</version>
<executions>
<execution>
<phase>process-classes</phase>
<goals>
<goal>read-project-properties</goal>
</goals>
<configuration>
<files>
<file>${project.build.outputDirectory}/META-INF/spring-configuration-metadata-encoded.properties</file>
</files>
</configuration>
</execution>
</executions>
</plugin>
Container Maven 插件
借助 fabric8:docker-maven-plugin
或 jib
Maven 插件,将 org.springframework.cloud.dataflow.spring.configuration.metadata.json
属性插入到具有相同名称的 Docker 标签中。
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
<version>2.0.0</version>
<configuration>
<from>
<image>springcloud/openjdk</image>
</from>
<to>
<image>springcloudstream/${project.artifactId}</image>
<tags>
<tag>3.0.0.BUILD-SNAPSHOT</tag>
</tags>
</to>
<container>
<creationTime>USE_CURRENT_TIMESTAMP</creationTime>
<format>Docker</format>
<labels>
<org.springframework.cloud.dataflow.spring-configuration-metadata.json>
${org.springframework.cloud.dataflow.spring.configuration.metadata.json}
</org.springframework.cloud.dataflow.spring-configuration-metadata.json>
</labels>
</container>
</configuration>
</plugin>
注意:docker-maven-plugin
版本必须至少为 0.33.0
或更新版本!
<plugin>
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>0.33.0</version>
<configuration>
<images>
<image>
<name>springcloudstream/${project.artifactId}:2.1.3.BUILD-SNAPSHOT</name>
<build>
<from>springcloud/openjdk</from>
<volumes>
<volume>/tmp</volume>
</volumes>
<labels>
<org.springframework.cloud.dataflow.spring-configuration-metadata.json>
${org.springframework.cloud.dataflow.spring.configuration.metadata.json}
</org.springframework.cloud.dataflow.spring-configuration-metadata.json>
</labels>
<entryPoint>
<exec>
<arg>java</arg>
<arg>-jar</arg>
<arg>/maven/log-sink-kafka.jar</arg>
</exec>
</entryPoint>
<assembly>
<descriptor>assembly.xml</descriptor>
</assembly>
</build>
</image>
</images>
</configuration>
</plugin>
使用应用程序元数据
生成应用程序配置元数据(作为单独的伴随工件或作为配置标签嵌入到应用程序容器镜像中)后,您可能需要一些额外的配置才能让 Data Flow 知道在哪里查找它。
使用元数据 Jar 文件
使用 app register
命令注册单个应用程序时,可以在 shell 中使用可选的 --metadata-uri
选项,如下所示:
dataflow:>app register --name log --type sink
--uri maven://org.springframework.cloud.stream.app:log-sink:3.2.1
--metadata-uri maven://org.springframework.cloud.stream.app:log-sink:jar:metadata:3.2.1
使用 app import
命令注册多个文件时,除了每个 <type>.<name>
行之外,该文件还应包含 <type>.<name>.metadata
行。严格来说,这样做是可选的(如果某些应用程序有,而其他应用程序没有,它也能工作),但这是最佳实践。
以下示例显示了一个 uber jar 应用程序,其中元数据工件托管在 Maven 存储库中(通过 http://
或 file://
检索它同样可行)。
source.http=maven://org.springframework.cloud.stream.app:log-sink:3.2.1
source.http.metadata=maven://org.springframework.cloud.stream.app:log-sink:jar:metadata:3.2.1
使用元数据容器镜像标签
使用 app register
命令注册单个 Docker 应用程序时,Data Flow 服务器会自动检查 org.springframework.cloud.dataflow.spring-configuration-metadata.json
配置标签中的元数据。
dataflow:>app register --name log --type sink --uri container:springcloudstream/log-sink-rabbit:2.1.13.RELEASE
配置特定于每个目标容器注册表提供程序或实例。
对于具有卷挂载密钥的私有容器注册表,注册表配置会自动从密钥中推断出来。此外,spring.cloud.dataflow.container.registry-configurations
还具有允许您显式配置多个容器注册表的属性,如下所示
容器注册表支持
您可以开箱即用地连接到各种云端和本地容器注册表,例如 Harbor、Arifactory/JFrog、Amazon ECR、Azure 容器注册表 或 托管您自己的私有注册表。
由于不同的注册表可能会采用不同的身份验证方案,以下部分提供了特定于注册表的配置详细信息
- Docker Hub - 公共 Docker Hub 注册表
- spring.cloud.dataflow.container.registry-configurations[default].registry-host=registry-1.docker.io
- spring.cloud.dataflow.container.registry-configurations[default].authorization-type=dockeroauth2
- spring.cloud.dataflow.container.registry-configurations[default].extra[registryAuthUri]=https://auth.docker.io/token?service=registry.docker.io&scope=repository:{repository}:pull&offline_token=1&client_id=shell
spring:
cloud:
dataflow:
container:
registry-configurations:
default:
registry-host: registry-1.docker.io
authorization-type: dockeroauth2
extra:
'registryAuthUri': 'https://auth.docker.io/token?service=registry.docker.io&scope=repository:{repository}:pull&offline_token=1&client_id=shell'
默认情况下使用此注册表。如果镜像名称未提供注册表主机前缀。公共 Docker Hub 存储库不需要用户名和密码授权。但是,私有 Docker Hub 存储库需要凭据。
- spring.cloud.dataflow.container.registry-configurations[harbor].registry-host=demo.goharbor.io
- spring.cloud.dataflow.container.registry-configurations[harbor].authorization-type=dockeroauth2
- spring.cloud.dataflow.container.registry-configurations[harbor].user=admin
- spring.cloud.dataflow.container.registry-configurations[harbor].secret=Harbor12345
spring:
cloud:
dataflow:
container:
registry-configurations:
harbor:
registry-host: demo.goharbor.io
authorization-type: dockeroauth2
user: admin
secret: Harbor12345
Harbor 注册表配置使用类似于 DockerHub 的 OAuth2 令牌授权,但使用不同的 registryAuthUri
。后者会在引导时自动解析,但您可以像这样覆盖它
- spring.cloud.dataflow.container.registry-configurations[harbor].extra[registryAuthUri]=https://demo.goharbor.io/service/token?service=harbor-registry&scope=repository:{repository}:pull
spring:
cloud:
dataflow:
container:
registry-configurations:
harbor:
extra:
'registryAuthUri': https://demo.goharbor.io/service/token?service=harbor-registry&scope=repository:{repository}:pull
- spring.cloud.dataflow.container.registry-configurations[myjfrog].registry-host=springsource-docker-private-local.jfrog.io
- spring.cloud.dataflow.container.registry-configurations[myjfrog].authorization-type=basicauth
- spring.cloud.dataflow.container.registry-configurations[myjfrog].user=[artifactory user]
- spring.cloud.dataflow.container.registry-configurations[myjfrog].secret=[artifactory encrypted password]
spring:
cloud:
dataflow:
container:
registry-configurations:
myjfrog:
registry-host: springsource-docker-private-local.jfrog.io
authorization-type: basicauth
user: [artifactory user]
secret: [artifactory encrypted password]
注意:您需要在 JFrog 中创建一个加密密码。
- spring.cloud.dataflow.container.registry-configurations[myecr].registry-host=283191309520.dkr.ecr.us-west-1.amazonaws.com
- spring.cloud.dataflow.container.registry-configurations[myecr].authorization-type=awsecr
- spring.cloud.dataflow.container.registry-configurations[myecr].user=[your AWS accessKey]
- spring.cloud.dataflow.container.registry-configurations[myecr].secret=[your AWS secretKey]
- spring.cloud.dataflow.container.registry-configurations[myecr].extra[region]=us-west-1
- spring.cloud.dataflow.container.registry-configurations[myecr].extra[registryIds]=283191309520
spring:
cloud:
dataflow:
container:
registry-configurations:
myecr:
registry-host: 283191309520.dkr.ecr.us-west-1.amazonaws.com
authorization-type: awsecr
user: [your AWS accessKey]
secret: [your AWS secretKey]
extra:
region: us-west-1
'registryIds': 283191309520
除了凭据之外,您还必须通过额外属性配置提供注册表的 region
(例如,.extra[region]=us-west-1
)。或者,您可以通过将 .extra[registryIds]
属性设置为逗号分隔值来设置注册表 ID。
- spring.cloud.dataflow.container.registry-configurations[myazurecr].registry-host=tzolovazureregistry.azurecr.io
- spring.cloud.dataflow.container.registry-configurations[myazurecr].authorization-type=basicauth
- spring.cloud.dataflow.container.registry-configurations[myazurecr].user=[your Azure registry username]
- spring.cloud.dataflow.container.registry-configurations[myazurecr].secret=[your Azure registry access password]
spring:
cloud:
dataflow:
container:
registry-configurations:
myazurecr:
registry-host: tzolovazureregistry.azurecr.io
authorization-type: basicauth
user: [your Azure registry username]
secret: [your Azure registry access password]
自定义
- 覆盖/增强卷挂载密钥
属性可以覆盖或增强通过注册表密钥获得的配置。例如,如果您创建了一个密钥来访问运行在地址 my-private-registry:5000
的注册表,则可以按如下方式禁用此注册表的 SSL 验证
- spring.cloud.dataflow.container.registry-configurations[myregistry].registry-host=my-private-registry:5000
- spring.cloud.dataflow.container.registry-configurations[myregistry].disableSslVerification=true
spring:
cloud:
dataflow:
container:
registry-configurations:
myregistry:
registry-host: my-private-registry:5000
disableSslVerification: true
这对于使用自签名证书测试注册表非常方便。
- 通过 Http 代理连接
您可以通过预先配置的代理重定向某些注册表配置。例如,如果通过配置在 my-proxy.test:8080
的代理访问运行在地址 my-private-registry:5000
的注册表,
- spring.cloud.dataflow.container.http-proxy.host=my-proxy.test
- spring.cloud.dataflow.container.http-proxy.port=8080
- spring.cloud.dataflow.container.registry-configurations[myregistrywithproxy].registry-host=my-proxy-registry:5000
- spring.cloud.dataflow.container.registry-configurations[myregistrywithproxy].use-http-proxy=true
spring:
cloud:
dataflow:
container:
httpProxy:
host: my-proxy.test
port: 8080
registry-configurations:
myregistrywithproxy:
registry-host: my-proxy-registry:5000
use-http-proxy: true
spring.cloud.dataflow.container.http-proxy
属性允许您配置全局 HTTP 代理,并且您可以选择使用注册表配置 use-http-proxy
属性为每个注册表使用代理。默认情况下不使用代理。