本站(springdoc.cn)中的内容来源于 spring.io ,原始版权归属于 spring.io。由 springdoc.cn 进行翻译,整理。可供个人学习、研究,未经许可,不得进行任何转载、商用或与之相关的行为。 商标声明:Spring 是 Pivotal Software, Inc. 在美国以及其他国家的商标。

本参考指南包括如何使用Spring Cloud Kubernetes。

1. 为什么你需要 Spring Cloud Kubernetes?

Spring Cloud Kubernetes提供了众所周知的Spring Cloud接口的实现,允许开发者在Kubernetes上构建和运行Spring Cloud应用。虽然这个项目在构建云原生应用时可能对你有用,但它也不是在Kubernetes上部署Spring Boot应用的必要条件。如果你刚刚开始在Kubernetes上运行你的Spring Boot应用,你只需要一个基本的Spring Boot应用和Kubernetes本身就可以完成很多事情。要了解更多信息,你可以通过阅读 Spring Boot部署到Kubernetes的参考文档 开始,也可以通过 Spring 和 Kubernetes 的研讨会材料开始。

2. Starter

Starter 是方便的依赖描述,你可以在你的应用程序中包含它。导入一个Starter,以获得功能集的依赖和Spring Boot自动配置。以 spring-cloud-starter-kubernetes-fabric8 开头的Starter提供了使用 Fabric8 Kubernetes Java 客户端 的实现。以 spring-cloud-starter-kubernetes-client 开头的Starter提供了使用 Kubernetes Java 客户端 的实现。

Starter Features
Fabric8 依赖
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-kubernetes-fabric8</artifactId>
</dependency>
Kubernetes Client 依赖
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-kubernetes-client</artifactId>
</dependency>

Discovery Client 实现,将服务名称(service name)解析为Kubernetes服务。

Fabric8 依赖
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-kubernetes-fabric8-config</artifactId>
</dependency>
Kubernetes Client 依赖
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-kubernetes-client-config</artifactId>
</dependency>

从Kubernetes ConfigMapSecret 加载应用 application properties。当 ConfigMap 或 Secret 发生变化时,重新加载 application properties。

Fabric8 依赖
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-kubernetes-fabric8-all</artifactId>
</dependency>
Kubernetes Client 依赖
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-kubernetes-client-all</artifactId>
</dependency>

所有 Spring Cloud Kubernetes 的特性。

3. 用于 Kubernetes 的 DiscoveryClient

该项目提供了 KubernetesDiscovery Client 的实现。这个客户端(Client)可以让你按名称查询Kubernetes端点(见 services)。服务通常由Kubernetes API服务器公开,是代表 httphttps 地址的端点的集合,客户端可以从作为pod运行的Spring Boot应用程序中访问这些端点。

这是你通过在你的项目中添加以下依赖而自动得到的东西。

基于 HTTP 的 DiscoveryClient

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-kubernetes-discoveryclient</artifactId>
</dependency>
spring-cloud-starter-kubernetes-discoveryclient 旨在与 Spring Cloud Kubernetes DiscoveryServer 一起使用。

Fabric8 Kubernetes 客户端

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-kubernetes-fabric8</artifactId>
</dependency>

Kubernetes Java 客户端

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-kubernetes-client</artifactId>
</dependency>

要启用 DiscoveryClient 的加载,请将 @EnableDiscoveryClient 添加到相应的配置或 application 类中,如下例所示。

@SpringBootApplication
@EnableDiscoveryClient
public class Application {
  public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
  }
}

然后,你可以通过自动注入将 client 注入你的代码中,如下例所示。

@Autowired
private DiscoveryClient discoveryClient;

你可以通过在 application.properties 中设置以下属性来选择从所有命名空间启用 DiscoveryClient

spring.cloud.kubernetes.discovery.all-namespaces=true

要想只从指定的命名空间发现服务和端点,你应该将属性 all-namespaces 设置为 false,并在 application.properties 中设置以下属性(在这个例子中命名空间是:ns1ns2)。

spring.cloud.kubernetes.discovery.namespaces[0]=ns1
spring.cloud.kubernetes.discovery.namespaces[1]=ns2

要发现未被 kubernetes api 服务器标记为 "ready" 的服务端点地址,可以在 application.properties 中设置以下属性(默认:false)。

spring.cloud.kubernetes.discovery.include-not-ready-addresses=true
这在为监控目的而发现服务时可能很有用,并且能够检查未准备好(not-ready)的服务实例的 /health 端点。

如果你的服务暴露了多个端口,你将需要指定 DiscoveryClient 应该使用哪个端口。 DiscoveryClient 将使用以下逻辑来选择端口。

  1. 如果该服务有一个标签(label) primary-port-name,它将使用标签值中指定的名称的端口。

  2. 如果没有标签,那么将使用 spring.cloud.kubernetes.discovery.primary-port-name 中指定的端口名称。

  3. 如果以上两项都没有指定,它将使用名为 https 的端口。

  4. 如果上述条件都不满足,它将使用名为 http 的端口。

  5. 作为最后的手段,它将选择端口列表中的第一个端口。

最后一个选项可能会导致非确定性的行为。请确保对你的服务和/或应用程序进行相应的配置。

默认情况下,所有的端口和它们的名字将被添加到 ServiceInstance 的元数据(metadata)中。

如果出于任何原因,你需要禁用 DiscoveryClient,你可以在 application.properties 中设置以下属性。

spring.cloud.kubernetes.discovery.enabled=false

一些Spring Cloud组件使用 DiscoveryClient,以获取本地服务实例的信息。要做到这一点,你需要将 Kubernetes 服务名称与 spring.application.name 属性对齐。

spring.application.name 对于在 Kubernetes 中为 application 注册的名称没有影响。

Spring Cloud Kubernetes还可以观察Kubernetes服务目录的变化,并相应地更新 DiscoveryClient 实现。我们所说的 "观察"(watch)是指每隔 spring.cloud.kubernetes.discovery.catalog-services-watch-delay 毫秒(默认为30000)发布一个心跳事件。该心跳事件将包含目标引用以及所有端点地址的命名空间(关于返回的确切细节,你可以看看 KubernetesCatalogWatch 内部)。这是一个实现细节,心跳事件的监听者不应该依赖这些细节。相反,他们应该通过 equals 方法查看两个后续心跳之间是否存在差异。我们会注意返回一个正确的实现,遵守 equals 契约。端点将以两种方式进行查询。

  • 所有命名空间 (通过 spring.cloud.kubernetes.discovery.all-namespaces=true 启用)

  • 特定的命名空间 (通过 spring.cloud.kubernetes.discovery.namespaces 启用), 例如:

spring:
  cloud:
    kubernetes:
      discovery:
        namespaces:
          - namespace-a
          - namespace-b

为了启用这个功能,你需要在你的 application 中的配置(configuration)类上添加 @EnableScheduling

默认情况下,我们使用 Endpoints(见 kubernetes.io/docs/concepts/services-networking/service/#endpoints ) API来查找服务的当前状态。但还有另一种方法,通过 EndpointSliceskubernetes.io/docs/concepts/services-networking/endpoint-slices/ )。这种支持可以通过一个属性启用:spring.cloud.kubernetes.discovery.use-endpoint-slices=true(默认为 false)。当然,你的集群也必须支持它。事实上,如果你启用了这个属性,但你的集群不支持它,我们将无法启动应用程序。如果你决定启用这种支持,你还需要适当地设置 Role/ClusterRole。例如:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: namespace-reader
rules:
  - apiGroups: ["discovery.k8s.io"]
    resources: ["endpointslices"]
    verbs: ["get", "list", "watch"]

4. Kubernetes 原生服务发现(service discovery)

Kubernetes 本身能够进行(服务端)服务发现(见: kubernetes.io/docs/concepts/services-networking/service/#discovering-services )。使用原生的kubernetes服务发现确保了与其他工具的兼容性,如Istio( istio.io ),这是一个能够进行负载均衡、断路器、故障转移等的 service mesh。

然后,调用者服务只需引用特定Kubernetes集群中可解析的名称。一个简单的实现可以使用一个指向完整域名(FQDN)的 spring RestTemplate,例如 {service-name}.{namespace}.svc.{cluster}.local:{service-port}

此外,你还可以将 Hystrix 用于:

  • 通过在 spring boot application 中注解 @EnableCircuitBreaker,在调用方实现断路器。

  • Fallback 功能,通过用 @HystrixCommand(fallbackMethod=…​) 注解相应的方法。

5. Kubernetes PropertySource 的实现

配置Spring Boot应用程序的最常见方法是创建 application.propertiesapplication.yamlapplication-profile.propertiesapplication-profile.yaml 文件,其中包含为你的应用程序或Spring Boot Starter 提供定制值的键值对。你可以通过指定系统属性(system properties)或环境变量来覆盖这些属性。

要启用这一功能,你需要在应用程序的配置属性中设置 spring.config.import=kubernetes:目前,你不能使用 spring.config.import 指定要加载的 ConfigMapSecret,默认情况下,Spring Cloud Kubernetes 将根据 spring.application.name 属性加载 ConfigMap/Secret。如果没有设置 spring.application.name,它将加载一个带有 application 名称的 ConfigMap/Secret

如果你想在启动阶段加载 Kubernetes PropertySource,就像3.0.x版本之前那样,你可以将 spring-cloud-starter-bootstrap 添加到你的应用程序的 classpath 中,或者将 spring.cloud.bootstrap.enabled=true 作为一个环境变量。

5.1. 使用 ConfigMap PropertySource

Kubernetes提供了一种名为 ConfigMap 的资源,以键值对或嵌入式 application.propertiesapplication.yaml 文件的形式将参数外部化,以传递给你的应用程序。Spring Cloud Kubernetes Config 项目使Kubernetes ConfigMap 实例在应用程序启动期间可用,并在观察到的 ConfigMap 实例上检测到变化时触发Bean或Spring上下文的热重载。

下面的一切解释主要是指使用 ConfigMap 的例子,但对 Secret 来说也是如此,即:两者都支持每一个功能。

默认行为是基于 Kubernetes ConfigMap 创建 Fabric8ConfigMapPropertySource(或 KubernetesClientConfigMapPropertySource),其 metadata.name 值为Spring应用程序的名称(由其 spring.application.name 属性定义)或在 application.properties 文件中定义的自定义名称,key如下:spring.cloud.kubernetes.config.name

然而,更高级的配置是可能的,你可以使用多个 ConfigMap 实例。spring.cloud.kubernetes.config.sources 列表使这成为可能。例如,你可以定义以下 ConfigMap 实例。

spring:
  application:
    name: cloud-k8s-app
  cloud:
    kubernetes:
      config:
        name: default-name
        namespace: default-namespace
        sources:
         # Spring Cloud Kubernetes looks up a ConfigMap named c1 in namespace default-namespace
         - name: c1
         # Spring Cloud Kubernetes looks up a ConfigMap named default-name in whatever namespace n2
         - namespace: n2
         # Spring Cloud Kubernetes looks up a ConfigMap named c3 in namespace n3
         - namespace: n3
           name: c3

在前面的例子中,如果 spring.cloud.kubernetes.config.namespace 没有被设置,名为 c1ConfigMap 将在应用程序运行的 namespace 中被查找。请参阅 Namespace 解析,以更好地了解应用程序的 namespace 是如何解析的。

找到的任何匹配的 ConfigMap 将被处理如下。

  • 应用个别配置属性。

  • 将以 spring.application.name 的值命名的任何属性的内容作为 yaml(或 properties)应用(如果它不存在,则通过 application.yaml/properties)。

  • 将上述名称的内容作为 properties file 应用 + 每个活动的配置文件(active profile)。

一个例子应该更有意义。让我们假设 spring.application.name=my-app,并且我们有一个叫 k8s 的活动配置文件(active profile)。对于下面的配置。

kind: ConfigMap
apiVersion: v1
metadata:
  name: my-app
data:
  my-app.yaml: |-
    ...
  my-app-k8s.yaml: |-
    ..
  my-app-dev.yaml: |-
   ..
  someProp: someValue

这些就是我们最终要加载的东西。

  • my-app.yaml 被视为一个文件。

  • my-app-k8s.yaml 被视为一个文件。

  • my-app-dev.yaml 忽略,因为 "dev" 不是一个活跃的配置文件。

  • someProp: someValue 普通属性。

上述流程的唯一例外是,当 ConfigMap 包含一个表明文件是 YAML 或 properties file 的单一KEY时。在这种情况下,key的名称不必是 application.yamlapplication.properties(它可以是任何东西),而且属性的值也被正确处理。这个特点有助于通过使用类似以下的东西来创建 ConfigMap 的用例。

kubectl create configmap game-config --from-file=/path/to/app-config.yaml

假设我们有一个名为 Demo 的 Spring Boot 应用程序,它使用以下属性来读取其线程池配置。

  • pool.size.core

  • pool.size.maximum

这可以外化为 yaml 格式的 config map,如下所示。

kind: ConfigMap
apiVersion: v1
metadata:
  name: demo
data:
  pool.size.core: 1
  pool.size.max: 16

单独的 properties 在大多数情况下工作得很好。然而,有时,嵌入的 yaml 更方便。在这种情况下,我们使用一个名为 application.yaml 的单一属性来嵌入我们的 yaml,如下所示。

kind: ConfigMap
apiVersion: v1
metadata:
  name: demo
data:
  application.yaml: |-
    pool:
      size:
        core: 1
        max:16

下面的例子也可以。

kind: ConfigMap
apiVersion: v1
metadata:
  name: demo
data:
  custom-name.yaml: |-
    pool:
      size:
        core: 1
        max:16

例如,你也可以定义根据标签来进行搜索。

spring:
  application:
    name: labeled-configmap-with-prefix
  cloud:
    kubernetes:
      config:
        enableApi: true
        useNameAsPrefix: true
        namespace: spring-k8s
        sources:
          - labels:
              letter: a

这将搜索命名空间 spring-k8s 中每一个标签为 {letter : a} 的 configmap。这里需要注意的是,与按名称读取 configmap 不同,这可能导致读取多个configmap。像往常一样,同样的功能也支持 secret。

你还可以根据读取 ConfigMap 时合并在一起的活动配置文件,对Spring Boot应用程序进行不同的配置。你可以通过使用 application.propertiesapplication.yaml 属性为不同的 profiles 提供不同的属性值,指定特定于 profile 的值,每一个都在它们自己的文档中(用 --- 序列表示),如下所示。

kind: ConfigMap
apiVersion: v1
metadata:
  name: demo
data:
  application.yml: |-
    greeting:
      message: Say Hello to the World
    farewell:
      message: Say Goodbye
    ---
    spring:
      profiles: development
    greeting:
      message: Say Hello to the Developers
    farewell:
      message: Say Goodbye to the Developers
    ---
    spring:
      profiles: production
    greeting:
      message: Say Hello to the Ops

在前面的案例中,用 development profile 加载到你的Spring应用程序的配置如下。

  greeting:
    message: Say Hello to the Developers
  farewell:
    message: Say Goodbye to the Developers

然而,如果 production profile 处于活动状态,配置就会变成:

  greeting:
    message: Say Hello to the Ops
  farewell:
    message: Say Goodbye

如果两个配置文件都处于活动状态,在 ConfigMap 中最后出现的属性会覆盖前面的任何值。

另一个选择是为每个配置文件创建一个不同的 config map,spring boot会根据活动的配置文件(active profiles)自动获取它。

kind: ConfigMap
apiVersion: v1
metadata:
  name: demo
data:
  application.yml: |-
    greeting:
      message: Say Hello to the World
    farewell:
      message: Say Goodbye
kind: ConfigMap
apiVersion: v1
metadata:
  name: demo-development
data:
  application.yml: |-
    spring:
      profiles: development
    greeting:
      message: Say Hello to the Developers
    farewell:
      message: Say Goodbye to the Developers
kind: ConfigMap
apiVersion: v1
metadata:
  name: demo-production
data:
  application.yml: |-
    spring:
      profiles: production
    greeting:
      message: Say Hello to the Ops
    farewell:
      message: Say Goodbye

要告诉Spring Boot应该启用哪个 profile,请参阅 Spring Boot文档。在部署到Kubernetes时,激活特定配置文件的一个选择是用一个环境变量启动你的Spring Boot应用程序,你可以在容器规范的 PodSpec 中定义这个变量。部署资源文件,如下所示。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deployment-name
  labels:
    app: deployment-name
spec:
  replicas: 1
  selector:
    matchLabels:
      app: deployment-name
  template:
    metadata:
      labels:
        app: deployment-name
    spec:
        containers:
        - name: container-name
          image: your-image
          env:
          - name: SPRING_PROFILES_ACTIVE
            value: "development"

你可能会遇到这样的情况:有多个 config map 有相同的属性名称。比如说:

kind: ConfigMap
apiVersion: v1
metadata:
  name: config-map-one
data:
  application.yml: |-
    greeting:
      message: Say Hello from one

kind: ConfigMap
apiVersion: v1
metadata:
  name: config-map-two
data:
  application.yml: |-
    greeting:
      message: Say Hello from two

根据你在 bootstrap.yaml | properties 中放置这些东西的顺序,你可能会得到一个意外的结果(最后一个 config map 获胜)。比如说。

spring:
  application:
    name: cloud-k8s-app
  cloud:
    kubernetes:
      config:
        namespace: default-namespace
        sources:
         - name: config-map-two
         - name: config-map-one

将导致属性 greetings.messageSay Hello from one

有一种方法可以通过指定 useNameAsPrefix 来改变这种默认配置。比如说。

spring:
  application:
    name: with-prefix
  cloud:
    kubernetes:
      config:
        useNameAsPrefix: true
        namespace: default-namespace
        sources:
          - name: config-map-one
            useNameAsPrefix: false
          - name: config-map-two

这样的配置将导致两个属性被生成。

  • greetings.message 等于 Say Hello from one

  • config-map-two.greetings.message 等于 Say Hello from two

注意 spring.cloud.kubernetes.config.useNameAsPrefix 的优先级低于 spring.cloud.kubernetes.config.sources.useNameAsPrefix。这允许你为所有源设置一个 "default" 策略,同时只允许覆盖少数源。

如果使用 config map name 不是一个选项,你可以指定一个不同的策略,叫做: explicitPrefix。因为这是你选择的显式前缀,它只能提供给 sources 级。同时,它比 useNameAsPrefix 有更高的优先级。让我们假设我们有第三个 config map,有这些条目。

kind: ConfigMap
apiVersion: v1
metadata:
  name: config-map-three
data:
  application.yml: |-
    greeting:
      message: Say Hello from three

像下面这样的配置:

spring:
  application:
    name: with-prefix
  cloud:
    kubernetes:
      config:
        useNameAsPrefix: true
        namespace: default-namespace
        sources:
          - name: config-map-one
            useNameAsPrefix: false
          - name: config-map-two
            explicitPrefix: two
          - name: config-map-three

将导致三个 properties 被生成:

  • greetings.message 等于 Say Hello from one.

  • two.greetings.message 等于 Say Hello from two.

  • config-map-three.greetings.message 等于 Say Hello from three.

你为 configmap 配置前缀的方式相同,你也可以为 secret 配置前缀;对于基于名称的 secret 和基于标签(label)的 secret 都是如此。比如说。

spring:
  application:
    name: prefix-based-secrets
  cloud:
    kubernetes:
      secrets:
        enableApi: true
        useNameAsPrefix: true
        namespace: spring-k8s
        sources:
          - labels:
              letter: a
            useNameAsPrefix: false
          - labels:
              letter: b
            explicitPrefix: two
          - labels:
              letter: c
          - labels:
              letter: d
            useNameAsPrefix: true
          - name: my-secret

生成属性源(source)时适用的处理规则与 config map 相同。唯一不同的是,按标签查找 secret 可能意味着我们会找到一个以上的源。在这种情况下,前缀(如果通过 useNameAsPrefix 指定)将是为这些特定标签找到的所有 secret 的名称。

还有一件事要记住,我们支持每个 sourceprefix,而不是每个secret。解释这一点的最简单方法是通过一个例子。

spring:
  application:
    name: prefix-based-secrets
  cloud:
    kubernetes:
      secrets:
        enableApi: true
        useNameAsPrefix: true
        namespace: spring-k8s
        sources:
          - labels:
              color: blue
            useNameAsPrefix: true

假设与这样一个标签相匹配的查询将提供两个 secret 作为结果:secret-asecret-b。这两个secret都有相同的属性名称:color=sea-bluecolor=ocean-blue。它没有定义哪个 color 将最终成为 property sources 的一部分,但它的前缀将是 secret-a.secret-b(自然地串联排序,secret 的名称)。

如果你需要更细化的结果,添加更多的标签(label)来独特地识别 secret 将是一个选择。

默认情况下,除了读取 sources 配置中指定的config map外,Spring还将尝试从 "profile aware" sources 读取所有属性。解释这一点的最简单方法是通过一个例子。假设你的应用程序启用了一个名为 "dev 的 profile,并且你有一个类似下面的配置。

spring:
  application:
    name: spring-k8s
  cloud:
    kubernetes:
      config:
        namespace: default-namespace
        sources:
          - name: config-map-one

除了读取 config-map-one,Spring还将尝试读取 config-map-one-dev;以这种特定的顺序。每个活动的配置文件(active profile)都会生成这样一个 profile aware config map。

虽然你的应用程序不应该受到这样的 config map 的影响,但如果需要,可以禁用它。

spring:
  application:
    name: spring-k8s
  cloud:
    kubernetes:
      config:
        includeProfileSpecificSources: false
        namespace: default-namespace
        sources:
          - name: config-map-one
            includeProfileSpecificSources: false

请注意,就像以前一样,你可以在两个层面上指定这个属性:为所有的config map或为个别的config map;后者的优先级更高。

你应该检查安全配置(security configuration)部分。要从 pod 内部访问config map,你需要有正确的Kubernetes服务账户、角色和角色绑定。

使用 ConfigMap 实例的另一个选择是通过运行Spring Cloud Kubernetes应用程序并让Spring Cloud Kubernetes从文件系统中读取它们来将它们挂载到Pod中。这种行为是由 spring.cloud.kubernetes.config.paths 属性控制的。你可以用它来补充或代替前面描述的机制。你可以在 spring.cloud.kubernetes.config.paths 中通过使用 , 来指定多个(精确)文件路径。

你必须提供每个 property file 的完整准确路径,因为目录没有被递归解析。
如果你使用 spring.cloud.kubernetes.config.pathsspring.cloud.kubernetes.secrets.path,自动重载功能将不起作用。你将需要向 /actuator/refresh 端点发出 POST 请求,或者重新启动/重新部署应用程序。

在某些情况下,您的应用程序可能无法使用Kubernetes API加载某些 ConfigMaps。如果你想让你的应用程序在这种情况下启动过程失败,你可以设置 spring.cloud.kubernetes.config.fail-fast=true,使应用程序启动时出现异常。

你也可以让你的应用程序在失败时重试加载 ConfigMap 属性源。首先,你需要设置 spring.cloud.kubernetes.config.fail-fast=true。然后你需要将 spring-retryspring-boot-starter-aop 添加到你的classpath。你可以通过设置 spring.cloud.kubernetes.config.retry.* 属性来配置重试属性,如最大尝试次数、初始间隔、倍数、最大间隔等 backoff 选项。

如果你因为某些原因在classpath上已经有 spring-retryspring-boot-starter-aop,并且想启用 fail-fast,但不希望启用重试;你可以通过设置 spring.cloud.kubernetes.config.retry.enabled=false 来禁用 ConfigMap PropertySources 的重试。
Table 1. 属性:
属性 类型 默认 说明

spring.cloud.kubernetes.config.enabled

Boolean

true

启用 ConfigMaps PropertySource

spring.cloud.kubernetes.config.name

String

${spring.application.name}

设置 ConfigMap 的名称以进行查询。

spring.cloud.kubernetes.config.namespace

String

Client namespace

设置查询的 Kubernetes namespac

spring.cloud.kubernetes.config.paths

List

null

设置 ConfigMap 实例的安装路径。

spring.cloud.kubernetes.config.enableApi

Boolean

true

启用或禁用通过API消费 ConfigMap 实例的功能

spring.cloud.kubernetes.config.fail-fast

Boolean

false

当加载 ConfigMap 时发生错误,可启用或禁用应用程序启动失败。

spring.cloud.kubernetes.config.retry.enabled

Boolean

true

启用或禁用 config retry。

spring.cloud.kubernetes.config.retry.initial-interval

Long

1000

初始重试时间间隔,以毫秒为单位。

spring.cloud.kubernetes.config.retry.max-attempts

Integer

6

最大的尝试次数。

spring.cloud.kubernetes.config.retry.max-interval

Long

2000

backoff的最大时间间隔。

spring.cloud.kubernetes.config.retry.multiplier

Double

1.1

下一个区间的倍数。

5.2. Secret PropertySource

Kubernetes有 Secrets 的概念,用于存储敏感数据,如密码、OAuth令牌等。该项目提供了与 Secrets 的集成,使Spring Boot应用程序可以访问Secrets。你可以通过设置 spring.cloud.kubernetes.secrets.enabled 属性明确地启用或禁用该功能。

启用后,Fabric8SecretsPropertySource 会从以下源查找 Kubernetes 的 Secrets

  1. 递归地读取 secrets 挂载。

  2. 以应用程序命名(如 spring.application.name 所定义)。

  3. 匹配某些标签

Note:

默认情况下,由于安全原因,通过API消费Secrets(上面第2和第3点)是不启用的。在secrets上的权限 "list" 允许客户端检查指定命名空间中的secrets值。此外,我们建议容器通过挂载的卷来共享 secrets。

如果你启用了通过API消费Secrets的功能,我们建议你通过使用授权策略(如RBAC)来限制对Secrets的访问。有关通过API消费Secrets的风险和最佳做法的更多信息,请参考 本文档

如果发现 secrets ,它们的数据就会被提供给应用程序。

假设我们有一个名为 demo 的spring boot应用程序,它使用 properties 来读取其数据库配置。我们可以通过使用以下命令创建一个 Kubernetes secret。

kubectl create secret generic db-secret --from-literal=username=user --from-literal=password=p455w0rd

前面的命令将创建以下secret(你可以通过使用 kubectl get secrets db-secret -o yaml 查看)。

apiVersion: v1
data:
  password: cDQ1NXcwcmQ=
  username: dXNlcg==
kind: Secret
metadata:
  creationTimestamp: 2017-07-04T09:15:57Z
  name: db-secret
  namespace: default
  resourceVersion: "357496"
  selfLink: /api/v1/namespaces/default/secrets/db-secret
  uid: 63c89263-6099-11e7-b3da-76d6186905a8
type: Opaque

请注意,这些数据包含 create 命令所提供的字词的Base64编码版本。

然后,你的应用程序可以使用这个secret — 例如,通过将 secret 的值导出为环境变量。

apiVersion: v1
kind: Deployment
metadata:
  name: ${project.artifactId}
spec:
   template:
     spec:
       containers:
         - env:
            - name: DB_USERNAME
              valueFrom:
                 secretKeyRef:
                   name: db-secret
                   key: username
            - name: DB_PASSWORD
              valueFrom:
                 secretKeyRef:
                   name: db-secret
                   key: password

你可以通过多种方式选择要消费的Secrets 。

  1. 通过列出 secrets 被映射的目录。

    -Dspring.cloud.kubernetes.secrets.paths=/etc/secrets/db-secret,etc/secrets/postgresql

    如果你把所有的 secrets 都映射到一个共同的 root上,你可以像这样设置它们。

    -Dspring.cloud.kubernetes.secrets.paths=/etc/secrets
  2. 通过设置一个命名的secret。

    -Dspring.cloud.kubernetes.secrets.name=db-secret
  3. 通过定义一个标签(label)列表。

    -Dspring.cloud.kubernetes.secrets.labels.broker=activemq
    -Dspring.cloud.kubernetes.secrets.labels.db=postgresql

ConfigMap 的情况一样,更高级的配置也是可能的,你可以使用多个 Secret 实例。spring.cloud.kubernetes.secrets.sources 列表使这成为可能。例如,你可以定义以下 Secret 实例。

spring:
  application:
    name: cloud-k8s-app
  cloud:
    kubernetes:
      secrets:
        name: default-name
        namespace: default-namespace
        sources:
         # Spring Cloud Kubernetes looks up a Secret named s1 in namespace default-namespace
         - name: s1
         # Spring Cloud Kubernetes looks up a Secret named default-name in namespace n2
         - namespace: n2
         # Spring Cloud Kubernetes looks up a Secret named s3 in namespace n3
         - namespace: n3
           name: s3

在前面的例子中,如果 spring.cloud.kubernetes.secrets.namespace 没有被设置,名为 s1Secret 将在应用程序运行的命名空间中被查找。请参阅 命名空间解析,以更好地了解应用程序的命名空间是如何解析的。

ConfigMaps 类似,如果你希望你的应用程序在无法加载 Secrets 源时无法启动,你可以设置 spring.cloud.kubernetes.secrets.fail-fast=true

也可以像 ConfigMaps 一样为 Secret 源启用重试。与 ConfigMap 源一样,首先你需要设置 spring.cloud.kubernetes.secrets.fail-fast=true。然后你需要在classpath中添加 spring-retryspring-boot-starter-aop。Secret 源的重试行为可以通过设置 spring.cloud.kubernetes.secrets.retry.* 属性进行配置。

如果你因为某些原因已经在 classpath 上有 spring-retryspring-boot-starter-aop,并且想启用 fail-fast,但不希望启用重试;你可以通过设置 spring.cloud.kubernetes.secrets.retry.enabled=false 来禁用 Secrets PropertySources 的重试。
Table 2. 属性:
属性 类型 默认 说明

spring.cloud.kubernetes.secrets.enabled

Boolean

true

启用 Secrets PropertySource

spring.cloud.kubernetes.secrets.name

String

${spring.application.name}

设置要查询的 secret 的名称

spring.cloud.kubernetes.secrets.namespace

String

Client namespace

设置Kubernetes namespace,以便在其中查找

spring.cloud.kubernetes.secrets.labels

Map

null

设置用于查询 secrets 的标签(label)

spring.cloud.kubernetes.secrets.paths

List

null

设置安装 secrets 的路径(例子1)。

spring.cloud.kubernetes.secrets.enableApi

Boolean

false

启用或禁用通过API消费 secrets 的功能(例子2和3)。

spring.cloud.kubernetes.secrets.fail-fast

Boolean

false

启用或禁用在加载 Secret 时发生错误而导致应用程序启动失败的情况。

spring.cloud.kubernetes.secrets.retry.enabled

Boolean

true

启用或禁用secrets retry。

spring.cloud.kubernetes.secrets.retry.initial-interval

Long

1000

初始重试时间间隔,以毫秒为单位。

spring.cloud.kubernetes.secrets.retry.max-attempts

Integer

6

最大的尝试次数。

spring.cloud.kubernetes.secrets.retry.max-interval

Long

2000

backoff 的最大时间间隔。

spring.cloud.kubernetes.secrets.retry.multiplier

Double

1.1

下一个区间的倍数。

Notes:

  • spring.cloud.kubernetes.secrets.labels 属性的行为与 基于Map的绑定 所定义的一样。

  • spring.cloud.kubernetes.secrets.paths 属性的行为与 基于集合(Collection)的绑定 所定义的相同。

  • 出于安全原因,通过API访问 secrets 可能会受到限制。首选的方法是将 secrets 挂载到Pod上。

你可以在 spring-boot-camel-config 找到一个使用 secrets 的应用程序的例子(尽管它还没有被更新到使用新的 spring-cloud-kubernetes 项目)。

5.3. 命名空间解析

寻找一个应用程序的命名空间是在尽力而为的基础上进行的。为了找到它,我们要反复进行一些步骤。最简单和最常见的步骤是在适当的配置中指定它,例如。

spring:
  application:
    name: app
  cloud:
    kubernetes:
      secrets:
        name: secret
        namespace: default
        sources:
         # Spring Cloud Kubernetes looks up a Secret named 'a' in namespace 'default'
         - name: a
         # Spring Cloud Kubernetes looks up a Secret named 'secret' in namespace 'b'
         - namespace: b
         # Spring Cloud Kubernetes looks up a Secret named 'd' in namespace 'c'
         - namespace: c
           name: d

记住,对 config map 也可以这样做。如果没有指定这样的命名空间,它将被读取(按照这个顺序)。

  1. spring.cloud.kubernetes.client.namespace 属性。

  2. 从驻留在 spring.cloud.kubernetes.client.serviceAccountNamespacePath 文件中的一个字符串。

  3. 从驻留在 /var/run/secrets/kubernetes.io/serviceaccount/namespace 文件(kubernetes默认命名空间路径)中的一个字符串。

  4. 从指定的客户端方法调用(例如 fabric8 的 : KubernetesClient::getNamespace),如果客户端提供这种方法。反过来,这可以通过环境属性来配置。例如,fabric8客户端可以通过 "KUBERNETES_NAMESPACE" 属性进行配置;具体细节请查阅客户端文档。

如果不能从上述步骤中找到一个命名空间,将抛出异常。

5.4. PropertySource 重新加载

该功能在2020.0版本中已被弃用。请参阅 Spring Cloud Kubernetes Configuration Watcher controller,以获取实现相同功能的替代方法。

一些应用程序可能需要检测外部属性源(property sources)上的变化,并更新其内部状态以反映新的配置。Spring Cloud Kubernetes的重载功能能够在相关的 ConfigMapSecret 发生变化时触发应用程序的重载。

默认情况下,该功能是禁用的。你可以通过使用 spring.cloud.kubernetes.reload.enabled=true 配置属性(例如,在 application.properties 文件中)来启用它。请注意,这将只启用对 configmap 的监控(即:spring.cloud.kubernetes.reload.monitoring-config-maps 将被设置为 true)。如果你想启用对 secrets 的监控,必须通过:spring.cloud.kubernetes.reload.monitoring-secrets=true 明确地完成。

支持以下级别的重载(通过设置 spring.cloud.kubernetes.reload.strategy 属性)。

  • refresh (默认):只有用 @ConfigurationProperties@RefreshScope 注解的配置bean被重新加载。这个重载级别利用了Spring Cloud Context 的刷新功能。

  • restart_context:整个 Spring ApplicationContext 会被优雅地重新启动。bean类将以新的配置重新创建。为了使重启上下文功能正常工作,你必须启用并公开 actuator 的 restart 端点

management:
  endpoint:
    restart:
      enabled: true
  endpoints:
    web:
      exposure:
        include: restart
  • shutdown:Spring ApplicationContext 被关闭以激活容器的重启。当你使用这个级别时,请确保所有非daemon线程的生命周期都与 ApplicationContext 绑定,并确保 replication controller 或 replica set 被配置为重启 pod。

假设在默认设置下启用了重载功能(refresh 模式),当 config map 发生变化时,会刷新以下 bean 类。

@Configuration
@ConfigurationProperties(prefix = "bean")
public class MyConfig {

    private String message = "a message that can be changed live";

    // getter and setters

}

为了看到变化的有效发生,你可以创建另一个Bean,定期打印消息,如下所示。

@Component
public class MyBean {

    @Autowired
    private MyConfig config;

    @Scheduled(fixedDelay = 5000)
    public void hello() {
        System.out.println("The message is: " + config.getMessage());
    }
}

你可以通过使用 ConfigMap 来改变应用程序打印的信息,如下所示。

apiVersion: v1
kind: ConfigMap
metadata:
  name: reload-example
data:
  application.properties: |-
    bean.message=Hello World!

对与pod相关的 ConfigMap 中名为 bean.message 的属性的任何改变都会反映在输出中。更一般地说,与以 @ConfigurationProperties 注解的 prefix 字段所定义的值为前缀的属性相关的变化会被检测到并反映在应用程序中。本章前面解释了 ConfigMap 与 pod 关联 的问题。

完整的示例可在 spring-cloud-kubernetes-reload-example 中找到。

重载功能支持两种操作模式。

  • Event (默认): 通过使用Kubernetes API(web socket)观察config map或secrets的变化。任何事件都会产生对配置的重新检查,如果有变化,会重新加载。为了监听config map的变化,service account 上的 view 角色是必需的。secrets 需要一个更高级别的角色(如 edit)(默认情况下,secrets 不被监控)。

  • Polling: 定期从 config map 和 secrets 中重新创建配置,以查看是否有变化。你可以通过使用 spring.cloud.kubernetes.reload.period 属性来配置轮询周期,默认为 15 秒。它要求与被监控的属性源的角色相同。这意味着,例如,在文件挂载的 secret 源上使用轮询不需要特别的权限。

5.5. 重新加载命名空间和标签过滤

默认情况下,使用 命名空间解析 中概述的步骤选择的命名空间将被用来监听 configmap 和 secrets 的变化。 也就是说:如果你没有告诉reload要监听哪些命名空间和 configmap/secrets,它将监听来自命名空间的所有configmap /secrets,这些命名空间将使用上述算法进行计算。

另一方面,你可以定义一个更细化的方法。例如,你可以指定将被监控的变化的命名空间。

spring:
  application:
    name: event-reload
  cloud:
    kubernetes:
      reload:
        enabled: true
        strategy: shutdown
        mode: event
        namespaces:
          - my-namespace

这样的配置将使应用程序只观察 my-namespace 中的变化。请注意,这将监视所有的 configmap/secrets(取决于你启用哪一个)。如果你想要一个更精细的方法,你可以启用 "label-filtering"。首先,我们需要通过以下方式启用这种支持: enable-reload-filtering: true

spring:
  application:
    name: event-reload
  cloud:
    kubernetes:
      reload:
        enabled: true
        strategy: shutdown
        mode: event
        namespaces:
          - my-namespaces
        monitoring-config-maps: true
        enable-reload-filtering: true

这样做的目的是监视只有 spring.cloud.kubernetes.config.informer.enabled: true 标签的 configmap/secrets。

Table 3. 属性:
属性 类型 默认 说明

spring.cloud.kubernetes.reload.enabled

Boolean

false

启用对 property sources 的监控和配置重载

spring.cloud.kubernetes.reload.monitoring-config-maps

Boolean

true

允许监控config map中的变化

spring.cloud.kubernetes.reload.monitoring-secrets

Boolean

false

允许监控secrets的变化

spring.cloud.kubernetes.reload.strategy

Enum

refresh

触发重载时使用的策略(refresh, restart_contextshutdown)。

spring.cloud.kubernetes.reload.mode

Enum

event

指定如何监听 property sources 的变化(eventpolling)。

spring.cloud.kubernetes.reload.period

Duration

15s

使用 polling 策略时,验证变化的周期。

spring.cloud.kubernetes.reload.namespaces

String[]

要监控变化的 namespaces

spring.cloud.kubernetes.reload.enable-reload-filtering

String

启用了重新加载功能的标签过滤功能。

Notes:

  • 你不应该在config map或secrets中使用 spring.cloud.kubernetes.reload 下的属性。在运行时改变这些属性可能会导致意外的结果。

  • 当你使用 refresh 级别时,删除一个属性或整个config map并不能恢复bean的原始状态。

6. Kubernetes 生态系统的感知

无论你的应用程序是否在Kubernetes内运行,本指南前面描述的所有功能都同样有效。这对开发和故障排除真的很有帮助。从开发的角度来看,这可以让你启动你的Spring Boot应用,并调试属于这个项目的一个模块。你不需要将其部署在Kubernetes中,因为该项目的代码依赖于 Fabric8 Kubernetes Java客户端,它是一个fluent DSL,可以通过使用 http 协议与Kubernetes服务器的REST API进行通信。

Kubernetes 感知是基于Spring Boot API的,特别是基于 ConditionalOnCloudPlatform。该属性将自动检测你的应用程序当前是否部署在kubernetes中。可以通过 spring.main.cloud-platform 来覆盖该设置。

例如,如果你需要测试一些功能,但不想部署到一个集群,只需设置:spring.main.cloud-platform=KUBERNETES。这将使 spring-cloud-kubernetes 像部署在一个真正的集群中一样行动。

如果你的 classpath 上有 spring-cloud-starter-bootstrap 或者正在设置 spring.cloud.bootstrap.enabled=true,那么你将不得不在 bootstrap.{properties|yml} 中设置 spring.main.cloud-platform(或特定的配置文件)。此外,请注意这些属性:spring.cloud.kubernetes.config.enabledspring.cloud.kubernetes.secrets.enabled 只有在你的 classpath 上有 spring-cloud-starter-bootstrap 或者设置 spring.cloud.bootstrap.enabled=true 时,在 bootstrap.{properties|yml} 中的设置才会生效。

6.1. 3.0.x 中的破坏性变化

在3.0.x之前的Spring Cloud Kubernetes版本中,Kubernetes 感知是通过 spring.cloud.kubernetes.enabled 属性实现的。该属性已被删除,不受支持。相反,我们使用Spring Boot API ConditionalOnCloudPlatform。如果需要明确启用或禁用这一感应,请使用 spring.main.cloud-platform=NONE/KUBERNETES

6.2. Kubernetes Profile 的自动配置

当应用程序在Kubernetes内以pod形式运行时,一个名为 kubernetes 的 Spring profile 会自动被激活。这让你可以定制配置,定义Spring Boot应用在 Kubernetes 平台内部署时应用的bean(例如,不同的开发和生产配置)。

6.3. Istio 感知

当你在应用程序的 classpath 中包含 spring-cloud-kubernetes-fabric8-istio 模块时,一个新的 profile 就会被添加到应用程序中,前提是该应用程序是在安装了 Istio 的Kubernetes集群中运行。然后你可以在你的Bean和 @Configuration 类中使用spring @Profile("istio") 注解。

Istio 感知模块使用 me.snowdrop:istio-client 与 Istio API 交互,让我们发现流量规则、断路器等,使我们的Spring Boot应用能够轻松地消费这些数据,根据环境动态地配置自己。

7. Pod 健康指标

Spring Boot使用 HealthIndicator 来暴露应用程序的健康信息。这使得它在向用户公开与健康有关的信息方面非常有用,并使它很适合作为 readiness 探针 使用。

Kubernetes健康指标(是核心模块的一部分)暴露了以下信息。

  • Pod名称、IP地址、命名空间、服务账户、节点名称及其IP地址。

  • 表示Spring Boot应用程序是在Kubernetes内部还是外部的一个flag。

你可以通过在 application.[properties | yaml] 中设置 management.health.kubernetes.enabledfalse 来禁用这个 HealthContributor

8. Info Contributor

Spring Cloud Kubernetes 包括一个 InfoContributor,它将Pod信息添加到Spring Boot的 /info Acturator端点。

你可以通过在 application.[properties | yaml] 中设置 management.info.kubernetes.enabledfalse 来禁用这个 InfoContributor

9. Leader 选举

Spring Cloud Kubernetes Leader 选举机制使用Kubernetes ConfigMap 实现了Spring Integration 的 Leader 选举API。

多个应用程序实例竞争领导权(leadership),但领导权只授予一个。当被授予领导权时,leader 应用程序会收到一个带有 leadership ContextOnGrantedEvent application event。应用程序周期性地尝试获得领导权,领导权授予第一个调用者。一个leader将一直是一个leader,直到它被从集群中移除,或者它放弃了它的领导权。当领导权被移除时,前一个 leader 会收到 OnRevokedEvent application event。在移除之后,集群中的任何实例都可以成为新的 leader,包括旧的 leader。

要在你的项目中包含它,请添加以下依赖。

Fabric8 Leader 实现

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-kubernetes-fabric8-leader</artifactId>
</dependency>

要指定用于 leader 选举的 configmap 的名称,请使用以下属性。

spring.cloud.kubernetes.leader.config-map-name=leader

10. 适用于 Kubernetes 的 LoadBalancer

该项目包括Spring Cloud Load Balancer,用于基于 Kubernetes Endpoints 的负载均衡,并提供了基于Kubernetes Service的负载均衡器的实现。要将其纳入你的项目,请添加以下依赖。

Fabric8 实现

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-kubernetes-fabric8-loadbalancer</artifactId>
</dependency>

Kubernetes Java Client 实现

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-kubernetes-client-loadbalancer</artifactId>
</dependency>

要启用基于 Kubernetes Service name 的负载均衡,请使用以下属性。然后负载均衡器将尝试使用地址调用应用程序,例如 service-a.default.svc.cluster.local

spring.cloud.kubernetes.loadbalancer.mode=SERVICE

要启用所有命名空间的负载均衡,请使用以下属性。遵守 spring-cloud-kubernetes-discovery 模块的属性。

spring.cloud.kubernetes.discovery.all-namespaces=true

如果一个服务需要通过HTTPS访问,你需要在你的服务定义中添加一个标签(add)或注解(annotation),名称为 secured,值为 true,然后负载均衡器将使用HTTPS向该服务发出请求。

11. Kubernetes 内部的安全配置

11.1. 命名空间(Namespace)

本项目中提供的大多数组件都需要知道命名空间。对于Kubernetes(1.3以上),命名空间作为 service account secret 的一部分提供给pod,并由客户端自动检测。对于早期版本,它需要作为环境变量指定给pod。做到这一点的快速方法如下。

      env:
      - name: "KUBERNETES_NAMESPACE"
        valueFrom:
          fieldRef:
            fieldPath: "metadata.namespace"

11.2. Service Account

对于支持集群内更精细的基于角色的访问的Kubernetes发行版,你需要确保使用 spring-cloud-kubernetes 运行的pod能够访问 Kubernetes API。对于你分配给deployment或pod的任何服务账户(service account),你需要确保它们有正确的角色。

根据要求,你需要 getlistwatch 以下资源的许可。

Table 4. Kubernetes 资源权限
依赖 资源

spring-cloud-starter-kubernetes-fabric8

pods, services, endpoints

spring-cloud-starter-kubernetes-fabric8-config

configmaps, secrets

spring-cloud-starter-kubernetes-client

pods, services, endpoints

spring-cloud-starter-kubernetes-client-config

configmaps, secrets

出于开发的目的,你可以在你的 default 服务账户中添加 cluster-reader 的权限。在生产系统中,你可能希望提供更细化的权限。

下面 的Role 和 RoleBinding 是 default 账户的命名空间权限的一个例子。

kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  namespace: YOUR-NAME-SPACE
  name: namespace-reader
rules:
  - apiGroups: [""]
    resources: ["configmaps", "pods", "services", "endpoints", "secrets"]
    verbs: ["get", "list", "watch"]

---

kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: namespace-reader-binding
  namespace: YOUR-NAME-SPACE
subjects:
- kind: ServiceAccount
  name: default
  apiGroup: ""
roleRef:
  kind: Role
  name: namespace-reader
  apiGroup: ""

12. 服务注册的实现

在Kubernetes中,服务注册由平台控制,应用程序本身并不像在其他平台中那样控制注册。因此,使用 spring.cloud.service-registry.auto-registration.enabled 或设置 @EnableDiscoveryClient(autoRegister=false) 在Spring Cloud Kubernetes中没有效果。

13. Spring Cloud Kubernetes Configuration Watcher

Kubernetes 提供了 将 ConfigMap 或 Secret 挂载到应用程序的容器中作为卷 的能力。当 ConfigMap 或 Secret 的内容发生变化时, 挂载的卷就会根据这些变化进行更新

然而,除非你重新启动应用程序,否则Spring Boot不会自动更新这些变化。Spring Cloud 提供了刷新 application context 的能力,无需重启应用程序,方法是点击 actuator 的 /refresh 端点,或通过使用 Spring Cloud Bus 发布 RefreshRemoteApplicationEvent

为了实现在Kubernetes上运行的Spring Cloud应用程序的这种配置刷新,你可以将 Spring Cloud Kubernetes Configuration Watcher controller 部署到你的Kubernetes集群中。

该应用程序以容器形式发布,可在 Docker Hub 上使用。然而,如果你需要定制配置 watcher 的行为,或者喜欢自己构建镜像,你可以很容易地从 GitHub上的源代码 构建自己的镜像并使用它。

Spring Cloud Kubernetes Configuration Watcher 可以通过两种方式向应用程序发送刷新通知。

  1. 通过HTTP,在这种情况下,被通知的应用程序必须有 /refresh actuator 端点暴露出来,并且可以从集群内访问。

  2. 使用Spring Cloud Bus,在这种情况下,你将需要在你的集群中部署一个message broker,以便应用程序使用。

13.1. Deployment YAML

下面是一个 deployment YAML 的样本,你可以用来将 Kubernetes Configuration Watcher 部署到 Kubernetes。

---
apiVersion: v1
kind: List
items:
  - apiVersion: v1
    kind: Service
    metadata:
      labels:
        app: spring-cloud-kubernetes-configuration-watcher
      name: spring-cloud-kubernetes-configuration-watcher
    spec:
      ports:
        - name: http
          port: 8888
          targetPort: 8888
      selector:
        app: spring-cloud-kubernetes-configuration-watcher
      type: ClusterIP
  - apiVersion: v1
    kind: ServiceAccount
    metadata:
      labels:
        app: spring-cloud-kubernetes-configuration-watcher
      name: spring-cloud-kubernetes-configuration-watcher
  - apiVersion: rbac.authorization.k8s.io/v1
    kind: RoleBinding
    metadata:
      labels:
        app: spring-cloud-kubernetes-configuration-watcher
      name: spring-cloud-kubernetes-configuration-watcher:view
    roleRef:
      kind: Role
      apiGroup: rbac.authorization.k8s.io
      name: namespace-reader
    subjects:
      - kind: ServiceAccount
        name: spring-cloud-kubernetes-configuration-watcher
  - apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
      namespace: default
      name: namespace-reader
    rules:
      - apiGroups: ["", "extensions", "apps"]
        resources: ["configmaps", "pods", "services", "endpoints", "secrets"]
        verbs: ["get", "list", "watch"]
  - apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: spring-cloud-kubernetes-configuration-watcher-deployment
    spec:
      selector:
        matchLabels:
          app: spring-cloud-kubernetes-configuration-watcher
      template:
        metadata:
          labels:
            app: spring-cloud-kubernetes-configuration-watcher
        spec:
          serviceAccount: spring-cloud-kubernetes-configuration-watcher
          containers:
          - name: spring-cloud-kubernetes-configuration-watcher
            image: springcloud/spring-cloud-kubernetes-configuration-watcher:2.0.1-SNAPSHOT
            imagePullPolicy: IfNotPresent
            readinessProbe:
              httpGet:
                port: 8888
                path: /actuator/health/readiness
            livenessProbe:
              httpGet:
                port: 8888
                path: /actuator/health/liveness
            ports:
            - containerPort: 8888

Service Account 和相关的角色绑定对于 Spring Cloud Kubernetes 配置的正常工作非常重要。controller 需要读取 Kubernetes 集群中的 ConfigMaps、Pods、Services、Endpoints和Secrets 数据的权限。

13.2. 监控 ConfigMap 和 Secret

Spring Cloud Kubernetes Configuration Watcher 将对标签(label)为 spring.cloud.kubernetes.config 且值为 trueConfigMaps 或标签为 spring.cloud.kubernetes.secret 且值为 true 的任何 Secret 中的更改做出反应。如果 ConfigMap 或 Secret 没有这些标签,或者这些标签的值不是 true,那么任何变化都将被忽略。

如果对具有有效标签的ConfigMap或Secret进行了更改,那么Spring Cloud Kubernetes Configuration Watcher 将采用 ConfigMap 或 Secret 的名称,并向具有该名称的应用程序发送通知。但这可能还不足以满足你的使用需求,例如,你可以。

  • 将一个config-map绑定到多个应用程序上,这样,在一个configmap内的变化会触发许多服务的刷新。

  • 基于 profile 的 sources 为你的应用程序触发事件

由于这个原因,有一个额外的annotation,你可以指定。

spring.cloud.kubernetes.configmap.appsspring.cloud.kubernetes.secret.apps。它需要一个用逗号分隔的应用程序字符串,指定当此 secret/configmap 发生变化时将收到通知的应用程序名称。

例如:

kind: ConfigMap
apiVersion: v1
metadata:
  name: example-configmap
  labels:
    spring.cloud.kubernetes.config: "true"
  annotations:
    spring.cloud.kubernetes.configmap.apps: "app-a, app-b"

13.3. HTTP 实现

HTTP实现是默认使用的。当使用该实现时,Spring Cloud Kubernetes Configuration Watcher和ConfigMap或Secret发生变化,那么HTTP实现将使用Spring Cloud Kubernetes Discovery Client来获取与ConfigMap或Secret名称相匹配的应用程序的所有实例,并向应用程序的 actuator /refres h端点发送HTTP POST请求。默认情况下,它将使用 discovery client 中注册的端口向 /actuator/refresh 发送post请求。

13.3.1. 非默认的 Management Port 和 Actuator Path

如果应用程序使用非默认的 actuator path 和/或为 management endpoint 使用不同的端口,应用程序的Kubernetes服务可以添加一个名为 boot.spring.io/actuator 的 annotation,并将其值设置为应用程序使用的路径和端口。例如

apiVersion: v1
kind: Service
metadata:
  labels:
    app: config-map-demo
  name: config-map-demo
  annotations:
    boot.spring.io/actuator: http://:9090/myactuator/home
spec:
  ports:
    - name: http
      port: 8080
      targetPort: 8080
  selector:
    app: config-map-demo

你可以选择配置 actuator path 和/或 management port 的另一种方式是设置 spring.cloud.kubernetes.configuration.watcher.actuatorPathspring.cloud.kubernetes.configuration.watcher.actuatorPort

13.4. Messaging 实现

当Spring Cloud Kubernetes Configuration Watcher应用程序被部署到Kubernetes时,可以通过将 profile 设置为 bus-amqp(RabbitMQ)或 bus-kafka(Kafka)来启用 messaging 实现。

13.5. RabbitMQ 配置

当启用 bus-amqp 配置文件时,你将需要配置 Spring RabbitMQ 以将其指向你希望使用的 RabbitMQ 实例的位置,以及验证所需的任何凭证。这可以通过设置标准 Spring RabbitMQ 属性来完成,例如。

spring:
  rabbitmq:
    username: user
    password: password
    host: rabbitmq

13.6. Kafka 配置

启用 bus-kafka 配置文件后,你需要配置Spring Kafka,将其指向你想使用的Kafka Broker实例的位置。这可以通过设置标准的Spring Kafka属性来完成,例如。

spring:
  kafka:
    producer:
      bootstrap-servers: localhost:9092

14. Spring Cloud Kubernetes Config Server

Spring Cloud Kubernetes Config Server,基于 Spring Cloud Config Server,增加了一个 Kubernetes Config MapsSecretsenvironment repository

这个组件是完全可选的。然而,它允许你继续利用你可能已经存储在现有 environment repository(Git、SVN、Vault等)中的配置,在Kubernetes上运行的应用程序。

Docker Hub 上有一个默认的镜像,它可以让你轻松地在Kubernetes上部署一个配置服务器(Config Server),而不需要自己构建代码和镜像。然而,如果你需要定制配置服务器的行为,或者喜欢自己构建镜像,你可以很容易地从 GitHub上的源代码 构建自己的镜像并使用它。

14.1. Configuration

14.1.1. 启用 Kubernetes Environment Repository

要启用 Kubernetes environment repository,kubernetes profile 必须包含在 active profiles 列表中。你也可以激活其他 profile,以使用其他 environment repositor 的实现。

14.1.2. Config Map 和 Secret PropertySources

默认情况下,只有 Config Map 数据会被获取。要同时启用 Secrets,你需要设置 spring.cloud.kubernetes.secrets.enableApi=true。你可以通过设置 spring.cloud.kubernetes.config.enableApi=false 来禁用 Config Map PropertySource

14.1.3. 从其他命名空间获取 Config Map 和 Secret 数据

默认情况下,Kubernetes environment repository 只会从其部署的命名空间中获取Config Map和Secrets。如果你想包括其他命名空间的数据,你可以将 spring.cloud.kubernetes.configserver.config-map-namespaces 和/或 spring.cloud.kubernetes.configserver.secrets-namespaces 设置为逗号分隔的命名空间值列表。

如果你设置了 spring.cloud.kubernetes.configserver.config-map-namespaces 和/或 spring.cloud.kubernetes.configserver.secrets-namespaces,你将需要包括配置服务器所部署的命名空间,以便继续从该命名空间获取Config Map和Secret数据。

14.1.4. Kubernetes 访问控制

Kubernetes Config Server 使用 Kubernetes API server 来获取 Config Map 和 Secret 数据。为了做到这一点,它需要 getlist Config Map 和 Secret 的能力(取决于你启用/禁用的内容)。

14.2. Deployment Yaml

下面是一个 deployment、service 和 permissions 配置的样本,你可以用来将一个基本的配置服务器部署到Kubernetes。

---
apiVersion: v1
kind: List
items:
  - apiVersion: v1
    kind: Service
    metadata:
      labels:
        app: spring-cloud-kubernetes-configserver
      name: spring-cloud-kubernetes-configserver
    spec:
      ports:
        - name: http
          port: 8888
          targetPort: 8888
      selector:
        app: spring-cloud-kubernetes-configserver
      type: ClusterIP
  - apiVersion: v1
    kind: ServiceAccount
    metadata:
      labels:
        app: spring-cloud-kubernetes-configserver
      name: spring-cloud-kubernetes-configserver
  - apiVersion: rbac.authorization.k8s.io/v1
    kind: RoleBinding
    metadata:
      labels:
        app: spring-cloud-kubernetes-configserver
      name: spring-cloud-kubernetes-configserver:view
    roleRef:
      kind: Role
      apiGroup: rbac.authorization.k8s.io
      name: namespace-reader
    subjects:
      - kind: ServiceAccount
        name: spring-cloud-kubernetes-configserver
  - apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
      namespace: default
      name: namespace-reader
    rules:
      - apiGroups: ["", "extensions", "apps"]
        resources: ["configmaps", "secrets"]
        verbs: ["get", "list"]
  - apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: spring-cloud-kubernetes-configserver-deployment
    spec:
      selector:
        matchLabels:
          app: spring-cloud-kubernetes-configserver
      template:
        metadata:
          labels:
            app: spring-cloud-kubernetes-configserver
        spec:
          serviceAccount: spring-cloud-kubernetes-configserver
          containers:
          - name: spring-cloud-kubernetes-configserver
            image: springcloud/spring-cloud-kubernetes-configserver
            imagePullPolicy: IfNotPresent
            env:
                - name: SPRING_PROFILES_INCLUDE
                  value: "kubernetes"
            readinessProbe:
              httpGet:
                port: 8888
                path: /actuator/health/readiness
            livenessProbe:
              httpGet:
                port: 8888
                path: /actuator/health/liveness
            ports:
            - containerPort: 8888

15. Spring Cloud Kubernetes Discovery Server

Spring Cloud Kubernetes Discovery Server 提供了HTTP端点,应用程序可用于收集Kubernetes集群内可用服务的信息。使用 spring-cloud-starter-kubernetes-discoveryclient 的应用程序可以使用 Spring Cloud Kubernetes Discovery Server,向该 starter 提供的 DiscoveryClient 实现提供数据。

15.1. 权限

Spring Cloud Discovery server 使用Kubernetes API服务器来获取有关服务和端点资源的数据,因此它需要列出、观察并获得使用这些端点的权限。请看下面的Kubernetes deployment YAML示例,了解如何在Kubernetes上配置服务账户。

15.2. 端点

有三个端点由服务器公开。

15.2.1. /apps

发送到 /appsGET 请求将返回一个可用服务的JSON数组。每个项目包含 Kubernetes 服务的名称和服务实例信息。下面是一个响应示例。

[
   {
      "name":"spring-cloud-kubernetes-discoveryserver",
      "serviceInstances":[
         {
            "instanceId":"836a2f25-daee-4af2-a1be-aab9ce2b938f",
            "serviceId":"spring-cloud-kubernetes-discoveryserver",
            "host":"10.244.1.6",
            "port":8761,
            "uri":"http://10.244.1.6:8761",
            "secure":false,
            "metadata":{
               "app":"spring-cloud-kubernetes-discoveryserver",
               "kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"v1\",\"kind\":\"Service\",\"metadata\":{\"annotations\":{},\"labels\":{\"app\":\"spring-cloud-kubernetes-discoveryserver\"},\"name\":\"spring-cloud-kubernetes-discoveryserver\",\"namespace\":\"default\"},\"spec\":{\"ports\":[{\"name\":\"http\",\"port\":80,\"targetPort\":8761}],\"selector\":{\"app\":\"spring-cloud-kubernetes-discoveryserver\"},\"type\":\"ClusterIP\"}}\n",
               "http":"8761"
            },
            "namespace":"default",
            "scheme":"http"
         }
      ]
   },
   {
      "name":"kubernetes",
      "serviceInstances":[
         {
            "instanceId":"1234",
            "serviceId":"kubernetes",
            "host":"172.18.0.3",
            "port":6443,
            "uri":"http://172.18.0.3:6443",
            "secure":false,
            "metadata":{
               "provider":"kubernetes",
               "component":"apiserver",
               "https":"6443"
            },
            "namespace":"default",
            "scheme":"http"
         }
      ]
   }
]

15.2.2. /apps/{name}

/apps/{name}GET 请求可以用来获取某个服务的所有实例的数据。下面是一个向 /apps/kubernetes 发出 GET 请求时的响应样本。

[
     {
        "instanceId":"1234",
        "serviceId":"kubernetes",
        "host":"172.18.0.3",
        "port":6443,
        "uri":"http://172.18.0.3:6443",
        "secure":false,
        "metadata":{
           "provider":"kubernetes",
           "component":"apiserver",
           "https":"6443"
        },
        "namespace":"default",
        "scheme":"http"
     }
]

15.2.3. /app/{name}/{instanceid}

/app/{name}/{instanceid} 发出的 GET 请求将返回某个服务的特定实例的实例数据。下面是向 /app/kubernetes/1234 发出 GET 请求时的响应样本。

 {
    "instanceId":"1234",
    "serviceId":"kubernetes",
    "host":"172.18.0.3",
    "port":6443,
    "uri":"http://172.18.0.3:6443",
    "secure":false,
    "metadata":{
       "provider":"kubernetes",
       "component":"apiserver",
       "https":"6443"
    },
    "namespace":"default",
    "scheme":"http"
 }

15.3. Deployment YAML

Spring Cloud Discovery Server 的镜像托管在 Docker Hub。然而,如果你需要定制 discovery server 的行为,或者喜欢自己建立镜像,你可以很容易地从 GitHub上的源代码 建立自己的镜像并使用它。

下面是一个 deployment YAML的样本,你可以用来将 Kubernetes Configuration Watcher 部署到 Kubernetes。

---
apiVersion: v1
kind: List
items:
  - apiVersion: v1
    kind: Service
    metadata:
      labels:
        app: spring-cloud-kubernetes-discoveryserver
      name: spring-cloud-kubernetes-discoveryserver
    spec:
      ports:
        - name: http
          port: 80
          targetPort: 8761
      selector:
        app: spring-cloud-kubernetes-discoveryserver
      type: ClusterIP
  - apiVersion: v1
    kind: ServiceAccount
    metadata:
      labels:
        app: spring-cloud-kubernetes-discoveryserver
      name: spring-cloud-kubernetes-discoveryserver
  - apiVersion: rbac.authorization.k8s.io/v1
    kind: RoleBinding
    metadata:
      labels:
        app: spring-cloud-kubernetes-discoveryserver
      name: spring-cloud-kubernetes-discoveryserver:view
    roleRef:
      kind: Role
      apiGroup: rbac.authorization.k8s.io
      name: namespace-reader
    subjects:
      - kind: ServiceAccount
        name: spring-cloud-kubernetes-discoveryserver
  - apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
      namespace: default
      name: namespace-reader
    rules:
      - apiGroups: ["", "extensions", "apps"]
        resources: ["services", "endpoints"]
        verbs: ["get", "list", "watch"]
  - apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: spring-cloud-kubernetes-discoveryserver-deployment
    spec:
      selector:
        matchLabels:
          app: spring-cloud-kubernetes-discoveryserver
      template:
        metadata:
          labels:
            app: spring-cloud-kubernetes-discoveryserver
        spec:
          serviceAccount: spring-cloud-kubernetes-discoveryserver
          containers:
          - name: spring-cloud-kubernetes-discoveryserver
            image: springcloud/spring-cloud-kubernetes-discoveryserver:3.0.0-SNAPSHOT
            imagePullPolicy: IfNotPresent
            readinessProbe:
              httpGet:
                port: 8761
                path: /actuator/health/readiness
            livenessProbe:
              httpGet:
                port: 8761
                path: /actuator/health/liveness
            ports:
            - containerPort: 8761

16. 示例

Spring Cloud Kubernetes 试图让你的应用程序通过遵循Spring Cloud接口来消费Kubernetes原生服务,这一点很透明。

在你的应用程序中,您需要将 spring-cloud-kubernetes-discovery 依赖项添加到classpath中,并删除任何包含 DiscoveryClient 实现(即 Eureka discovery 客户端)的其他依赖项。这同样适用于 PropertySourceLocator,你需要将 spring-cloud-kubernetes-config 添加到classpath中,并删除任何包含 PropertySourceLocator 实现(即 configuration server client)的其他依赖。

下面的项目强调了这些依赖的用法,并演示了你如何从任何Spring Boot应用程序中使用这些库。

17. 其他资源

本节列出了其他资源,如关于Spring Cloud Kubernetes的介绍(幻灯片)和视频。

请随时通过PR 向 该 repository 提交其他资源。

18. 配置属性

要查看所有与Kubernetes相关的配置属性列表,请查看 附录页面

19. 构建

19.1. 基本的编译和测试

要构建源代码,你需要安装JDK 17。

Spring Cloud使用Maven进行大多数构建相关的活动,通过克隆你感兴趣的项目并键入以下内容,你应该能很快上手

$ ./mvnw install
你也可以自己安装Maven(>=3.3.3),运行 mvn 命令来代替下面例子中的 ./mvnw。如果你这样做,如果你的本地Maven设置不包含 spring 预发布 artifact 的 repository 声明,你可能还需要添加 -P spring
请注意,您可能需要通过设置 MAVEN_OPTS 环境变量,如 -Xmx512m -XX:MaxPermSize=128m 来增加Maven的可用内存。我们试图在 .mvn 配置中涵盖这一点,所以如果你发现你必须这样做才能使构建成功,请提出一个raise,将设置添加到 source control 中。

需要中间件(如,Redis)进行测试的项目一般需要安装和运行 Docker 的本地实例。

19.2. 文档

spring-cloud-build 模块有一个 "docs" profile,如果你打开它,它将尝试从 src/main/asciidoc 构建 asciidoc 源。作为该过程的一部分,它将寻找 README.adoc,并通过加载所有内容来处理它,但不对其进行解析或渲染,只是将其复制到 ${main.basedir}(默认为 $C:\Users\KevinBlandy\Desktop\SpringDoc\spring-cloud-kubernetes-doc\docs,即项目的根目录)。如果README有任何改动,在Maven构建后就会以修改过的文件出现在正确位置。提交并推送修改内容即可。

19.3. 使用代码工作

如果你没有IDE的偏好,我们建议你在处理代码时使用 Spring Tools SuiteEclipse。我们使用 m2eclipse eclipse插件来支持maven。其他IDE和工具只要使用Maven 3.3.3或更高版本,也应能顺利工作。

19.3.1. 激活 Spring Maven profile

Spring Cloud 项目需要激活 "spring" Maven profile,以解决spring里程碑和快照库的问题。使用你喜欢的IDE将该 profile 设置为 active 状态,否则你可能会遇到构建错误。

19.3.2. 用 m2eclipse 导入到 eclipse 中

在使用eclipse时,我们推荐使用 m2eclipse eclipse插件。如果你还没有安装m2eclipse,它可以从 "eclipse marketplace" 获得。

旧版本的m2e不支持Maven 3.3,所以一旦项目被导入Eclipse,你还需要告诉m2eclipse为项目使用正确的profile。如果你看到项目中与POMs有关的许多不同的错误,请检查你是否有一个最新的安装。如果你不能升级m2e,把 "spring" profile加入你的 settings.xml。或者你可以从父pom的 "spring" profile 中复制版本库设置到你的 settings.xml 中。

19.3.3. 在没有 m2eclipse 的情况下导入 eclipse 中

如果你不愿意使用 m2eclipse,你可以用以下命令生成 eclipse 项目元数据。

$ ./mvnw eclipse:eclipse

生成的 eclipse 项目可以通过在 file 菜单中选择 import existing projects 来导入。

20. 贡献

Spring Cloud在非限制性的Apache 2.0许可下发布,并遵循非常标准的Github开发流程,使用Github tracker 处理 issue,并将 pull request 合并到 master。如果你想做出贡献,哪怕是一些微不足道的事情,请不要犹豫,但要遵循以下准则。

20.1. 签署贡献者许可协议

在我们接受一个补丁或 pull request 之前,我们需要你签署 贡献者许可协议。签署贡献者协议并不授予任何人对主仓库的提交权,但这意味着我们可以接受你的贡献,如果我们接受你的贡献,你将获得作者的荣誉。积极的贡献者可能会被要求加入核心团队,并被赋予合并 pull request 的能力。

20.2. 行为准则

本项目遵守 《贡献者公约》 的行为准则。通过参与,你被期望维护这一准则。请将不可接受的行为报告给 spring-code-of-conduct@pivotal.io

20.3. 准则公约和内部管理

这些都不是 pull request 的必要条件,但它们都会有帮助。它们也可以在原始 pull request 之后、合并之前添加。

  • 使用Spring框架的代码格式约定。如果你使用Eclipse,你可以使用 Spring Cloud Build 项目中的 eclipse-code-formatter.xml 文件导入格式化设置。如果使用IntelliJ,你可以使用 Eclipse Code Formatter Plugin 来导入相同的文件。

  • 确保所有新的 .java 文件都有一个简单的 Javadoc 类注释,至少有一个 @author 的标签来标识你,最好至少有一段关于类的用途。

  • 在所有新的 .java 文件中添加ASF license header 注释(从项目中的现有文件中复制)。

  • 在你大量修改的 .java 文件中加入自己作为 @author(不仅仅是外观上的修改)。

  • 添加一些 Javadocs,如果你改变了命名空间,则添加一些XSD doc元素。

  • 一些单元测试也会有很大的帮助—​总得有人来做。

  • 如果没有人在使用你的分支,请将其与当前的主干分支(或主项目中的其他目标分支)重新建立基线。

  • 在写提交信息时,请遵循 这些惯例,如果你要修复一个现有的问题,请在提交信息的末尾加上 Fixes gh-XXXX(其中XXXX是 issue 编号)。

20.4. 检查风格(Checkstyle)

Spring Cloud Build自带一套检查风格(checkstyle)的规则。你可以在 spring-cloud-build-tools 模块中找到它们。该模块下最值得注意的文件是。

spring-cloud-build-tools/
└── src
    ├── checkstyle
    │   └── checkstyle-suppressions.xml (3)
    └── main
        └── resources
            ├── checkstyle-header.txt (2)
            └── checkstyle.xml (1)
1 默认的检查风格规则
2 文件头设置
3 默认的 suppression 规则

20.4.1. Checkstyle 配置

Checkstyle 规则默认是禁用的。要在你的项目中添加 checkstyle,只需定义以下属性和插件。

pom.xml
<properties>
<maven-checkstyle-plugin.failsOnError>true</maven-checkstyle-plugin.failsOnError> (1)
        <maven-checkstyle-plugin.failsOnViolation>true
        </maven-checkstyle-plugin.failsOnViolation> (2)
        <maven-checkstyle-plugin.includeTestSourceDirectory>true
        </maven-checkstyle-plugin.includeTestSourceDirectory> (3)
</properties>

<build>
        <plugins>
            <plugin> (4)
                <groupId>io.spring.javaformat</groupId>
                <artifactId>spring-javaformat-maven-plugin</artifactId>
            </plugin>
            <plugin> (5)
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-checkstyle-plugin</artifactId>
            </plugin>
        </plugins>

    <reporting>
        <plugins>
            <plugin> (5)
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-checkstyle-plugin</artifactId>
            </plugin>
        </plugins>
    </reporting>
</build>
1 构建时出现 Checkstyle error 而失败
2 违反Checkstyle规定时,不合格。
3 Checkstyle还分析了test sources
4 添加Spring Java Format 插件,它将重新格式化你的代码,以通过大多数Checkstyle格式化规则。
5 在你的构建和报告阶段添加checkstyle插件

如果你需要抑制某些规则(例如,行长需要更长),那么你只需在 ${project.root}/src/checkstyle/checkstyle-suppressions.xml 下定义一个文件,写上你的抑制措施即可。例子。

projectRoot/src/checkstyle/checkstyle-suppresions.xml
<?xml version="1.0"?>
<!DOCTYPE suppressions PUBLIC
        "-//Puppy Crawl//DTD Suppressions 1.1//EN"
        "https://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
<suppressions>
    <suppress files=".*ConfigServerApplication\.java" checks="HideUtilityClassConstructor"/>
    <suppress files=".*ConfigClientWatch\.java" checks="LineLengthCheck"/>
</suppressions>

建议将 ${spring-cloud-build.rootFolder}/.editorconfig${spring-cloud-build.rootFolder}/.springformat 复制到你的项目。这样一来,一些默认的格式化规则就会被应用。你可以通过运行这个脚本来做到这一点。

$ curl https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/.editorconfig -o .editorconfig
$ touch .springformat

20.5. IDE设置

20.5.1. Intellij IDEA

为了设置Intellij,你应该导入我们的编码惯例、检查配置文件并设置checkstyle插件。在 Spring Cloud Build 项目中可以找到以下文件。

spring-cloud-build-tools/
└── src
    ├── checkstyle
    │   └── checkstyle-suppressions.xml (3)
    └── main
        └── resources
            ├── checkstyle-header.txt (2)
            ├── checkstyle.xml (1)
            └── intellij
                ├── Intellij_Project_Defaults.xml (4)
                └── Intellij_Spring_Boot_Java_Conventions.xml (5)
1 默认的Checkstyle规则
2 文件头的设置
3 默认的 suppression 规则
4 Intellij的项目默认值,适用于大多数Checkstyle规则
5 适用于Intellij的项目风格惯例,适用于大多数Checkstyle规则
Code style
Figure 1. Code style

进入 FileSettingsEditorCode style。在那里点击 Scheme 部分旁边的图标。在那里,点击 Import Scheme,选择 Intellij IDEA code style XML 选项。导入 spring-cloud-build-tools/src/main/resources/intellij/Intellij_Spring_Boot_Java_Conventions.xml 文件。

Code style
Figure 2. Inspection profiles

进入 FileSettingsEditorInspections。在那里点击 Profile 部分旁边的图标。在那里,点击 Import Profile 并导入 spring-cloud-build-tools/src/main/resources/intellij/Intellij_Project_Defaults.xml 文件。

Checkstyle

为了让Intellij与Checkstyle一起工作,你必须安装 Checkstyle 插件。建议同时安装 Assertions2Assertj 来自动转换JUnit断言。

Checkstyle

进入 FileSettingsOther settingsCheckstyle。在那里点击 Configuration file 部分的 + 图标。在那里,你必须定义检查风格规则应该从哪里提取。在上图中,我们从克隆的Spring Cloud Build资源库中挑选规则。不过,你也可以指向Spring Cloud Build的GitHub仓库(例如,对于 checkstyle.xml : raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/spring-cloud-build-tools/src/main/resources/checkstyle.xml )。我们需要提供以下变量。

记住将扫描范围设置为所有来源,因为我们对生产和测试来源应用检查式规则。

20.6. Duplicate Finder(重复搜索器)

Spring Cloud Build带来了 basepom:duplicate-finder-maven-plugin,它可以标记java classpath上重复和冲突的类和资源。

20.6.1. Duplicate Finder 配置

Duplicate finder 默认是启用的,会在Maven构建的 verify 阶段运行,但只有当你在项目的pom.xml build 部分添加了 duplicate-finder-maven-plugin,它才会在项目中生效。

pom.xml
<build>
    <plugins>
        <plugin>
            <groupId>org.basepom.maven</groupId>
            <artifactId>duplicate-finder-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

对于其他属性,我们已经设置了 插件文档 中列出的默认值。

你可以通过设置以 double-finder-maven-plugin 为前缀的选定属性的值来轻松覆盖它们。例如,将 double-finder-maven-plugin.skip 设为 true,以便在构建中跳过重复检查。

如果你需要在你的设置中添加 ignoredClassPatternsignoredResourcePatterns,请确保在你项目的 plugin configuration 部分添加它们。

<build>
    <plugins>
        <plugin>
            <groupId>org.basepom.maven</groupId>
            <artifactId>duplicate-finder-maven-plugin</artifactId>
            <configuration>
                <ignoredClassPatterns>
                    <ignoredClassPattern>org.joda.time.base.BaseDateTime</ignoredClassPattern>
                    <ignoredClassPattern>.*module-info</ignoredClassPattern>
                </ignoredClassPatterns>
                <ignoredResourcePatterns>
                    <ignoredResourcePattern>changelog.txt</ignoredResourcePattern>
                </ignoredResourcePatterns>
            </configuration>
        </plugin>
    </plugins>
</build>

21. AOT 和 原生镜像(native image)的支持

在这一点上,Spring Cloud Kubernetes不支持Spring Boot AOT转换或原生镜像。在未来的版本中可能会增加部分支持。