# Spring Cloud Kubernetes

本参考指南介绍了如何使用 Spring Cloud Kubernetes。

## 1. Why do you need Spring Cloud Kubernetes?

Spring Cloud Kubernetes 提供了众所周知的 Spring Cloud接口的实现，允许开发人员在 Kubernetes 上构建和运行 Spring Cloud应用程序。虽然这个项目在构建云原生应用程序时可能对你很有用，但在 Kubernetes 上部署 Spring 启动应用程序也不是必需的。如果你刚刚开始在 Kubernetes 上运行你的启动应用程序，你只需要一个基本的启动应用程序和 Kubernetes 本身就可以完成很多事情。要了解更多信息，你可以从阅读[Spring Boot reference documentation for deploying to Kubernetes ](https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#cloud-deployment-kubernetes)开始，还可以阅读研讨会材料[Spring and Kubernetes](https://hackmd.io/@ryanjbaxter/spring-on-k8s-workshop)。

## 2.初学者

启动器是可以包含在应用程序中的方便的依赖关系描述符。包括一个启动器，以获得依赖关系和 Spring 一个功能集的启动自动配置。以`spring-cloud-starter-kubernetes-fabric8`开头的启动器使用[Fabric8Kubernetes Java 客户端](https://github.com/fabric8io/kubernetes-client)提供实现。以`spring-cloud-starter-kubernetes-client`开头的启动器使用[Kubernetes Java 客户端](https://github.com/kubernetes-client/java)提供实现。

|起动器|                                                                                                        Features                                                                                                         |
|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|Fabric8dependency<br/><br/>```<br/><dependency><br/>    <groupId>org.springframework.cloud</groupId><br/>    <artifactId>spring-cloud-starter-kubernetes-fabric8</artifactId><br/></dependency><br/>```<br/><br/>Kubernetes client dependency<br/><br/>```<br/><dependency><br/>    <groupId>org.springframework.cloud</groupId><br/>    <artifactId>spring-cloud-starter-kubernetes-client</artifactId><br/></dependency><br/>```|                                               [Discovery Client](#discoveryclient-for-kubernetes) implementation that<br/>resolves service names to Kubernetes Services.                                                |
|Fabric8dependency<br/><br/>```<br/><dependency><br/>    <groupId>org.springframework.cloud</groupId><br/>    <artifactId>Spring-cloud-starter-kubernetes-fabric8-config</artifactId><br/></dependency><br/>```<br/><br/>Kubernetes client dependency<br/><br/>```<br/><dependency><br/>    <groupId>org.springframework.cloud</groupId><br/>    <artifactId>spring-cloud-starter-kubernetes-client-config</artifactId><br/></dependency><br/>```|Load application properties from Kubernetes[ConfigMaps](#configmap-propertysource) and [Secrets](#secrets-propertysource).[Reload](#propertysource-reload) application properties when a ConfigMap or<br/>Secret changes.|
|Fabric8dependency<br/><br/>```<br/><dependency><br/>    <groupId>org.springframework.cloud</groupId><br/>    <artifactId>spring-cloud-starter-kubernetes-fabric8-all</artifactId><br/></dependency><br/>```<br/><br/>Kubernetes client dependency<br/><br/>```<br/><dependency><br/>    <groupId>org.springframework.cloud</groupId><br/>    <artifactId>spring-cloud-starter-kubernetes-client-all</artifactId><br/></dependency><br/>```|                                                                                          All Spring Cloud Kubernetes features.                                                                                          |

## 3.Kubernetes 的发现

该项目为[Kubernetes](https://kubernetes.io)提供了[发现客户端](https://github.com/spring-cloud/spring-cloud-commons/blob/master/spring-cloud-commons/src/main/java/org/springframework/cloud/client/discovery/DiscoveryClient.java)的实现。这个客户机允许你按名称查询 Kubernetes 端点（参见[services](https://kubernetes.io/docs/user-guide/services/)）。Kubernetes API 服务器通常将服务公开为表示`http`和`https`地址的端点集合，客户端可以从 Spring 以 POD 形式运行的启动应用程序访问这些端点。

这是通过在项目中添加以下依赖项而免费获得的：

基于 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](#spring-cloud-kubernetes-discoveryserver)的。|
|---|---------------------------------------------------------------------------------------------------------------------------------------------------------------------|

Fabric8Kubernetes 客户端

```
<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`添加到相应的配置或应用程序类中，如下例所示：

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

然后，你可以通过自动布线将客户机插入到代码中，如下例所示：

```
@Autowired
private DiscoveryClient discoveryClient;
```

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

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

要发现未被 Kubernetes API 服务器标记为“ready”的服务端点地址，可以在`application.properties`（默认：false）中设置以下属性：

```
spring.cloud.kubernetes.discovery.include-not-ready-addresses=true
```

|   |在为监视目的发现服务时，这可能是有用的，并且将允许检查未准备好的服务实例的`/health`端点。|
|---|----------------------------------------------------------------------------------------------------------------------------------------------------------|

如果你的服务公开了多个端口，那么你将需要指定`DiscoveryClient`应该使用哪个端口。`DiscoveryClient`将使用以下逻辑选择端口。

1. 如果服务有一个标签`primary-port-name`，它将使用在标签的值中指定名称的端口。

2. 如果不存在标签，则将使用`spring.cloud.kubernetes.discovery.primary-port-name`中指定的端口号。

3. 如果上面两个都没有指定，它将使用名为`https`的端口。

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

5. 作为最后的手段，它 WIL 在港口列表中选择第一个港口。

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

默认情况下，所有端口及其名称都将添加到`ServiceInstance`的元数据中。

如果出于任何原因，需要禁用`DiscoveryClient`，则可以在`application.properties`中设置以下属性：

```
spring.cloud.kubernetes.discovery.enabled=false
```

Spring 一些云组件使用`DiscoveryClient`以便获得有关本地服务实例的信息。为此，你需要将 Kubernetes 服务名称与`spring.application.name`属性对齐。

|   |`spring.application.name`对于在 Kubernetes 中为应用程序注册的名称没有任何效力|
|---|-----------------------------------------------------------------------------------------------------------|

Spring Cloud Kubernetes 还可以观察 Kubernetes 服务目录的变化并相应地更新`DiscoveryClient`实现。为了启用此功能，你需要在应用程序中的配置类上添加`@EnableScheduling`。

## 4.Kubernetes 原生服务发现

Kubernetes 本身能够（服务器端）发现服务（参见：[Kubernetes.io/DOCS/概念/服务-网络/服务/# 发现-服务](https://kubernetes.io/docs/concepts/services-networking/service/#discovering-services)）。使用本机 Kubernetes 服务发现可以确保与其他工具的兼容性，例如 Istio（[istio.io](https://istio.io)），这是一种能够实现负载平衡、断路器、故障转移等功能的服务网格。

调用方服务只需要引用特定 Kubernetes 集群中可解析的名称。一个简单的实现可以使用一个 Spring `RestTemplate`，它引用一个完全限定的域名，例如`[{service-name}.{namespace}.svc.{cluster}.local:{service-port}](https://{service-name}.{namespace}.svc.{cluster}.local:{service-port})`。

此外，你可以将 Hystrix 用于：

* 在调用方实现断路器，通过用`@EnableCircuitBreaker`注释 Spring 引导应用程序类

* 回退功能，通过使用`@HystrixCommand(fallbackMethod=`注释相应的方法

## 5.Kubernetes PropertySource 实现

配置 Spring 启动应用程序的最常见方法是创建`application.properties`或`application.yaml`或`application-profile.properties`或`application-profile.yaml`文件，该文件包含为应用程序或 Spring 启动程序提供定制值的键值对。你可以通过指定系统属性或环境变量来覆盖这些属性。

### 5.1.使用`ConfigMap``PropertySource`

Kubernetes 提供了一个名为[`ConfigMap`]的资源（https://kubernetes.io/DOCS/user-guide/configmap/），以外部化以键值对的形式传递给应用程序的参数，或嵌入`application.properties`或`application.yaml`文件。[Spring Cloud Kubernetes Config](https://github.com/spring-cloud/spring-cloud-kubernetes/tree/master/spring-cloud-kubernetes-fabric8-config)项目使 Kubernetes`ConfigMap`实例在应用程序引导过程中可用，并在观察到的`ConfigMap`实例上检测到更改时触发 bean 或 Spring 上下文的热重载。

默认的行为是基于 Kubernetes 创建`Fabric8ConfigMapPropertySource`它具有一个`metadata.name`值，该值既是你的 Spring 应用程序的名称（由其`spring.application.name`属性定义），也是在`bootstrap.properties`文件中定义的自定义名称，该文件位于以下键下：`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`，则将在应用程序运行的名称空间中查找名为`ConfigMap`的`c1`。请参阅[名称空间解析](#namespace-resolution)，以更好地了解如何解析应用程序的名称空间。

找到的任何匹配的`ConfigMap`将按以下方式进行处理：

* 应用单独的配置属性。

* 将名为`yaml`的任何属性的内容应用为`application.yaml`。

* 将任何名为`application.properties`的属性的内容作为属性文件应用。

上述流的一个例外是，当`ConfigMap`包含一个**单身**键时，该键指示该文件是 YAML 或 Properties 文件。在这种情况下，键的名称不必是`application.yaml`或`application.properties`（它可以是任何东西），并且该属性的值被正确地处理。这个特性促进了`ConfigMap`是通过使用如下内容创建的用例：

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

假设我们有一个名为`demo`的 Spring 引导应用程序，该应用程序使用以下属性来读取其线程池配置。

* `pool.size.core`

* `pool.size.maximum`

这可以外部化为`yaml`格式的配置映射，如下所示：

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

在大多数情况下，单个属性都可以正常工作。然而，有时，嵌入式`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
```

你还可以根据读取`ConfigMap`时合并在一起的活动配置文件来不同地配置 Spring 引导应用程序。你可以通过使用`application.properties`或`application.yaml`属性为不同的配置文件提供不同的属性值，并在各自的文档中指定配置文件特定的值（由`---`序列指示），如下所示：

```
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`配置文件加载到 Spring 应用程序中的配置如下：

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

但是，如果`production`配置文件是活动的，那么配置将变为：

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

如果这两个配置文件都是活动的，则在`ConfigMap`中最后出现的属性将覆盖前面的任何值。

另一种选择是为每个配置文件创建不同的配置映射，并且 Spring 启动将基于活动配置文件自动获取它

```
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 在引导时应该启用哪个`profile`，可以传递`SPRING_PROFILES_ACTIVE`环境变量。为此，你可以使用一个环境变量启动你的 Spring 引导应用程序，你可以在容器规范的 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"
```

你可能会遇到这样的情况，即有多个配置映射具有相同的属性名。例如：

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

and

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

根据在`bootstrap.yaml|properties`中放置这些参数的顺序，你可能最终会得到一个未预期的结果（最后一个配置映射获胜）。例如：

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

将导致属性`greetings.message`为`Say 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`具有*下层*的优先权。这允许你为所有源设置一个“默认”策略，同时只允许覆盖少数几个源。

如果使用配置映射名称不是一个选项，则可以指定一个不同的策略，称为：`explicitPrefix`。由于这是你选择的*显式*前缀，因此它只能提供给`sources`级别。同时它具有比`useNameAsPrefix`更高的优先级。假设我们有第三个配置映射，它包含以下条目：

```
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
```

将生成三个属性：

* `greetings.message`等于`Say Hello from one`。

* `two.greetings.message`等于`Say Hello from two`。

* `config-map-three.greetings.message`等于`Say Hello from three`。

默认情况下，除了读取`sources`配置中指定的配置映射外， Spring 还将尝试从“配置文件感知”源读取所有属性。最简单的解释方法是通过一个例子。让我们假设你的应用程序启用了一个名为“dev”的配置文件，并且你的配置如下所示：

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

除了读取`config-map-one`外， Spring 还将尝试按此特定顺序读取`config-map-one-dev`；。每个活动配置文件生成这样的配置文件感知配置映射。

虽然你的应用程序不应该受到这样的配置映射的影响，但如果需要，可以禁用它：

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

注意，和前面一样，你可以在两个级别中指定此属性：对于所有配置映射或对于单个配置映射；后者具有更高的优先级。

|   |你应该检查安全配置部分。要从 POD 内部访问配置映射，你需要拥有正确的<br/>Kubernetes 服务帐户、角色和角色绑定。|
|---|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

使用`ConfigMap`实例的另一种选择是，通过运行 Spring Cloud Kubernetes 应用程序并让 Spring Cloud Kubernetes 从文件系统中读取它们，将它们安装到 POD 中。此行为由`spring.cloud.kubernetes.config.paths`属性控制。你可以在前面描述的机制之外使用它，也可以使用它来代替它。通过使用`,`分隔符，可以在`spring.cloud.kubernetes.config.paths`中指定多个（精确的）文件路径。

|   |你必须为每个属性文件提供完整的精确路径，因为目录不是递归解析的。|
|---|--------------------------------------------------------------------------------------------------------------------|

|   |如果使用`spring.cloud.kubernetes.config.paths`或`spring.cloud.kubernetes.secrets.path`，则自动重新加载<br/>功能将无法工作。你需要向`/actuator/refresh`端点或<br/>重新启动/重新部署应用程序发出`POST`请求。|
|---|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

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

你还可以使你的应用程序在出现故障时重试加载`ConfigMap`属性源。首先，需要设置`spring.cloud.kubernetes.config.fail-fast=true`。然后，你需要在 Classpath 中添加`spring-retry`和`spring-boot-starter-aop`。你可以通过设置`spring.cloud.kubernetes.config.retry.*`属性来配置重试属性，如最大尝试次数、退避选项（如初始间隔、乘法器、最大间隔）。

|   |如果由于某种原因在 Classpath 上已经有`spring-retry`和`spring-boot-starter-aop`<br/>并且希望启用 fail-fast，但是不希望被启用重试；你可以通过设置`ConfigMap`来禁用`PropertySources`的重试。|
|---|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

|                         Name                          |  Type   |          Default           |说明|
|-------------------------------------------------------|---------|----------------------------|-----------------------------------------------------------------------------------------------------|
|       `spring.cloud.kubernetes.config.enabled`        |`Boolean`|           `true`           |启用配置图`PropertySource`|
|         `spring.cloud.kubernetes.config.name`         |`String` |`${spring.application.name}`|设置`ConfigMap`的名称以进行查找|
|      `spring.cloud.kubernetes.config.namespace`       |`String` |      Client namespace      |设置要查找的 Kubernetes 名称空间|
|        `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`           |启用或禁用配置重试。|
|`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`           |退场的最大间隔。|
|   `spring.cloud.kubernetes.config.retry.multiplier`   |`Double` |           `1.1`            |下一个区间的乘数。|

### 5.2.秘密 PropertySource

Kubernetes 有[Secrets](https://kubernetes.io/docs/concepts/configuration/secret/)的概念，用于存储诸如密码、OAuth 令牌等敏感数据。该项目提供了与`Secrets`的集成，以使 Spring 引导应用程序能够访问秘密。你可以通过设置`spring.cloud.kubernetes.secrets.enabled`属性显式地启用或禁用此功能。

启用后，`Fabric8SecretsPropertySource`将从以下来源查找`Secrets`的 kubernetes:

1. 从秘密挂载中递归地读取

2. 以应用程序命名（由`spring.application.name`定义）

3. 匹配一些标签

**注：**

默认情况下，出于安全原因，通过 API（以上第 2 点和第 3 点）**未启用**消耗秘密。Secrets 上的权限“列表”允许客户端检查指定名称空间中的 Secrets 值。此外，我们建议容器通过安装的卷共享秘密。

如果你允许通过 API 使用机密，我们建议你使用授权策略（例如 RBAC）来限制对机密的访问。有关通过 API 使用秘密时的风险和最佳实践的更多信息，请参阅[this doc](https://kubernetes.io/docs/concepts/configuration/secret/#best-practices)。

如果发现了这些秘密，它们的数据就会提供给应用程序。

假设我们有一个名为`demo`的 Spring 引导应用程序，该应用程序使用属性来读取其数据库配置。我们可以使用以下命令创建一个 Kubernetes 秘密：

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

前面的命令将创建以下秘密（你可以使用`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`命令提供的基本 64 编码版本的文字。

然后，你的应用程序可以使用这个秘密——例如，通过将秘密的值导出为环境变量：

```
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
```

你可以通过多种方式选择要使用的秘密：

1. 通过列出映射秘密的目录：

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

   如果你将所有的秘密映射到一个公共根，则可以将它们设置为：

   ```
   -Dspring.cloud.kubernetes.secrets.paths=/etc/secrets
   ```

2. 通过设置一个命名的秘密：

   ```
   -Dspring.cloud.kubernetes.secrets.name=db-secret
   ```

3. 通过定义标签列表：

   ```
   -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`，则将在应用程序运行的名称空间中查找名为`Secret`的`Secret`。请参阅[名称空间分辨率](#namespace-resolution)，以更好地了解如何解析应用程序的名称空间。

[类似于`ConfigMaps`]（#config-map-fail-fast）；如果你希望你的应用程序在无法加载`Secrets`属性源时启动失败，则可以设置`spring.cloud.kubernetes.secrets.fail-fast=true`。

也可以为`Secret`属性源[比如`ConfigMaps`]启用重试（#config-map-retry）。与`ConfigMap`属性源一样，首先需要设置`spring.cloud.kubernetes.secrets.fail-fast=true`。然后，你需要在 Classpath 中添加`spring-retry`和`spring-boot-starter-aop`。通过设置`spring.cloud.kubernetes.secrets.retry.*`属性，可以配置`Secret`属性源的重试行为。

|   |如果由于某种原因在 Classpath 上已经有`spring-retry`和`spring-boot-starter-aop`<br/>并且希望启用 fail-fast，但是不希望被启用重试；你可以通过设置`spring.cloud.kubernetes.secrets.retry.enabled=false`来禁用`PropertySources`的重试。|
|---|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

|                          Name                          |  Type   |          Default           |说明|
|--------------------------------------------------------|---------|----------------------------|--------------------------------------------------------------------------------------------------|
|       `spring.cloud.kubernetes.secrets.enabled`        |`Boolean`|           `true`           |启用秘密`PropertySource`|
|         `spring.cloud.kubernetes.secrets.name`         |`String` |`${spring.application.name}`|设置要查找的秘密的名称|
|      `spring.cloud.kubernetes.secrets.namespace`       |`String` |      Client namespace      |将 Kubernetes 名称空间设置为在何处查找|
|        `spring.cloud.kubernetes.secrets.labels`        |  `Map`  |           `null`           |设置用于查找秘密的标签|
|        `spring.cloud.kubernetes.secrets.paths`         | `List`  |           `null`           |设置安装秘密的路径（示例 1）|
|      `spring.cloud.kubernetes.secrets.enableApi`       |`Boolean`|          `false`           |通过 API 启用或禁用消耗秘密（示例 2 和 3）|
|      `spring.cloud.kubernetes.secrets.fail-fast`       |`Boolean`|          `false`           |当加载`Secret`时发生错误时，启用或禁用失败的应用程序启动|
|    `spring.cloud.kubernetes.secrets.retry.enabled`     |`Boolean`|           `true`           |启用或禁用秘密重试。|
|`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`           |退场的最大间隔。|
|   `spring.cloud.kubernetes.secrets.retry.multiplier`   |`Double` |           `1.1`            |下一个区间的乘数。|

注：

* `spring.cloud.kubernetes.secrets.labels`属性的行为由[基于地图的绑定](https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-Configuration-Binding#map-based-binding)定义。

* `spring.cloud.kubernetes.secrets.paths`属性的行为由[基于集合的绑定](https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-Configuration-Binding#collection-based-binding)定义。

* 出于安全原因，通过 API 访问机密可能会受到限制。最好的办法是把秘密装在吊舱里。

你可以在[spring-boot-camel-config](https://github.com/fabric8-quickstarts/spring-boot-camel-config)找到一个使用秘密的应用程序示例（尽管它尚未更新为使用新的`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
```

请记住，配置映射也可以这样做。如果没有指定这样的命名空间，则将读取它（按此顺序）：

1. 来自 property`spring.cloud.kubernetes.client.namespace`

2. 来自驻留在由`spring.cloud.kubernetes.client.serviceAccountNamespacePath`属性表示的文件中的字符串

3. 来自驻留在`/var/run/secrets/kubernetes.io/serviceaccount/namespace`文件中的字符串（Kubernetes 缺省名称空间路径）

4. 从指定的客户端方法调用（例如 Fabric8 的：`KubernetesClient::getNamespace`），如果客户端提供了这样的方法。这又可以通过环境属性进行配置。例如，可以通过“Kubernetes\_Namespace”属性配置 Fabric8 客户机；有关详细信息，请参阅客户机文档。

未能从上述步骤中找到名称空间将导致引发异常。

### 5.4.`PropertySource`重新加载

|   |该功能在 2020.0 版本中已被弃用。请参阅<br/>的[Spring Cloud Kubernetes Configuration Watcher](#spring-cloud-kubernetes-configuration-watcher)控制器以替代<br/>的方式实现相同的功能。|
|---|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

一些应用程序可能需要检测外部属性源上的更改，并更新其内部状态以反映新的配置。 Spring Cloud Kubernetes 的重新加载功能能够在相关的`ConfigMap`或`Secret`发生变化时触发应用程序重新加载。

默认情况下，此功能将被禁用。你可以通过使用`spring.cloud.kubernetes.reload.enabled=true`配置属性（例如，在`application.properties`文件中）来启用它。

支持以下级别的重新加载（通过设置`spring.cloud.kubernetes.reload.strategy`属性）：

* `refresh`（缺省）：只有注解为`@ConfigurationProperties`或`@RefreshScope`的配置 bean 才会重新加载。这个重新加载级别利用了 Spring Cloud上下文的刷新功能。

* `restart_context`:整个 Spring `ApplicationContext`被优雅地重新启动。使用新配置重新创建 bean。为了使 Restart 上下文功能正常工作，你必须启用并公开 Restart Actuator 端点

```
management:
  endpoint:
    restart:
      enabled: true
  endpoints:
    web:
      exposure:
        include: restart
```

* `shutdown`:关闭 Spring `ApplicationContext`以激活容器的重新启动。使用此级别时，请确保所有非守护进程线程的生命周期都绑定到`ApplicationContext`，并且配置了一个复制控制器或复制集来重新启动 POD。

假设使用默认设置（`refresh`模式）启用了 Reload 功能，则在配置映射发生更改时将刷新以下 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 关联]（#configmap-propertysource）在本章的前面进行了解释。

完整示例可在[`spring-cloud-kubernetes-reload-example`]（https://github.com/ Spring-cloud/ Spring-cloud-kubernetes/tree/main/ Spring-cloud-kubernetes-examples/kubernetes-reload-example）中找到。

Reload 功能支持两种操作模式：\* 事件（默认）：通过使用 Kubernetes API（Web 套接字）监视配置映射或秘密中的更改。任何事件都会产生对配置的重新检查，如果发生更改，还会产生重新加载。为了监听配置映射更改，服务帐户上的`view`角色是必需的。机密需要更高级别的角色（例如`edit`）（默认情况下，机密不受监视）。\* 轮询：周期性地从配置映射和秘密中重新创建配置，以查看它是否已更改。可以使用`spring.cloud.kubernetes.reload.period`属性配置轮询周期，默认设置为 15 秒。它需要与受监视的属性源具有相同的角色。这意味着，例如，在文件挂载的秘密源上使用轮询不需要特定的权限。

|                         Name                          |   Type   | Default |说明|
|-------------------------------------------------------|----------|---------|--------------------------------------------------------------------------------------|
|       `spring.cloud.kubernetes.reload.enabled`        |`Boolean` | `false` |启用对属性源和配置重新加载的监视|
|`spring.cloud.kubernetes.reload.monitoring-config-maps`|`Boolean` | `true`  |允许监视配置映射中的更改|
|  `spring.cloud.kubernetes.reload.monitoring-secrets`  |`Boolean` | `false` |允许监视机密的更改|
|       `spring.cloud.kubernetes.reload.strategy`       |  `Enum`  |`refresh`|在启动重新加载时使用的策略（`refresh`，`restart_context`，或`shutdown`）|
|         `spring.cloud.kubernetes.reload.mode`         |  `Enum`  | `event` |指定如何侦听属性源中的更改（`event`或`polling`）|
|        `spring.cloud.kubernetes.reload.period`        |`Duration`|  `15s`  |使用`polling`策略时验证更改的周期|

注意：\* 你不应该在配置映射或秘密中使用`spring.cloud.kubernetes.reload`下的属性。在运行时更改这些属性可能会导致意想不到的结果。\* 当你使用`refresh`级别时，删除属性或整个配置映射不会恢复 bean 的原始状态。

## 6.Kubernetes 生态系统意识

无论你的应用程序是否在 Kubernetes 内部运行，本指南前面描述的所有功能都同样有效。这对于开发和故障排除非常有帮助。从开发的角度来看，这允许你启动 Spring 引导应用程序，并调试该项目的一个模块。你不需要在 Kubernetes 中部署它，因为项目的代码依赖于[Fabric8Kubernetes Java 客户端](https://github.com/fabric8io/kubernetes-client)，这是一种 Fluent DSL，可以通过使用`http`协议与 Kubernetes 服务器的 REST API 进行通信。

要禁用与 Kubernetes 的集成，你可以将`spring.cloud.kubernetes.enabled`设置为`false`。请注意，当`spring-cloud-kubernetes-config`在 Classpath 上时，`spring.cloud.kubernetes.enabled`应设置在`bootstrap.{properties|yml}`（或配置文件指定的一个）中，否则应设置在`application.{properties|yml}`（或配置文件指定的一个）中。由于我们在`spring-cloud-kubernetes-config`中设置特定的`EnvironmentPostProcessor`的方式，你还需要通过系统属性（或环境变量）禁用该处理器，例如，你可以通过`-DSPRING_CLOUD_KUBERNETES_ENABLED=false`启动应用程序（任何形式的放松绑定也可以工作）。还要注意这些属性：`spring.cloud.kubernetes.config.enabled`和`spring.cloud.kubernetes.secrets.enabled`仅在`bootstrap.{properties|yml}`中设置时才生效

### 6.1.Kubernetes 配置文件自动配置

当应用程序在 Kubernetes 中作为 POD 运行时，一个名为`kubernetes`的 Spring 配置文件会自动被激活。这使你可以定制配置，以定义在 Spring 引导应用程序部署在 Kubernetes 平台中时应用的 bean（例如，不同的开发和生产配置）。

### 6.2.Istio 意识

当在应用程序 Classpath 中包含`spring-cloud-kubernetes-fabric8-istio`模块时，将向应用程序添加一个新的配置文件，前提是该应用程序在安装了[Istio](https://istio.io)的 Kubernetes 集群中运行。然后可以在 bean 和`@Configuration`类中使用 Spring `@Profile("istio")`注释。

Istio Awareness 模块使用`me.snowdrop:istio-client`与 Istio API 进行交互，让我们发现交通规则、断路器等等，使我们的 Spring 引导应用程序很容易使用这些数据来根据环境动态配置自己。

## 7.POD 健康指示器

Spring Boot 使用[`HealthIndicator`]（https://github.com/ Spring-projects/ Spring-boot/blob/master/ Spring-boot-project/ Spring-boot-actuator/SRC/main/java/org/springframework/boot/actuate/health/healthendpoint.java）来公开有关应用程序健康的信息。这使得它对于向用户公开与健康相关的信息非常有用，并且非常适合作为[准备状态调查](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/)使用。

Kubernetes 健康指示器（它是核心模块的一部分）公开了以下信息：

* POD 名称、IP 地址、命名空间、服务帐户、节点名称及其 IP 地址

* 指示 Spring 引导应用程序是 Kubernetes 的内部还是外部的标志

你可以通过在`application.[properties | yaml]`中将`management.health.kubernetes.enabled`设置为`false`来禁用此`HealthContributor`。

## 8.信息贡献者

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

你可以通过在`application.[properties | yaml]`中将`management.info.kubernetes.enabled`设置为`false`来禁用此`InfoContributor`。

## 9.领导人选举

Spring Cloud Kubernetes 领导人选举机制使用 Kubernetes 配置图实现 Spring 集成的领导人选举 API。

多个应用程序实例竞争领导权，但领导权将只授予一个。当授予领导权时，领导者应用程序将接收带有领导权`OnGrantedEvent`的`OnGrantedEvent`应用程序事件。应用程序会定期尝试获得领导力，并将领导力授予第一个呼叫者。领导者将一直是领导者，直到被从集群中移除，或者交出领导者。当领导层被撤职时，前一位领导人将收到`OnRevokedEvent`应用程序事件。删除后，集群中的任何实例都可能成为新的领导者，包括旧的领导者。

要将它包含在项目中，请添加以下依赖项。

Fabric8Leader 实现

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

要指定用于领导者选举的配置图的名称，请使用以下属性。

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

## 10.Kubernetes 负载平衡器

Spring 该项目包括用于基于 Kubernetes 端点的负载平衡的云负载平衡器和提供基于 Kubernetes 服务的负载平衡器的实现。要将它包含到项目中，请添加以下依赖项。

Fabric8 的实现

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

Kubernetes Java 客户端实现

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

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

```
spring.cloud.kubernetes.loadbalancer.mode=SERVICE
```

要启用跨所有名称空间的负载平衡，请使用以下属性。来自`spring-cloud-kubernetes-discovery`模块的属性是受尊重的。

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

如果需要通过 HTTPS 访问服务，则需要在服务定义中添加名称`secured`和值`true`的标签或注释，然后负载均衡器将使用 HTTPS 向服务发出请求。

## 11.Kubernetes 内部的安全配置

### 11.1.名称空间

这个项目中提供的大多数组件都需要知道名称空间。对于 Kubernetes（1.3+），命名空间作为服务帐户秘密的一部分提供给 POD，并由客户端自动检测。对于早期版本，需要将其指定为 POD 的环境变量。实现这一点的快速方法如下：

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

### 11.2.服务帐户

对于支持集群中更细粒度的基于角色的访问的 Kubernetes 发行版，你需要确保使用`spring-cloud-kubernetes`运行的 POD 能够访问 Kubernetes API。对于分配给部署或 POD 的任何服务帐户，你需要确保它们具有正确的角色。

根据需求，你将需要`get`、`list`和`watch`对以下资源的权限：

|依赖性|        Resources        |
|----------------------------------------------|-------------------------|
|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   |

出于开发目的，你可以将`cluster-reader`权限添加到你的`default`服务帐户。在生产系统中，你可能希望提供更细粒度的权限。

下面的 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 提供了在应用程序的容器中[将配置图或秘密挂载为卷](https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#add-configmap-data-to-a-volume)的功能。当配置图或秘密的内容发生变化时，[安装的卷将会随着这些变化而更新。](https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#mounted-configmaps-are-updated-automatically)。

然而， Spring 启动不会自动更新这些更改，除非重新启动应用程序。 Spring Cloud提供了在不重新启动应用程序的情况下刷新应用程序上下文的能力，而无需通过点击执行器端点`/refresh`或通过使用 Spring Cloud总线发布`RefreshRemoteApplicationEvent`。

要实现在 Kubernetes 上运行的 Spring Cloud应用程序的这种配置刷新，你可以将 Spring Cloud Kubernetes 配置观察控制器部署到你的 Kubernetes 集群中。

该应用程序作为容器发布，并在[Docker Hub](https://hub.docker.com/r/springcloud/spring-cloud-kubernetes-configuration-watcher)上可用。

Spring Cloud Kubernetes 配置观察者可以通过两种方式向应用程序发送刷新通知。

1. 在 HTTP 上，在这种情况下，被通知的应用程序必须将`/refresh`执行器端点公开并可从集群内访问

2. Spring 使用云总线，在这种情况下，你将需要部署到你的 Custer 的消息代理，以便应用程序使用。

### 13.1.部署 YAML

下面是一个示例部署 YAML，你可以使用它将 Kubernetes 配置监视器部署到 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
```

Spring Cloud Kubernetes 配置要想正常工作，服务帐户和相关的角色绑定是很重要的。控制器需要访问来读取关于 Kubernetes 集群中的配置映射、POD、服务、端点和秘密的数据。

### 13.2.监视配置图和秘密

Spring Cloud Kubernetes Configuration Watcher 将对带有值`true`的标签的`spring.cloud.kubernetes.config`的配置映射中的更改或带有值`true`的标签的`spring.cloud.kubernetes.secret`的任何秘密做出反应。如果配置图或秘密没有这些标签中的任何一个，或者这些标签的值不是`true`，那么任何更改都将被忽略。

Spring Cloud Kubernetes 配置观察者在配置地图上寻找的标签和秘密可以通过分别设置`spring.cloud.kubernetes.configuration.watcher.configLabel`和`spring.cloud.kubernetes.configuration.watcher.secretLabel`来进行更改。

如果对具有有效标签的配置图或秘密进行了更改，则 Spring Cloud Kubernetes 配置观察者将获取配置图或秘密的名称，并向具有该名称的应用程序发送通知。

### 13.3.HTTP 实现

默认情况下使用的是 HTTP 实现。当使用 Spring Cloud Kubernetes 配置监视器并且发生对配置图或秘密的更改时，那么 HTTP 实现将使用 Spring Cloud Kubernetes 发现客户端来获取与配置图或秘密的名称相匹配的应用程序的所有实例并向应用程序的执行器`/refresh`端点发送 HTTP POST 请求。默认情况下，它将使用在发现客户端中注册的端口向`/actuator/refresh`发送 POST 请求。

#### 13.3.1.非默认管理端口和执行器路径

如果应用程序使用非默认的执行器路径和/或为管理端点使用不同的端口，则用于应用程序的 Kubernetes 服务可以添加一个名为`boot.spring.io/actuator`的注释，并将其值设置为应用程序使用的路径和端口。例如

```
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
```

可以选择配置执行器路径和/或管理端口的另一种方式是通过设置`spring.cloud.kubernetes.configuration.watcher.actuatorPath`和`spring.cloud.kubernetes.configuration.watcher.actuatorPort`。

### 13.4.消息传递实现

当 Spring Cloud Kubernetes Configuration Watcher 应用程序部署到 Kubernetes 时，可以通过将配置文件设置为或来启用消息传递实现。

### 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 代理实例的位置。这可以通过设置标准 Spring Kafka 属性来完成，例如

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

## 14. Spring Cloud Kubernetes Config Server

Spring Cloud Kubernetes Config 服务器基于[Spring Cloud Config Server](https://spring.io/projects/spring-cloud-config)，并为 Kubernetes[配置映射](https://kubernetes.io/docs/concepts/configuration/configmap/)和[Secrets](https://kubernetes.io/docs/concepts/configuration/secret/)添加了[环境存储库](https://docs.spring.io/spring-cloud-config/docs/current/reference/html/#_environment_repository)。

这是一个完全可选的组件。然而，它允许你继续利用你在 Kubernetes 上运行的应用程序来利用可能存储在现有环境存储库（Git、SVN、Vault 等）中的配置。

默认映像位于[Docker Hub](https://hub.docker.com/r/springcloud/spring-cloud-kubernetes-configserver)上，这将允许你轻松地获得部署在 Kubernetes 上的配置服务器，而无需自己构建代码和映像。但是，如果你需要自定义配置服务器行为，你可以轻松地从 Github 上的源代码构建自己的映像并使用它。

### 14.1.配置

#### 14.1.1.启用 Kubernetes 环境存储库

要启用 Kubernetes 环境存储库，`kubernetes`配置文件必须包含在活动配置文件列表中。你也可以激活其他配置文件来使用其他环境存储库实现。

#### 14.1.2.配置映射和秘密 PropertySources

默认情况下，将只获取配置映射数据。要启用秘密，还需要设置`spring.cloud.kubernetes.secrets.enableApi=true`。你可以通过设置`spring.cloud.kubernetes.config.enableApi=false`来禁用配置映射`PropertySource`。

#### 14.1.3.从其他名称空间获取配置映射和秘密数据

默认情况下，Kubernetes 环境存储库将仅从部署它的名称空间获取配置映射和秘密。如果希望包括来自其他名称空间的数据，则可以将`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`，则需要包括部署配置服务器的名称空间，以便继续从该名称空间获取配置映射和秘密数据。|
|---|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

#### 14.1.4.Kubernetes 访问控制

Kubernetes 配置服务器使用 Kubernetes API 服务器获取配置映射和秘密数据。为了做到这一点，它需要`get`和`list`配置映射和秘密（取决于你启用/禁用的内容）。

### 14.2.部署 YAML

下面是一个示例部署、服务和权限配置，你可以使用它将基本配置服务器部署到 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 发现服务器提供了应用程序可以用来收集关于 Kubernetes 集群中可用的服务的信息的 HTTP 端点。 Spring Cloud Kubernetes 发现服务器可以由使用`spring-cloud-starter-kubernetes-discoveryclient`的应用程序使用，以向由该启动器提供的`DiscoveryClient`实现提供数据。

### 15.1.权限

Spring Cloud发现服务器使用 Kubernetes API 服务器来获取有关服务和端点重排的数据，因此它需要列表、监视和获得使用这些端点的权限。有关如何在 Kubernetes 上配置服务帐户的示例，请参见下面的示例 Kubernetes Deployment YAML。

### 15.2.端点

服务器公开了三个端点。

#### 15.2.1.`/apps`

发送到`GET`的`/apps`请求将返回可用服务的 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.`/app/{name}`

可以使用对`/app/{name}`的`GET`请求来获取给定服务的所有实例的实例数据。下面是对`GET`请求进行`/app/kubernetes`时的示例响应。

```
[
     {
        "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`请求将返回给定服务的特定实例的实例数据。下面是当`GET`请求被发送到`/app/kubernetes/1234`时的示例响应。

```
 {
    "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.部署 YAML

Spring Cloud发现服务器的图像托管在[Docker Hub](https://hub.docker.com/r/springcloud/spring-cloud-kubernetes-discoveryserver)上。

下面是一个示例部署 YAML，你可以使用它将 Kubernetes 配置监视器部署到 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:2.1.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 发现客户机）的任何其他依赖项。这同样适用于`PropertySourceLocator`，其中你需要将`spring-cloud-kubernetes-config`添加到 Classpath 中，并删除包含`PropertySourceLocator`实现（即配置服务器客户端）的任何其他依赖项。

下面的项目重点介绍了这些依赖关系的用法，并演示了如何从任何 Spring 启动应用程序中使用这些库：

* [Spring Cloud Kubernetes Examples](https://github.com/spring-cloud/spring-cloud-kubernetes/tree/master/spring-cloud-kubernetes-examples):位于此存储库中的那些。

* Spring Cloud Kubernetes 完整示例：小黄人和老板

  * [Minion](https://github.com/salaboy/spring-cloud-k8s-minion)

  * [Boss](https://github.com/salaboy/spring-cloud-k8s-boss)

* Spring Cloud Kubernetes 全例：[Springone 站台售票服务](https://github.com/salaboy/s1p_docs)

* [Spring Cloud Gateway with Spring Cloud Kubernetes Discovery and Config](https://github.com/salaboy/s1p_gateway)

* [Spring Boot Admin with Spring Cloud Kubernetes Discovery and Config](https://github.com/salaboy/showcase-admin-tool)

## 17.其他资源

本节列出了其他资源，例如关于 Spring Cloud Kubernetes 的演示文稿（幻灯片）和视频。

* [S1P Spring Cloud on PKS](https://salaboy.com/2018/09/27/the-s1p-experience/)

* [Spring Cloud, Docker, Kubernetes → London Java Community July 2018](https://salaboy.com/2018/07/18/ljc-july-18-spring-cloud-docker-k8s/)

请随时通过 pull 请求提交其他资源到[这个存储库](https://github.com/spring-cloud/spring-cloud-kubernetes)。

## 18.配置属性

要查看所有 Kubernetes 相关配置属性的列表，请检查[附录页](appendix.html)。

## 19.建筑物

### 19.1.基本编译和测试

要构建源代码，你需要安装 JDK17.

Spring Cloud 在大多数与构建相关的活动中使用 Maven，你应该能够通过克隆感兴趣的项目并键入来很快地开始工作。

```
$ ./mvnw install
```

|   |你也可以自己安装 Maven（\>=3.3.3），并在下面的示例中运行`mvn`命令<br/>来代替`./mvnw`。如果你这样做，那么如果你的本地 Maven 设置不<br/>包含 Spring 预发布工件的存储库声明，那么你可能还需要添加`-P spring`。|
|---|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

|   |请注意，你可能需要通过将<br/>环境变量设置为`-Xmx512m -XX:MaxPermSize=128m`，从而增加 Maven 可用的<br/>内存量。我们试图在<br/>`.mvn`配置中覆盖此内容，因此，如果你发现必须这样做才能使<br/>构建成功，请提出一张票据，以将设置添加到<br/>源代码控制中。|
|---|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

需要中间件（即 Redis）进行测试的项目通常需要安装并运行[Docker]([WWW.docker.com/get-started](https://www.docker.com/get-started)）的本地实例。

### 19.2.文件

Spring-cloud-build 模块有一个“DOCS”配置文件，如果你将其打开，它将尝试从`src/main/asciidoc`构建 ASCIIDoc 源。作为该过程的一部分，它将寻找`README.adoc`，并通过加载所有的包含来处理它，但不是解析或呈现它，只是将其复制到`${main.basedir}`（默认为`$/tmp/releaser-1645122597379-0/spring-cloud-kubernetes/docs`，即项目的根）。如果 README 中有任何更改，那么在构建 Maven 之后，它将在正确的位置显示为经过修改的文件。只要承诺并推动改变就行了。

### 19.3.使用代码

如果你没有 IDE 偏好，我们建议你在使用代码时使用[Spring Tools Suite](https://www.springsource.com/developer/sts)或[Eclipse](https://eclipse.org)。我们使用[m2eclipse](https://eclipse.org/m2e/)Eclipse 插件来提供 Maven 支持。其他 IDE 和工具也应该在没有问题的情况下工作，只要它们使用 Maven 3.3.3 或更好。

#### 19.3.1. Activate the Spring Maven profile

Spring Cloud项目需要激活“ Spring” Maven 配置文件以解析 Spring 里程碑和快照存储库。使用你首选的 IDE 将此配置文件设置为活动的，否则你可能会遇到构建错误。

#### 19.3.2.用 M2Eclipse 导入到 Eclipse 中

在使用 Eclipse 时，我们推荐[m2eclipse](https://eclipse.org/m2e/)Eclipse 插件。如果你还没有安装 M2Eclipse，它可以从“Eclipse 市场”获得。

|   |较早版本的 M2E 不支持 Maven 3.3，因此，一旦<br/>项目导入到 Eclipse 中，你还需要告诉<br/>M2Eclipse 为项目使用正确的配置文件。如果你<br/>在项目中看到许多与 POM 相关的错误，请检查<br/>是否有最新的安装。如果你不能升级 M2E，<br/>将“ Spring”配置文件添加到你的`settings.xml`。或者，你可以<br/>将存储库设置从父<br/> POM 的“ Spring”配置文件复制到你的`settings.xml`中。|
|---| |

#### 19.3.3.在没有 M2Eclipse 的情况下导入 Eclipse

如果不喜欢使用 M2Eclipse，可以使用以下命令生成 Eclipse 项目元数据：

```
$ ./mvnw eclipse:eclipse
```

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

## 20.贡献

Spring Cloud是在非限制性的 Apache2.0 许可下发布的，并遵循非常标准的 GitHub 开发过程，使用 GitHub Tracker 处理问题并将拉请求合并到 Master 中。如果你想贡献一些微不足道的东西，请不要犹豫，但要遵循下面的指导方针。

### 20.1.签署贡献者许可协议

在我们接受一个重要的补丁或拉请求之前，我们需要你签署[贡献者许可协议](https://cla.pivotal.io/sign/spring)。签署贡献者协议并不会授予任何人对主库的提交权限，但这确实意味着我们可以接受你的贡献，并且如果我们接受了，你将获得作者信用。活跃的贡献者可能会被要求加入核心团队，并被赋予合并拉请求的能力。

### 20.2.行为守则

此项目遵守贡献者契约[行为守则](https://github.com/spring-cloud/spring-cloud-build/blob/master/docs/src/main/asciidoc/code-of-conduct.adoc)。通过参与，你将被期望坚持这一准则。请向[[电子邮件保护]]报告不可接受的行为（/cdn-cgi/l/email-protection#D4A7A4A6BDBAB3F9B7BBB0B1F9BBB2F9B7BBBAB0A1B7A7A7A7A9A094A4BDA2BBA0B5B8FABDBB）。

### 20.3.守则惯例和内部管理

这些都不是拉请求所必需的，但它们都会有所帮助。它们也可以在原始的拉请求之后但在合并之前添加。

* 使用 Spring 框架代码格式约定。如果使用 Eclipse，则可以使用`eclipse-code-formatter.xml`文件从[Spring Cloud Build](https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/spring-cloud-dependencies-parent/eclipse-code-formatter.xml)项目导入格式化设置。如果使用 IntelliJ，可以使用[Eclipse 代码格式化插件](https://plugins.jetbrains.com/plugin/6546)导入相同的文件。

* 确保所有新的`.java`文件都有一个简单的 Javadoc 类注释，其中至少有一个`@author`标记来标识你，并且最好至少有一个段落来说明类的用途。

* 将 ASF 许可标头注释添加到所有新的`.java`文件（从项目中的现有文件复制）

* 将自己作为`@author`添加到要进行实质性修改的.java 文件中（不仅仅是外观上的更改）。

* 添加一些 Javadocs，如果你更改了名称空间，还可以添加一些 XSDDOC 元素。

* 几个单元测试也会有很大帮助——必须有人去做。

* 如果没有其他人正在使用你的分支，请将它重新设置为当前的主分支（或主项目中的其他目标分支）。

* 在编写提交消息时，请遵循[这些约定](https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html)，如果你正在修复现有的问题，请在提交消息的末尾添加`Fixes gh-XXXX`（其中 xxxx 是问题编号）。

### 20.4.checkstyle

Spring Cloud构建附带一组 CheckStyle 规则。你可以在`spring-cloud-build-tools`模块中找到它们。该模块下最值得注意的文件是：

Spring-云构建工具/

```
└── src
    ├── checkstyle
    │   └── checkstyle-suppressions.xml (3)
    └── main
        └── resources
            ├── checkstyle-header.txt (2)
            └── checkstyle.xml (1)
```

|**1**|默认的 checkstyle 规则|
|-----|-------------------------|
|**2**|文件头设置|
|**3**|默认抑制规则|

#### 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 错误失败|
|-----|--------------------------------------------------------------------------------------------------------------|
|**2**|构建 checkstyle 冲突失败|
|**3**|CheckStyle 还分析了测试源|
|**4**|添加 Spring Java 格式插件，该插件将重新格式化你的代码，以传递大多数 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 思想

为了设置 IntelliJ，你应该导入我们的编码约定、检查配置文件并设置 CheckStyle 插件。以下文件可以在[Spring Cloud Build](https://github.com/spring-cloud/spring-cloud-build/tree/master/spring-cloud-build-tools)项目中找到。

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**|默认抑制规则|
|**4**|适用大多数 CheckStyle 规则的 IntelliJ 的项目默认值|
|**5**|适用大多数 CheckStyle 规则的 IntelliJ 的项目风格约定|

![Code style](https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/docs/src/main/asciidoc/images/intellij-code-style.png)

图 1.代码样式

转到`File``Settings``Editor``Code 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](https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/docs/src/main/asciidoc/images/intellij-inspections.png)

图 2.检查剖面

转到`File``Settings``Editor``Inspections`。点击`Profile`区域旁边的图标。在那里，单击`Import Profile`并导入`spring-cloud-build-tools/src/main/resources/intellij/Intellij_Project_Defaults.xml`文件。

checkstyle

要让 IntelliJ 使用 CheckStyle，你必须安装`Checkstyle`插件。建议还安装`Assertions2Assertj`来自动转换 JUnit 断言

![Checkstyle](https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/docs/src/main/asciidoc/images/intellij-checkstyle.png)

转到`File``Settings``Other settings``Checkstyle`。点击`Configuration file`部分中的`+`图标。在这里，你必须定义应该从哪里选择 CheckStyle 规则。在上面的图片中，我们从克隆的 Spring Cloud构建存储库中选择了规则。但是，你可以指向 Spring Cloud Build 的 GitHub 存储库（例如`checkstyle.xml`:`[raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/spring-cloud-build-tools/src/main/resources/checkstyle.xml](https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/spring-cloud-build-tools/src/main/resources/checkstyle.xml)`）。我们需要提供以下变量：

* `checkstyle.header.file`-请将其指向 Spring Cloud Build 的`spring-cloud-build-tools/src/main/resources/checkstyle-header.txt`文件，可以在你的克隆 repo 中，也可以通过`[raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/spring-cloud-build-tools/src/main/resources/checkstyle-header.txt](https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/spring-cloud-build-tools/src/main/resources/checkstyle-header.txt)`URL。

* `checkstyle.suppressions.file`-默认抑制。请将它指向 Spring Cloud build 的`spring-cloud-build-tools/src/checkstyle/checkstyle-suppressions.xml`文件，或者在你的克隆 repo 中，或者通过`[raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/spring-cloud-build-tools/src/checkstyle/checkstyle-suppressions.xml](https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/spring-cloud-build-tools/src/checkstyle/checkstyle-suppressions.xml)`URL。

* `checkstyle.additional.suppressions.file`-此变量对应于本地项目中的抑制。例如，你正在处理`spring-cloud-contract`。然后指向`project-root/src/checkstyle/checkstyle-suppressions.xml`文件夹。`spring-cloud-contract`的例子是：`/home/username/spring-cloud-contract/src/checkstyle/checkstyle-suppressions.xml`。

|   |请记住将`Scan Scope`设置为`All sources`，因为我们为生产和测试源应用了 checkstyle 规则。|
|---|------------------------------------------------------------------------------------------------------------------|

### 20.6.重复查找器

Spring Cloud构建带来了`basepom:duplicate-finder-maven-plugin`，这使得能够在 Java Classpath 上标记重复的和冲突的类和资源。

#### 20.6.1.重复查找器配置

重复查找器是**默认启用**，将在 Maven 构建的`verify`阶段运行，但是只有在项目的`duplicate-finder-maven-plugin`部分中添加`duplicate-finder-maven-plugin`，它才会在项目中生效。

POM.xml

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

对于其他属性，我们设置了[插件文档](https://github.com/basepom/duplicate-finder-maven-plugin/wiki)中列出的默认值。

你可以轻松地重写它们，但可以使用`duplicate-finder-maven-plugin`前缀设置所选属性的值。例如，将`duplicate-finder-maven-plugin.skip`设置为`true`，以便在构建中跳过重复检查。

如果需要将`ignoredClassPatterns`或`ignoredResourcePatterns`添加到设置中，请确保将它们添加到项目的插件配置部分中：

```
<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>
```