Spring Cloud Kubernetes Configuration Watcher

Kubernetes 提供了在您应用程序的容器中 mount a ConfigMap or Secret as a volume 的能力。当 ConfigMap 或 Secret 的内容更改时, mounted volume will be updated with those changes

Kubernetes provides the ability to mount a ConfigMap or Secret as a volume in the container of your application. When the contents of the ConfigMap or Secret changes, the mounted volume will be updated with those changes.

然而,在您重启应用程序之前,Spring Boot 不会自动更新这些更改。Spring Cloud 提供通过点击 actuator 端点 /refresh 或通过使用 Spring Cloud Bus 发布`RefreshRemoteApplicationEvent` 来刷新应用程序上下文而不重启应用程序的能力。

However, Spring Boot will not automatically update those changes unless you restart the application. Spring Cloud provides the ability refresh the application context without restarting the application by either hitting the actuator endpoint /refresh or via publishing a RefreshRemoteApplicationEvent using Spring Cloud Bus.

若要在 Kubernetes 上运行的 Spring Cloud 应用程序中实现此配置刷新,您可以向 Kubernetes 集群中部署 Spring Cloud Kubernetes Configuration Watcher 控制器。

To achieve this configuration refresh of a Spring Cloud app running on Kubernetes, you can deploy the Spring Cloud Kubernetes Configuration Watcher controller into your Kubernetes cluster.

该应用程序发布为一个容器,并且在 Docker Hub 中可用。但是,如果您需要自定义配置监视程序行为或希望自己构建该映像,那么您可以轻松地从 source code on GitHub 构建自己的映像并使用该映像。

The application is published as a container and is available on Docker Hub. However, if you need to customize the config watcher behavior or prefer to build the image yourself you can easily build your own image from the source code on GitHub and use that.

配置它的另一个选择是在用于部署配置 watcher 的 deployment.yaml 中提供一些环境变量。以下是其中一些重要的变量:

Another option to configure it is to provide some environment variables in the deployment.yaml used to deploy configuration watcher. Here are some important ones:

env:
  - name: LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_CONFIGURATION_WATCHER
    value: DEBUG
  - name: LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_CLIENT_CONFIG_RELOAD
    value: DEBUG
  - name: LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_COMMONS_CONFIG_RELOAD
    value: DEBUG

这些变量将启用配置 watcher 上的调试日志记录,并且在初始设置中特别有用,以便诊断潜在的错误配置。

These enable debug logging on the configuration watcher and are particular useful on the initial set-up, to be able to diagnose potential miss-configurations.

env:
  - name: SPRING_CLOUD_KUBERNETES_RELOAD_NAMESPACES_0
    value: "namespace-a"

这一选项让监视程序知道到哪里查找秘密和 ConfigMap。您在此处有两个选项:选择性命名空间(上面的设置)和由 Namespace Resolution 选择的命名空间(这是默认选项)。请记住,所有这些选项都需要适当的 RBAC 规则。

This one lets watcher know where to search for secrets and configmaps. You have two options here: selective namespaces (the setting above) and a namespace chosen by Namespace Resolution (this is the default option). Keep in mind that all these options require proper RBAC rules.

configmap/secret 中的更改将仅在特定更改来自标签为:spring.cloud.kubernetes.config=truespring.cloud.kubernetes.secret=true 的源的情况下触发配置 watcher 发出事件。

Changes from configmaps/secrets will only trigger an event being fired from configuration watcher if that particular change came from a source that has a label: spring.cloud.kubernetes.config=true or spring.cloud.kubernetes.secret=true.

简而言之,如果您更改了一个 configmap(或 secret),它 具有上述标签,配置 watcher 将跳过为其触发事件(如果您启用了调试日志记录,这将在日志中显示)。

To put it simpler, if you change a configmap (or secret), that does not have the label above, configuration watcher will skip firing an event for it (if you enabled debug logging, this will be visible in logs).

默认情况下,配置 watcher 将监视配置命名空间中所有 configmap/secret。如果您希望仅过滤以监视特定源,您可以通过设置以下来实现:

By default, configuration watcher will monitor all configmaps/secrets in the configured namespace(s). If you want to filter to watch only particular sources, you can do that by setting:

SPRING_CLOUD_KUBERNETES_CONFIG_INFORMER_ENABLED=TRUE

这将告诉 watcher 仅监视具有标签:spring.cloud.kubernetes.config.informer.enabled=true 的源。

This will tell watcher to only monitor sources that have a label: spring.cloud.kubernetes.config.informer.enabled=true.

另一项重要的配置,特别是对于作为存储卷挂载(通过 spring.cloud.kubernetes.config.paths/spring.cloud.kubernetes.secrets.paths 或使用 spring.config.import)的 configmap 和 secret,是:

One more important configuration, especially for configmaps and secrets that are mounted as volumes (via spring.cloud.kubernetes.config.paths/spring.cloud.kubernetes.secrets.paths or using spring.config.import) is:

- name: SPRING_CLOUD_KUBERNETES_CONFIGURATION_WATCHER_REFRESHDELAY
  value: "10000"

这表示在从配置 watcher 发出事件之前我们应该等待多少毫秒。这非常重要,因为 kubernetes 文档说:

This tells how many milliseconds should we wait before firing the event from configuration watcher. This is important because kubernetes documentation says:

当前在存储卷中使用的 ConfigMap 更新后,最终也会更新投影的键。

When a ConfigMap currently consumed in a volume is updated, projected keys are eventually updated as well.

您需要将这个 eventually 部分“匹配”到集群中的该毫秒值。

You need to "match" this eventually part to that value in milliseconds on your cluster.

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

Spring Cloud Kubernetes Configuration Watcher can send refresh notifications to applications in two ways.

  1. 通过 HTTP,在这种情况下,正在通知的应用程序必须具有在集群内部公开且可访问的 /refresh actuator 端点

  2. Over HTTP, in which case the application being notified, must have the /refresh actuator endpoint exposed and accessible from within the cluster

  3. 使用 Spring Cloud Bus,在这种情况下,需要为应用程序部署到主机中一个消息代理。

  4. Using Spring Cloud Bus, in which case you will need a message broker deployed to your custer for the application to use.

Deployment YAML

以下是样本部署 YAML,您可以使用它将 Kubernetes Configuration Watcher 部署到 Kubernetes。

Below is a sample deployment YAML you can use to deploy the Kubernetes Configuration Watcher to 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:{spring-cloud-version}
            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 集群中 ConfigMap、Pod、服务、端点和 Secret 的数据。

The Service Account and associated Role Binding is important for Spring Cloud Kubernetes Configuration to work properly. The controller needs access to read data about ConfigMaps, Pods, Services, Endpoints and Secrets in the Kubernetes cluster.

Monitoring ConfigMaps and Secrets

如果对带有有效标签的 ConfigMap 或 Secret 进行更改(如上文所述),那么 Spring Cloud Kubernetes Configuration Watcher 将获取 ConfigMap 或 Secret 的名称,并向具有该名称的应用程序发送通知。这可能不足以满足您的用例,例如,您可能希望:

If a change is made to a ConfigMap or Secret with valid labels (as detailed above), then Spring Cloud Kubernetes Configuration Watcher will take the name of the ConfigMap or Secret and send a notification to the application with that name. This might not be enough for your use-case though, you could for example want to:

  • 将 ConfigMap 绑定到多个应用程序,以便单个 ConfigMap 中的更改触发多个服务的刷新

  • bind a config-map to multiple applications, so that a change inside a single configmap triggers a refresh for many services

  • 让基于配置文件的源触发应用程序的事件

  • have profile based sources trigger events for your application

由于这个原因,您还可以指定附加注释:

For that reasons there is an addition annotation you could specify:

spring.cloud.kubernetes.configmap.appsspring.cloud.kubernetes.secret.apps。它获取以逗号分隔的应用字符串,该字符串指定在该 secret/configmap 中发生更改时将收到通知的应用程序的名称。

spring.cloud.kubernetes.configmap.apps or spring.cloud.kubernetes.secret.apps. It takes a String of apps separated by comma, that specifies the names of applications that will receive a notification when changes happen in this secret/configmap.

例如:

For example:

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

HTTP Implementation

HTTP 实现是默认使用的实现。当使用此实现时,如果 Spring Cloud Kubernetes Configuration Watcher 发生更改到 ConfigMap 或 Secret,那么 HTTP 实现将使用 Spring Cloud Kubernetes Discovery Client 获取与 ConfigMap 或 Secret 名称匹配的所有应用程序实例,并向应用程序的执行器“/refresh”端点发送 HTTP POST 请求。默认情况下,它将使用在发现客户端中注册的端口,向 /actuator/refresh 发送 post 请求。

The HTTP implementation is what is used by default. When this implementation is used, Spring Cloud Kubernetes Configuration Watcher and a change to a ConfigMap or Secret occurs then the HTTP implementation will use the Spring Cloud Kubernetes Discovery Client to fetch all instances of the application which match the name of the ConfigMap or Secret and send an HTTP POST request to the application’s actuator /refresh endpoint. By default, it will send the post request to /actuator/refresh using the port registered in the discovery client.

Non-Default Management Port and Actuator Path

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

If the application is using a non-default actuator path and/or using a different port for the management endpoints, the Kubernetes service for the application can add an annotation called boot.spring.io/actuator and set its value to the path and port used by the application. For example

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.actuatorPathspring.cloud.kubernetes.configuration.watcher.actuatorPort

Another way you can choose to configure the actuator path and/or management port is by setting spring.cloud.kubernetes.configuration.watcher.actuatorPath and spring.cloud.kubernetes.configuration.watcher.actuatorPort.

Messaging Implementation

当在 Kubernetes 中部署 Spring Cloud Kubernetes Configuration Watcher 应用程序时,可以通过将概要文件设置为 bus-amqp(RabbitMQ)或 bus-kafka(Kafka)来启用消息传递实施。

The messaging implementation can be enabled by setting profile to either bus-amqp (RabbitMQ) or bus-kafka (Kafka) when the Spring Cloud Kubernetes Configuration Watcher application is deployed to Kubernetes.

Configuring RabbitMQ

启用 bus-amqp 概要文件时,您将需要配置 Spring RabbitMQ,将其指向要使用的 RabbitMQ 实例以及进行身份验证所需的任何凭据。可以通过设置标准的 Spring RabbitMQ 属性来执行此操作,例如

When the bus-amqp profile is enabled you will need to configure Spring RabbitMQ to point it to the location of the RabbitMQ instance you would like to use as well as any credentials necessary to authenticate. This can be done by setting the standard Spring RabbitMQ properties, for example

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

Configuring Kafka

启用 bus-kafka 概要文件时,您将需要配置 Spring Kafka,将其指向要使用的 Kafka Broker 实例。可以通过设置标准的 Spring Kafka 属性来执行此操作,例如

When the bus-kafka profile is enabled you will need to configure Spring Kafka to point it to the location of the Kafka Broker instance you would like to use. This can be done by setting the standard Spring Kafka properties, for example

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