【容器平台】Spring Cloud Kubernetes 介绍

1.为什么需要Spring Cloud Kubernetes?


Spring Cloud Kubernetes提供Spring Cloud通用接口实现,以使用Kubernetes本机服务。此存储库中提供的项目的主要目标是促进Kubernetes中运行的Spring Cloud / Spring Boot应用程序的集成。

2.适用于Kubernetes的DiscoveryClient


该项目为Kubernetes提供Discovery Client的实现。这允许您按名称查询Kubernetes端点(请参阅服务)。服务通常由Kubernetes API服务器作为端点集合公开,这些端点表示客户端可以从作为pod运行的Spring Boot应用程序访问的http,https地址。 Spring Cloud Kubernetes功能区项目还使用此发现功能来获取为要负载平衡的应用程序定义的端点列表。

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

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-kubernetes</artifactId>
    <version>${latest.version}</version>
</dependency>


要启用DiscoveryClient的加载,请将@EnableDiscoveryClient添加到相应的配置或应用程序类,如下所示:

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


然后,您可以通过以下方式将客户端注入代码:

@Autowired
private DiscoveryClient discoveryClient;


如果由于任何原因需要禁用DiscoveryClient,您只需在application.properties中设置以下属性:

spring.cloud.kubernetes.discovery.enabled=false


一些Spring Cloud组件使用DiscoveryClient来获取有关本地服务实例的信息。为此,您需要将Kubernetes服务名称与spring.application.name属性对齐。

3. Kubernetes PropertySource实现


配置Spring Boot应用程序的最常用方法是创建application.properties | yaml或application-profile.properties | yaml文件,其中包含为应用程序或Spring Boot启动程序提供自定义值的键值对。用户可以通过指定系统属性或环境变量来覆盖这些属性。

3.1 ConfigMap PropertySource


Kubernetes提供了一个名为ConfigMap的资源,用于外化参数,以键值对或嵌入式application.properties | yaml文件的形式传递给您的应用程序。 Spring Cloud Kubernetes Config项目在应用程序引导期间使Kubernetes`ConfigMap可用,并在观察到的`ConfigMap`s上检测到更改时触发bean或Spring上下文的热重新加载。

默认行为是基于Kubernetes ConfigMap创建一个ConfigMapPropertySource,它具有您的Spring应用程序名称(由其spring.application.name属性定义)或在bootstrap.properties文件中定义的自定义名称的metadata.name。以下键是spring.cloud.kubernetes.config.name。

但是,可以使用多个ConfigMaps进行更高级的配置。这可以通过spring.cloud.kubernetes.config.sources列表实现。例如,可以定义以下ConfigMaps

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


在上面的示例中,尚未设置spring.cloud.kubernetes.config.namespace,然后将在应用程序运行的命名空间中查找名为c1的ConfigMap

找到的任何匹配的ConfigMap将按如下方式处理:

应用单个配置属性。
作为yaml应用名为application.yaml的任何属性的内容
将属性文件作为属性文件应用于名为application.properties的任何属性的内容
上述流程的唯一例外是ConfigMap包含指示文件是YAML或属性文件的单个密钥。在这种情况下,密钥的名称不必是application.yaml或application.properties(它可以是任何东西),并且将正确处理属性的值。此功能有助于使用以下内容创建ConfigMap的用例:

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

例:

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

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:

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


以下也有效:

The following also works:

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


Spring Boot应用程序也可以根据活动配置文件进行不同的配置,这些配置文件将在读取ConfigMap时合并在一起。可以使用application.properties | 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

如果两个配置文件都处于活动状态,则configmap中最后显示的属性将覆盖先前的值。

要告诉Spring Boot应该在bootstrap启用哪个配置文件,可以使用您将使用OpenShift DeploymentConfig或Kubernetes ReplicationConfig资源文件定义的env变量将系统属性传递给启动Spring Boot应用程序的Java命令,如下所示:

apiVersion: v1
kind: DeploymentConfig
spec:
  replicas: 1
  ...
    spec:
      containers:
      - env:
        - name: JAVA_APP_DIR
          value: /deployments
        - name: JAVA_OPTIONS
          value: -Dspring.profiles.active=developer

注意: - 检查安全配置部分,从pod内部访问配置映射,您需要拥有正确的Kubernetes服务帐户,角色和角色绑定。

表3.1。属性:

3.1

3.2 密码PropertySource


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

启用S​​ecretsPropertySource时,将从以下来源查找Kubernetes for Secrets:

  • 1。从秘密装载中递归读取
  • 2。以应用程序命名(由spring.application.name定义)
  • 3。匹配某些标签

请注意,默认情况下,出于安全原因,未启用通过API(上面的第2点和第3点)使用Secrets,并建议容器通过已安装的卷共享机密。否则,必须提供正确的RBAC安全配置,以确保发生对Secrets的未授权访问。

如果发现了秘密,则他们的数据可供应用程序使用。

例:

假设我们有一个名为demo的spring启动应用程序,它使用属性来读取其数据库配置。我们可以使用以下命令创建Kubernetes秘密:

oc create secret泛型db-secret --from-literal = username = user --from-literal = password = p455w0rd
这将创建以下秘密(使用oc 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编码版本。

然后,您的应用程序可以使用此秘密,例如将秘密的值导出为环境变量:

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


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

通过列出秘密被映射的目录:`-Dspring.cloud.kubernetes.secrets.paths = / etc / secrets / db-secret,etc / secrets / postgresql`

如果您将所有秘密映射到公共根,则可以将它们设置为:

If you have all the secrets mapped to a common root, you can set them like:
```
-Dspring.cloud.kubernetes.secrets.paths=/etc/secrets


通过设置一个命名密码:` -Dspring.cloud.kubernetes.secrets.name=db-secret `
通过定义标签列表:` -Dspring.cloud.kubernetes.secrets.labels.broker=activemq -Dspring.cloud.kubernetes.secrets.labels.db=postgresql `


表3.2。属性:

 

3.2
注意: - 属性spring.cloud.kubernetes.secrets.labels的行为与基于Map的绑定相同。 - 属性spring.cloud.kubernetes.secrets.paths的行为与基于Collection的绑定一样。 - 出于安全原因,可能会限制通过API访问机密,首选方法是将密码安装到POD。

使用秘密的应用程序示例(虽然它尚未更新为使用新的spring-cloud-kubernetes项目):spring-boot-camel-config

 

 

3.3 PropertySource Reload


某些应用程序可能需要检测外部属性源的更改并更新其内部状态以反映新配置。当相关的ConfigMap或Secret更改时,Spring Cloud Kubernetes的重新加载功能可以触发应用程序重新加载。

默认情况下禁用此功能,可以使用配置属性spring.cloud.kubernetes.reload.enabled = true启用此功能(例如,在application.properties文件中)。

支持以下级别的重新加载(属性spring.cloud.kubernetes.reload.strategy): -  refresh(默认值):仅重新加载使用@ConfigurationProperties或@RefreshScope注释的配置Bean。此重新加载级别利用Spring Cloud Context的刷新功能。 -  restart_context:正常重启整个Spring ApplicationContext。使用新配置重新创建Bean。 -  shutdown:关闭Spring ApplicationContext以激活容器的重启。使用此级别时,请确保所有非守护程序线程的生命周期都绑定到ApplicationContext,并且复制控制器或副本集配置为重新启动Pod。

例:

假设使用默认设置(刷新模式)启用了重新加载功能,则在配置映射更改时将刷新以下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注释的前缀字段定义的值的属性相关联的更改,并将其反映在应用程序中。 [ConfigMap与pod关联](#configmap-propertysource)如上所述。

完整示例可在[spring-cloud-kubernetes-reload-example]中找到(spring-cloud-kubernetes-examples / kubernetes-reload-example)。

重新加载功能支持两种操作模式: - 事件(默认):使用Kubernetes API(Web套接字)监视配置映射或机密中的更改。任何事件都会对配置进行重新检查,并在发生更改时重新加载。需要服务帐户上的视图角色才能侦听配置映射更改。秘密需要更高级别的角色(例如编辑)(默认情况下不监控秘密)。 - 轮询:从配置映射和秘密中定期重新创建配置,以查看它是否已更改。可以使用属性spring.cloud.kubernetes.reload.period配置轮询周期,默认为15秒。它需要与受监视属性源相同的角色。这意味着,例如,在文件安装的秘密源上使用轮询不需要特定的权限。

表3.3。属性:

3.3


注意: -  spring.cloud.kubernetes.reload下的属性。不应该在配置映射或秘密中使用:在运行时更改此类属性可能会导致意外结果; - 使用刷新级别时,删除属性或整个配置映射不会还原Bean的原始状态。

4. Ribbon discovery in Kubernetes


调用微服务的Spring Cloud客户端应用程序应该对依赖客户端负载平衡功能感兴趣,以便自动发现它可以到达给定服务的端点。此机制已在[spring-cloud-kubernetes-ribbon](spring-cloud-kubernetes-ribbon / pom.xml)项目中实现,其中Kubernetes客户端将填充包含有关此类端点的信息的Ribbon ServerList。

该实现是以下启动器的一部分,您可以通过将其依赖项添加到您的pom文件来使用它:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-kubernetes-ribbon</artifactId>
    <version>${latest.version}</version>
</dependency>


填充端点列表后,Kubernetes客户端将搜索生成在当前命名空间/项目中的已注册端点,这些端点与使用Ribbon Client注释定义的服务名称相匹配:

@RibbonClient(name =“name-service”)
您可以通过使用以下格式在application.properties中提供属性(通过应用程序的专用ConfigMap)来配置功能区的行为:<服务名称> .ribbon。<name of your service>.ribbon.<Ribbon configuration key> 其中:

<name of your service> 对应于您通过功能区访问的服务名称,使用@RibbonClient注释进行配置(例如,上例中的名称服务)
<功能区配置键>是功能区的CommonClientConfigKey类定义的功能区配置键之一
此外,spring-cloud-kubernetes-ribbon项目定义了两个额外的配置键,以进一步控制Ribbon与Kubernetes的交互方式。特别是,如果端点定义了多个端口,则默认行为是使用找到的第一个端口。要更具体地选择要使用的端口,请在多端口服务中使用PortName项。如果要指定应在哪个Kubernetes命名空间中查找目标服务,请使用KubernetesNamespace键,记住在这两个实例中为这些键添加前面指定的服务名称和功能区前缀。

使用此模块进行功能区发现的示例包括:


注意:可以通过在应用程序属性文件spring.cloud.kubernetes.ribbon.enabled = false中设置此键来禁用功能区发现客户端。

5. Kubernetes感知


无论您的应用程序是否在Kubernetes内部运行,上述所有功能都将同样有效。这对开发和故障排除非常有用。从开发的角度来看,这非常有用,因为您可以启动Spring Boot应用程序并调试此项目的一个模块部分。它不需要在Kubernetes中部署它,因为项目的代码依赖于[Fabric8 Kubernetes Java客户端](https://github.com/fabric8io/kubernetes-client),这是一个流畅的DSL,能够使用http协议进行通信到Kubernetes Server的REST API。

5.1 Kubernetes配置文件自动配置
当应用程序作为Kubernetes内的pod运行时,名为kubernetes的Spring配置文件将自动激活。这允许开发人员定制配置,以定义在Kubernetes平台中部署Spring Boot应用程序时将应用的bean(例如,不同的dev和prod配置)。

6.Pod 健康指标


Spring Boot使用HealthIndicator来公开有关应用程序运行状况的信息。这使得向用户公开健康相关信息非常有用,也非常适合用作准备探针。

作为核心模块一部分的Kubernetes运行状况指示器公开以下信息:

pod名称,IP地址,名称空间,服务帐户,节点名称及其IP地址
指示Spring Boot应用程序是Kubernetes内部还是外部的标志

7.领导人选举


<TBD>

8. Kubernetes内部的安全配置


8.1命名空间


此项目中提供的大多数组件都需要知道命名空间。对于Kubernetes(1.3+),命名空间可作为服务帐户机密的一部分提供给pod,并由客户端自动检测。对于早期版本,需要将其指定为pod的env var。一个快速的方法是:

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


8.2服务帐户
对于支持集群内更细粒度的基于角色的访问的Kubernetes发行版,您需要确保使用spring-cloud-kubernetes运行的pod可以访问Kubernetes API。对于您分配给部署/窗格的任何服务帐户,您需要确保它具有正确的角色。例如,您可以根据您所在的项目将群集阅读器权限添加到默认服务帐户:

9.例子


Spring Cloud Kubernetes尝试使您的应用程序透明化,以便在Spring Cloud界面之后使用Kubernetes Native Services。

在您的应用程序中,您需要将spring-cloud-kubernetes-discovery依赖项添加到类路径中,并删除包含DiscoveryClient实现的任何其他依赖项(即Eureka Discovery Client)。这同样适用于PropertySourceLocator,您需要在其中向spring-cloud-kubernetes-config添加类路径并删除包含PropertySourceLocator实现的任何其他依赖项(即Config Server Client)。

以下项目重点介绍了这些依赖项的用法,并演示了如何在任何Spring Boot应用程序中使用这些库。

使用这些项目的示例列表:


10.其他资源


在这里,您可以找到其他资源,如演示文稿(幻灯片)和有关Spring Cloud Kubernetes的视频。


请随意通过PR向此存储库提交其他资源。

11.构建


11.1基本编译和测试


要构建源代码,您需要安装JDK 1.7。

Spring Cloud使用Maven进行大多数与构建相关的活动,您应该能够通过克隆您感兴趣的项目并键入来快速实现

$ ./mvnw安装
[注意]
您也可以自己安装Maven(> = 3.3.3)并在下面的示例中运行mvn命令代替./mvnw。如果这样做,如果本地Maven设置不包含spring pre-release工件的存储库声明,则可能还需要添加-P spring。

[注意]
请注意,您可能需要通过设置MAVEN_OPTS环境变量来增加Maven可用的内存量,其值为-Xmx512m -XX:MaxPermSize = 128m。我们尝试在.mvn配置中介绍这一点,因此如果您发现必须这样做以使构建成功,请提出一个票证以将设置添加到源代码管理中。

有关如何构建项目的提示,请查看.travis.yml(如果有)。应该有一个“脚本”,也许是“安装”命令。另请查看“服务”部分,了解是否需要在本地运行任何服务(例如mongo或rabbit)。忽略您在“before_install”中可能找到的与git相关的位,因为它们与设置git凭据有关,而您已经拥有这些位。

需要中间件的项目通常包括docker-compose.yml,因此请考虑使用Docker Compose在Docker容器中运行middeware服务器。有关mongo,rabbit和redis常见情况的具体说明,请参阅脚本演示存储库中的README。

[注意]
如果所有其他方法都失败了,请使用.travis.yml命令(通常为./mvnw install)进行构建。

11.2文件


spring-cloud-build模块有一个“docs”配置文件,如果你切换它,它将尝试从src / main / asciidoc构建asciidoc源代码。作为该过程的一部分,它将查找README.adoc并通过加载所有包含来处理它,但不解析或呈现它,只需将其复制到$ {main.basedir}(默认为$ {basedir},即根目录该项目)。如果README中有任何更改,它将在Maven构建后显示为正确位置的修改文件。提交它并推动变革。

11.3使用代码


如果您没有IDE首选项,我们建议您在使用代码时使用Spring Tools Suite或Eclipse。我们使用m2eclipse eclipse插件来支持maven。只要他们使用Maven 3.3.3或更高版本,其他IDE和工具也应该没有问题。

11.3.1使用m2eclipse导入eclipse
在使用eclipse时,我们建议使用m2eclipse eclipse插件。如果您还没有安装m2eclipse,可以从“eclipse marketplace”获得。

[注意]
较旧版本的m2e不支持Maven 3.3,因此一旦将项目导入Eclipse,您还需要告诉m2eclipse使用正确的项目配置文件。如果您在项目中看到与POM相关的许多不同错误,请检查您是否具有最新安装。如果无法升级m2e,请将“spring”配置文件添加到settings.xml。或者,您可以将存储库设置从父pom的“spring”配置文件复制到settings.xml中。

11.3.2在没有m2eclipse的情况下导入eclipse
如果您不想使用m2eclipse,可以使用以下命令生成eclipse项目元数据:

$ ./mvnw eclipse:eclipse
可以通过从文件菜单中选择导入现有项目来导入生成的eclipse项目。

12.贡献


Spring Cloud是在非限制性Apache 2.0许可下发布的,遵循非常标准的Github开发过程,使用Github跟踪器解决问题并将拉取请求合并到master中。如果您想贡献一些微不足道的东西,请不要犹豫,但请遵循以下指南。

12.1签署贡献者许可协议


在我们接受非平凡补丁或拉取请求之前,我们需要您签署“贡献者许可协议”。签署贡献者的协议不会授予任何人对主存储库的承诺权,但它确实意味着我们可以接受您的贡献,如果我们这样做,您将获得作者信用。可能会要求活跃的贡献者加入核心团队,并且能够合并拉取请求。

12.2行为准则


该项目遵守“贡献者公约”行为准则。通过参与,您应该支持此代码。请向spring-code-of-conduct@pivotal.io报告不可接受的行为。

12.3规范约定和内务管理


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

使用Spring Framework代码格式约定。如果使用Eclipse,则可以使用Spring Cloud Build项目中的eclipse-code-formatter.xml文件导入格式化程序设置。如果使用IntelliJ,则可以使用Eclipse Code Formatter Plugin导入同一文件。
确保所有新的.java文件都有一个简单的Javadoc类注释,至少有一个标识你的@author标记,最好至少有一个关于该类的内容的段落。
将ASF许可证头注释添加到所有新的.java文件(从项目中的现有文件复制)
将您自己作为@author添加到您实际修改的.java文件中(超过整容更改)。
添加一些Javadoc,如果更改名称空间,则添加一些XSD doc元素。
一些单元测试也会有很多帮助 - 有人必须这样做。
如果没有其他人使用您的分支,请将其重新绑定到当前主服务器(或主项目中的其他目标分支)。
在编写提交消息时,请遵循这些约定,如果要解决现有问题,请在提交消息末尾添加修复gh-XXXX(其中XXXX是问题编号)。

 

原文 :https://cloud.spring.io/spring-cloud-static/spring-cloud-kubernetes/2.1.0.RC1/single/spring-cloud-kubernetes.html