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=true
或 spring.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 可以通过两种方式向应用发送刷新通知。
-
通过 HTTP,在这种情况下,被通知的应用必须暴露
/refresh
actuator 端点,并且可以从集群内部访问。 -
使用 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.apps
或 spring.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.actuatorPath
和 spring.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
。