Spring Cloud Kubernetes 配置觀察器

Kubernetes 提供了將 ConfigMap 或 Secret 掛載為應用程式容器中的卷的能力。當 ConfigMap 或 Secret 的內容發生變化時,掛載的卷將隨之更新。

然而,除非重啟應用程式,否則 Spring Boot 不會自動更新這些變化。Spring Cloud 提供了無需重啟應用即可重新整理應用上下文的能力,可以透過訪問 /refresh actuator 端點或使用 Spring Cloud Bus 釋出 RefreshRemoteApplicationEvent 來實現。

為了在 Kubernetes 上執行的 Spring Cloud 應用中實現此配置重新整理,您可以將 Spring Cloud Kubernetes Configuration Watcher 控制器部署到您的 Kubernetes 叢集中。

該應用作為容器釋出,可在 Docker Hub 上獲取。但是,如果您需要自定義配置觀察器行為或更喜歡自己構建映象,您可以輕鬆地從 GitHub 上的原始碼構建自己的映象並使用。

配置它的另一種選擇是在用於部署配置觀察器的 deployment.yaml 中提供一些環境變數。以下是一些重要的變數:

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

這些變數用於啟用配置觀察器的除錯日誌記錄,在初始設定時特別有用,以便診斷潛在的配置錯誤。

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

此變數讓觀察器知道在哪裡搜尋 secrets 和 configmaps。這裡有兩種選擇:選擇性名稱空間(上面的設定)和透過名稱空間解析(Namespace Resolution)選擇的名稱空間(這是預設選項)。請記住,所有這些選項都需要適當的 RBAC 規則。

configmaps/secrets 的更改只有在其來源於帶有以下標籤的源時,才會觸發配置觀察器發出事件:spring.cloud.kubernetes.config=truespring.cloud.kubernetes.secret=true

簡單來說,如果您更改了一個沒有上述標籤的 configmap(或 secret),配置觀察器將跳過為此更改觸發事件(如果您啟用了除錯日誌記錄,這將在日誌中可見)。

預設情況下,配置觀察器將監控配置的名稱空間中的所有 configmaps/secrets。如果您想過濾只監控特定的源,可以透過設定以下變數實現:

SPRING_CLOUD_KUBERNETES_CONFIG_INFORMER_ENABLED=TRUE

這將告訴觀察器只監控帶有標籤:spring.cloud.kubernetes.config.informer.enabled=true 的源。

另一個重要的配置,特別是對於作為卷掛載的 configmaps 和 secrets(透過 spring.cloud.kubernetes.config.paths/spring.cloud.kubernetes.secrets.paths 或使用 spring.config.import),是

- name: SPRING_CLOUD_KUBERNETES_CONFIGURATION_WATCHER_REFRESHDELAY
  value: "10000"

這指定了在配置觀察器觸發事件之前應該等待多少毫秒。這很重要,因為 Kubernetes 文件提到

當卷中當前使用的 ConfigMap 更新時,投影的鍵也會最終更新。

您需要將這個“最終”的部分與叢集中該值的毫秒數“匹配”。

Spring Cloud Kubernetes Configuration Watcher 可以透過兩種方式嚮應用傳送重新整理通知。

  1. 透過 HTTP,在這種情況下,被通知的應用必須暴露 /refresh actuator 端點,並且可以從叢集內部訪問。

  2. 使用 Spring Cloud Bus,在這種情況下,您需要在叢集中部署一個訊息代理供應用使用。

部署 YAML

下面是一個您可以用來將 Kubernetes Configuration Watcher 部署到 Kubernetes 的示例部署 YAML。

---
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:3.2.1
            imagePullPolicy: IfNotPresent
            readinessProbe:
              httpGet:
                port: 8888
                path: /actuator/health/readiness
            livenessProbe:
              httpGet:
                port: 8888
                path: /actuator/health/liveness
            ports:
            - containerPort: 8888

Service Account 和相關的 Role Binding 對於 Spring Cloud Kubernetes Configuration 的正常工作很重要。控制器需要訪問許可權來讀取 Kubernetes 叢集中的 ConfigMaps、Pods、Services、Endpoints 和 Secrets 的資料。

監控 ConfigMaps 和 Secrets

如果對帶有有效標籤(如上所述)的 ConfigMap 或 Secret 進行了更改,則 Spring Cloud Kubernetes Configuration Watcher 將獲取該 ConfigMap 或 Secret 的名稱,並向同名應用傳送通知。但這可能不足以滿足您的用例,例如,您可能希望

  • 將一個 config-map 繫結到多個應用,以便單個 configmap 內的更改能觸發多個服務的重新整理

  • 讓基於配置檔案的源為您的應用觸發事件

因此,您可以指定一個額外的註解

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"

HTTP 實現

HTTP 實現是預設使用的實現。當使用此實現時,如果 ConfigMap 或 Secret 發生變化,Spring Cloud Kubernetes Configuration Watcher 的 HTTP 實現將使用 Spring Cloud Kubernetes Discovery Client 獲取與 ConfigMap 或 Secret 名稱匹配的所有應用例項,並嚮應用的 /refresh actuator 端點發送一個 HTTP POST 請求。預設情況下,它將使用在 Discovery Client 中註冊的埠向 /actuator/refresh 傳送 POST 請求。

您還可以配置配置觀察器呼叫例項的 shutdown actuator 端點。為此,您可以設定 spring.cloud.kubernetes.configuration.watcher.refresh-strategy=shutdown

非預設管理埠和 Actuator 路徑

如果應用使用非預設的 actuator 路徑和/或使用不同的埠作為管理端點,應用的 Kubernetes service 可以新增一個名為 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

另一種配置 actuator 路徑和/或管理埠的方式是設定 spring.cloud.kubernetes.configuration.watcher.actuatorPathspring.cloud.kubernetes.configuration.watcher.actuatorPort

訊息實現

將 Spring Cloud Kubernetes Configuration Watcher 應用部署到 Kubernetes 時,可以透過將 profile 設定為 bus-amqp (RabbitMQ) 或 bus-kafka (Kafka) 來啟用訊息實現。預設情況下,使用訊息實現時,配置觀察器將使用 Spring Cloud Bus 向所有應用例項傳送 RefreshRemoteApplicationEvent。這將導致應用例項在不重啟的情況下重新整理應用的配置屬性。

您還可以配置以便關閉應用例項來重新整理應用的配置屬性。當應用關閉時,Kubernetes 將重啟應用例項並載入新的配置屬性。要使用此策略,請設定 spring.cloud.kubernetes.configuration.watcher.refresh-strategy=shutdown

配置 RabbitMQ

啟用 bus-amqp profile 後,您需要配置 Spring RabbitMQ,使其指向您希望使用的 RabbitMQ 例項位置以及進行身份驗證所需的任何憑據。這可以透過設定標準的 Spring RabbitMQ 屬性來實現,例如

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

配置 Kafka

啟用 bus-kafka profile 後,您需要配置 Spring Kafka,使其指向您希望使用的 Kafka Broker 例項位置。這可以透過設定標準的 Spring Kafka 屬性來實現,例如

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