Spring Cloud Kubernetes:等待通知者缓存准备就绪的超时

Posted

技术标签:

【中文标题】Spring Cloud Kubernetes:等待通知者缓存准备就绪的超时【英文标题】:Spring Cloud Kubernetes: Timeout waiting for informers cache to be ready 【发布时间】:2021-07-12 23:56:42 【问题描述】:

我正在尝试在基于 Spring Boot 的微服务中利用 Spring Cloud Kubernetes,即自动配置和服务发现。

但是,我在初始化期间收到一条错误消息(等待通知者缓存准备好超时,kubernetes 服务是否启动?),以及高冗长,我无法做到这两点上网找资料帮我查明原因。错误消息和过多的日志消息在下面详细说明。为缺乏上下文而道歉,但我也很困惑!

应用程序在default 服务帐户中运行,该服务帐户具有documentation 中指定的所有权限:

$ kubectl describe serviceaccount default
Name:                default
Namespace:           joaomlneto
Labels:              <none>
Annotations:         <none>
Image pull secrets:  devspace-auth-rg-nl-ams-scw-cloud
Mountable secrets:   default-token-2sxvc
Tokens:              default-token-2sxvc
Events:              <none>

$ kubectl describe rolebinding namespace-reader-binding
Name:         namespace-reader-binding
Labels:       <none>
Annotations:  <none>
Role:
  Kind:  Role
  Name:  namespace-reader
Subjects:
  Kind            Name     Namespace
  ----            ----     ---------
  ServiceAccount  default  joaomlneto

$ kubectl describe role namespace-reader
Name:         namespace-reader
Labels:       <none>
Annotations:  <none>
PolicyRule:
  Resources              Non-Resource URLs  Resource Names  Verbs
  ---------              -----------------  --------------  -----
  configmaps             []                 []              [list watch get]
  endpoints              []                 []              [list watch get]
  pods                   []                 []              [list watch get]
  secrets                []                 []              [list watch get]
  services               []                 []              [list watch get]
  configmaps.apps        []                 []              [list watch get]
  endpoints.apps         []                 []              [list watch get]
  pods.apps              []                 []              [list watch get]
  secrets.apps           []                 []              [list watch get]
  services.apps          []                 []              [list watch get]
  configmaps.extensions  []                 []              [list watch get]
  endpoints.extensions   []                 []              [list watch get]
  pods.extensions        []                 []              [list watch get]
  secrets.extensions     []                 []              [list watch get]
  services.extensions    []                 []              [list watch get]

我使用的是 Spring Boot 2.4; Spring Cloud Kubernetes 2.0.2。我的pom.xml

<properties>
    <java.version>11</java.version>
    <spring-cloud.version>2020.0.2</spring-cloud.version>
    <spring-cloud-kubernetes.version>2.0.2</spring-cloud-kubernetes.version>
    <graphql-java-kickstart.version>11.0.0</graphql-java-kickstart.version>
    <lombok.version>1.18.20</lombok.version>
</properties>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-kubernetes-client-all</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-loadbalancer</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.kafka</groupId>
        <artifactId>spring-kafka</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.kafka</groupId>
        <artifactId>spring-kafka-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>$lombok.version</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>com.graphql-java-kickstart</groupId>
        <artifactId>graphql-spring-boot-starter</artifactId>
        <version>$graphql-java-kickstart.version</version>
    </dependency>
    <dependency>
        <groupId>com.graphql-java-kickstart</groupId>
        <artifactId>graphql-spring-boot-starter-test</artifactId>
        <version>$graphql-java-kickstart.version</version>
        <scope>test</scope>
    </dependency>
</dependencies>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>$spring-cloud.version</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-kubernetes-dependencies</artifactId>
            <version>$spring-cloud-kubernetes.version</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <excludeDevtools>false</excludeDevtools>
            </configuration>
        </plugin>
    </plugins>
</build>

<repositories>
    <repository>
        <releases>
            <enabled>true</enabled>
        </releases>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
        <id>central</id>
        <name>Maven Central</name>
        <url>https://repo1.maven.org/maven2</url>
    </repository>
    <repository>
        <id>supersecret</id>
        <name>A Super Secret Repo</name>
        <url>https://example.com/1</url>
        <releases>
            <enabled>true</enabled>
        </releases>
        <snapshots>
            <enabled>true</enabled>
        </snapshots>
    </repository>
</repositories>

<distributionManagement>
    <repository>
        <id>supersecret2</id>
        <name>Another Super Secret Repo</name>
        <url>https://example.com/2</url>
    </repository>
</distributionManagement>

但是,在应用程序成功启动一分钟后,我收到以下错误:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'kubernetesInformerDiscoveryClient' defined in class path resource [org/springframework/cloud/kubernetes/client/discovery/KubernetesDiscoveryClientAutoConfiguration$KubernetesInformerDiscoveryConfiguration.class]: Invocation of init method failed; nested exception is java.lang.IllegalStateException: Timeout waiting for informers cache to be ready, is the kubernetes service up?
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1786) ~[spring-beans-5.3.5.jar:5.3.5]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:602) ~[spring-beans-5.3.5.jar:5.3.5]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:524) ~[spring-beans-5.3.5.jar:5.3.5]
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.5.jar:5.3.5]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.5.jar:5.3.5]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.5.jar:5.3.5]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.5.jar:5.3.5]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:944) ~[spring-beans-5.3.5.jar:5.3.5]
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918) ~[spring-context-5.3.5.jar:5.3.5]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583) ~[spring-context-5.3.5.jar:5.3.5]
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:144) ~[spring-boot-2.4.4.jar:2.4.4]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:769) ~[spring-boot-2.4.4.jar:2.4.4]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:761) ~[spring-boot-2.4.4.jar:2.4.4]
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:426) ~[spring-boot-2.4.4.jar:2.4.4]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:326) ~[spring-boot-2.4.4.jar:2.4.4]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1313) ~[spring-boot-2.4.4.jar:2.4.4]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1302) ~[spring-boot-2.4.4.jar:2.4.4]
    at myorg.myapp.Application.main(Application.java:9) ~[classes/:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
    at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49) ~[spring-boot-devtools-2.4.4.jar:2.4.4]
Caused by: java.lang.IllegalStateException: Timeout waiting for informers cache to be ready, is the kubernetes service up?
    at org.springframework.cloud.kubernetes.client.discovery.KubernetesInformerDiscoveryClient.afterPropertiesSet(KubernetesInformerDiscoveryClient.java:221) ~[spring-cloud-kubernetes-client-discovery-2.0.2.jar:2.0.2]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1845) ~[spring-beans-5.3.5.jar:5.3.5]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1782) ~[spring-beans-5.3.5.jar:5.3.5]
    ... 22 common frames omitted

我还会每秒记录以下消息(在错误之前和之后,无穷无尽):

2021-04-18 16:19:12.585  INFO 224 --- [pool-9-thread-1] .k.c.d.KubernetesInformerDiscoveryClient : Waiting for the cache of informers to be fully loaded..
2021-04-18 16:19:12.935  INFO 224 --- [s.V1Endpoints-1] i.k.c.informer.cache.ReflectorRunnable   : class io.kubernetes.client.openapi.models.V1Endpoints#Start listing and watching...
2021-04-18 16:19:12.950  INFO 224 --- [els.V1Service-1] i.k.c.informer.cache.ReflectorRunnable   : class io.kubernetes.client.openapi.models.V1Service#Start listing and watching...

【问题讨论】:

【参考方案1】:

我设法通过使用 Fabric8 客户端而不是官方客户端来消除错误消息。这个简单的改变就足以解决我的问题。

这是通过将 pom.xml 中的依赖关系从 spring-cloud-starter-kubernetes-client-all 更改为 spring-cloud-starter-kubernetes-fabric8-all 来完成的。

由于这似乎不是预期的行为,我打开了bug report on the Spring Cloud Kubernetes project on GitHub。


编辑 2022 年 1 月:bug report 已标记为已解决,尽管有些人仍然遇到此问题。我仍在使用 Fabric8,没有遇到任何问题。没有回头。

【讨论】:

【参考方案2】:

您尚未发布您的 yaml 配置以及您如何应用它,因此我无法就您的情况提供指导。但是,您的问题的一个可能原因可能是服务帐户的令牌错误。

阅读文档的Security Configurations Inside Kubernetes 部分,我们看到以下引用:

对于 Kubernetes (1.3+),命名空间对 pod 可用 服务帐户机密的一部分,并由 客户

这意味着如果 pod 使用的服务帐户的 secret 由于任何原因错误配置了命名空间,kubernetes 客户端将默默地忽略该错误并继续尝试在错误的命名空间中列出服务/端点,而实际上该命名空间是 授予。

您可以在命名空间joaomlneto 中列出秘密:

kubectl get secrets --namespace joaomlneto

然后,您可以检查 default 服务帐户令牌的命名空间是否与同一命名空间相同:

kubectl get secret/default-token-..... --template='.data.namespace' --namespace joaomlneto

base64 编码的输出应解码为joaomlneto。如果没有,您将遇到权限问题。要修复它,您可以删除然后重新创建服务帐户,这次正确配置它。

【讨论】:

嘿,接近 :) 感谢您的输入。通过简单地将官方 K8S 客户端替换为 fabric8 客户端(将 spring-cloud-starter-kubernetes-client-all 替换为 spring-cloud-starter-kubernetes-fabric8-all),我设法摆脱了错误消息。我在 Spring Cloud Kubernetes 项目中提交了一个错误,因为我猜这不是正确的行为 (github.com/spring-cloud/spring-cloud-kubernetes/issues/776)。 我正在通过他们的组件图 (devspace.sh/component-chart/docs/introduction) 部署方法使用 devspace 部署应用程序。生成的部署规范具有正确的命名空间 (joaomlneto),并且由于没有提及服务帐户,我假设它使用默认值。 :) 这也是我没有在这里发布它的原因,因为我很确定这不是问题的根源,并且在这里发布它会有点混乱 刚刚检查,$ kubectl get secret/default-token-64pvh --template='.data.namespace' --namespace joaomlneto | base64 -d 输出正确:joaomlneto%【参考方案3】:

您需要为您的 spring 应用程序授予必要的权限,使用您正在使用的依赖项spring-cloud-starter-kubernetes-fabric8-all,您需要授予以下权限:“configmaps”、“pods”、“services”、“endpoints”、“秘密”。

以下是 Spring Cloud 文档中的示例:

kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  namespace: YOUR-NAME-SPACE
  name: namespace-reader
rules:
  - apiGroups: ["", "extensions", "apps"]
    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: ""

链接:https://docs.spring.io/spring-cloud-kubernetes/docs/current/reference/html/index.html

【讨论】:

你好!感谢你及时的答复!但我想我已经设置了这些权限 - 我已经在问题中包含了命令 kubectl describe role namespace-readerkubectl describe rolebinding namespace-reader-bindingkubectl describe serviceaccount default 的输出。 @JoãoNeto 你能尝试在 application.properties/yml 中设置spring.cloud.kubernetes.discovery.wait-cache-ready=true 看看它是否有效吗? 我将该设置添加到我的application.yml,但仍然遇到 BeanCreationException 和过度冗长 :( 我想知道我正在使用的提供商的集群配置是否有问题 我的意思是设置为 false,但我猜你已经尝试过了。 你好!我完全搞砸了并粘贴了错误的 pom.xml(我不确定我是怎么做到的)。我使用的是官方的 K8S 客户端而不是 fabric8,这就是问题所在。我猜这是一个错误,我报告了它(github.com/spring-cloud/spring-cloud-kubernetes/issues/776)。 :) 抱歉,感谢您的帮助!

以上是关于Spring Cloud Kubernetes:等待通知者缓存准备就绪的超时的主要内容,如果未能解决你的问题,请参考以下文章

正在使用 Kubernetes Spring Cloud 多个配置映射

Spring Cloud Kubernetes(二)

spring-cloud-kubernetes官方demo运行实战

部署 spring-cloud-kubernetes kubernetes-hello-world-example 失败

Spring Cloud Kubernetes 支持 Spring Cloud 负载均衡器吗?

存在 spring-cloud-kubernetes 配置映射依赖项的 spring 应用程序启动异常