Reputation: 44
So I was recently tasked with building a simple k8s operator that would have a CRD that only contains a string. Whenever a new resource of the type is created, it would read the string and log it into the pod logs. Sounds simple right?
Well, considering I have barely any experience with k8s and none in making an operator, not so much, I found some tutorial online that explains how to build an operator using spring-boot (also part of my task is that I have to use spring-boot). I have followed this tutorial then attempted to alter the code for my purpose, but I keep getting an error that ChatGPT describes as library version missmatch, and I have no clue whatsoever how to resolve this issue.
2024-03-27T12:10:33.700Z INFO 1 --- [operator] [ main] d.example.operator.OperatorApplication : Starting OperatorApplication v0.0.1-SNAPSHOT using Java 17.0.2 with PID 1 (/app.jar started by root in /)
2024-03-27T12:10:33.702Z INFO 1 --- [operator] [ main] d.example.operator.OperatorApplication : No active profile set, falling back to 1 default profile: "default"
2024-03-27T12:10:34.241Z WARN 1 --- [operator] [ main] s.c.a.AnnotationConfigApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'kubernetesClient' defined in class path resource [io/javaoperatorsdk/operator/springboot/starter/OperatorAutoConfiguration.class]: Failed to instantiate [io.fabric8.kubernetes.client.KubernetesClient]: Factory method 'kubernetesClient' threw exception with message: class io.fabric8.kubernetes.client.okhttp.OkHttpClientImpl overrides final method io.fabric8.kubernetes.client.http.StandardHttpClient.close()V
2024-03-27T12:10:34.246Z INFO 1 --- [operator] [ main] .s.b.a.l.ConditionEvaluationReportLogger :
Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.
2024-03-27T12:10:34.254Z ERROR 1 --- [operator] [ main] o.s.boot.SpringApplication : Application run failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'kubernetesClient' defined in class path resource [io/javaoperatorsdk/operator/springboot/starter/OperatorAutoConfiguration.class]: Failed to instantiate [io.fabric8.kubernetes.client.KubernetesClient]: Factory method 'kubernetesClient' threw exception with message: class io.fabric8.kubernetes.client.okhttp.OkHttpClientImpl overrides final method io.fabric8.kubernetes.client.http.StandardHttpClient.close()V
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:648) ~[spring-beans-6.1.5.jar!/:6.1.5]
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:636) ~[spring-beans-6.1.5.jar!/:6.1.5]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1335) ~[spring-beans-6.1.5.jar!/:6.1.5]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1165) ~[spring-beans-6.1.5.jar!/:6.1.5]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:562) ~[spring-beans-6.1.5.jar!/:6.1.5]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:522) ~[spring-beans-6.1.5.jar!/:6.1.5]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326) ~[spring-beans-6.1.5.jar!/:6.1.5]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-6.1.5.jar!/:6.1.5]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) ~[spring-beans-6.1.5.jar!/:6.1.5]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[spring-beans-6.1.5.jar!/:6.1.5]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:975) ~[spring-beans-6.1.5.jar!/:6.1.5]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:962) ~[spring-context-6.1.5.jar!/:6.1.5]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:624) ~[spring-context-6.1.5.jar!/:6.1.5]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754) ~[spring-boot-3.2.4.jar!/:3.2.4]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:456) ~[spring-boot-3.2.4.jar!/:3.2.4]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:334) ~[spring-boot-3.2.4.jar!/:3.2.4]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1354) ~[spring-boot-3.2.4.jar!/:3.2.4]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1343) ~[spring-boot-3.2.4.jar!/:3.2.4]
at de.example.operator.OperatorApplication.main(OperatorApplication.java:10) ~[!/:0.0.1-SNAPSHOT]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[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:568) ~[na:na]
at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:91) ~[app.jar:0.0.1-SNAPSHOT]
at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:53) ~[app.jar:0.0.1-SNAPSHOT]
at org.springframework.boot.loader.launch.JarLauncher.main(JarLauncher.java:58) ~[app.jar:0.0.1-SNAPSHOT]
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [io.fabric8.kubernetes.client.KubernetesClient]: Factory method 'kubernetesClient' threw exception with message: class io.fabric8.kubernetes.client.okhttp.OkHttpClientImpl overrides final method io.fabric8.kubernetes.client.http.StandardHttpClient.close()V
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:177) ~[spring-beans-6.1.5.jar!/:6.1.5]
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:644) ~[spring-beans-6.1.5.jar!/:6.1.5]
... 25 common frames omitted
Caused by: java.lang.IncompatibleClassChangeError: class io.fabric8.kubernetes.client.okhttp.OkHttpClientImpl overrides final method io.fabric8.kubernetes.client.http.StandardHttpClient.close()V
at java.base/java.lang.ClassLoader.defineClass1(Native Method) ~[na:na]
at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1012) ~[na:na]
at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:150) ~[na:na]
at java.base/java.net.URLClassLoader.defineClass(URLClassLoader.java:524) ~[na:na]
at java.base/java.net.URLClassLoader$1.run(URLClassLoader.java:427) ~[na:na]
at java.base/java.net.URLClassLoader$1.run(URLClassLoader.java:421) ~[na:na]
at java.base/java.security.AccessController.doPrivileged(AccessController.java:712) ~[na:na]
at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:420) ~[na:na]
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:587) ~[na:na]
at org.springframework.boot.loader.net.protocol.jar.JarUrlClassLoader.loadClass(JarUrlClassLoader.java:104) ~[app.jar:0.0.1-SNAPSHOT]
at org.springframework.boot.loader.launch.LaunchedClassLoader.loadClass(LaunchedClassLoader.java:91) ~[app.jar:0.0.1-SNAPSHOT]
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520) ~[na:na]
at io.fabric8.kubernetes.client.okhttp.OkHttpClientBuilderImpl.completeBuild(OkHttpClientBuilderImpl.java:122) ~[kubernetes-httpclient-okhttp-6.9.2.jar!/:na]
at io.fabric8.kubernetes.client.okhttp.OkHttpClientBuilderImpl.initialBuild(OkHttpClientBuilderImpl.java:94) ~[kubernetes-httpclient-okhttp-6.9.2.jar!/:na]
at io.fabric8.kubernetes.client.okhttp.OkHttpClientBuilderImpl.build(OkHttpClientBuilderImpl.java:55) ~[kubernetes-httpclient-okhttp-6.9.2.jar!/:na]
at io.fabric8.kubernetes.client.okhttp.OkHttpClientBuilderImpl.build(OkHttpClientBuilderImpl.java:36) ~[kubernetes-httpclient-okhttp-6.9.2.jar!/:na]
at io.fabric8.kubernetes.client.KubernetesClientBuilder.getHttpClient(KubernetesClientBuilder.java:93) ~[kubernetes-client-api-6.11.0.jar!/:na]
at io.fabric8.kubernetes.client.KubernetesClientBuilder.build(KubernetesClientBuilder.java:78) ~[kubernetes-client-api-6.11.0.jar!/:na]
at io.javaoperatorsdk.operator.springboot.starter.OperatorAutoConfiguration.lambda$kubernetesClient$3(OperatorAutoConfiguration.java:61) ~[operator-framework-spring-boot-starter-5.4.1.jar!/:na]
at java.base/java.util.Optional.orElseGet(Optional.java:364) ~[na:na]
at io.javaoperatorsdk.operator.springboot.starter.OperatorAutoConfiguration.kubernetesClient(OperatorAutoConfiguration.java:60) ~[operator-framework-spring-boot-starter-5.4.1.jar!/:na]
at io.javaoperatorsdk.operator.springboot.starter.OperatorAutoConfiguration$$SpringCGLIB$$0.CGLIB$kubernetesClient$3(<generated>) ~[operator-framework-spring-boot-starter-5.4.1.jar!/:na]
at io.javaoperatorsdk.operator.springboot.starter.OperatorAutoConfiguration$$SpringCGLIB$$FastClass$$1.invoke(<generated>) ~[operator-framework-spring-boot-starter-5.4.1.jar!/:na]
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:258) ~[spring-core-6.1.5.jar!/:6.1.5]
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331) ~[spring-context-6.1.5.jar!/:6.1.5]
at io.javaoperatorsdk.operator.springboot.starter.OperatorAutoConfiguration$$SpringCGLIB$$0.kubernetesClient(<generated>) ~[operator-framework-spring-boot-starter-5.4.1.jar!/:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[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:568) ~[na:na]
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) ~[spring-beans-6.1.5.jar!/:6.1.5]
... 26 common frames omitted
I currently have the following code in my spring-boot project.
MyCustomResource.java
package de.example.operator;
import io.fabric8.kubernetes.client.CustomResource;
import io.fabric8.kubernetes.api.model.Namespaced;
import io.javaoperatorsdk.operator.api.ObservedGenerationAwareStatus;
import io.fabric8.kubernetes.model.annotation.Group;
import io.fabric8.kubernetes.model.annotation.Version;
@Group("de.example")
@Version("v1")
public class MyCustomResource extends CustomResource<MyCustomSpec, ObservedGenerationAwareStatus> implements Namespaced {
}
MyCustomResourceReconciler.java
package de.example.operator;
import io.javaoperatorsdk.operator.api.reconciler.Context;
import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration;
import io.javaoperatorsdk.operator.api.reconciler.UpdateControl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import io.javaoperatorsdk.operator.api.reconciler.Reconciler;
@Component
@ControllerConfiguration
public class MyCustomResourceReconciler implements Reconciler<MyCustomResource> {
private static final Logger log = LoggerFactory.getLogger(MyCustomResourceReconciler.class);
@Override
public UpdateControl<MyCustomResource> reconcile(MyCustomResource resource, Context<MyCustomResource> context) {
String message = resource.getSpec().getMessage();
log.info("Message from CR {}: {}", resource.getMetadata().getName(), message);
return UpdateControl.noUpdate();
}
}
MyCustomSpec.java
package de.example.operator;
public class MyCustomSpec {
private String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
OperatorApplication.java
package de.example.operator;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class OperatorApplication {
public static void main(String[] args) {
SpringApplication.run(OperatorApplication.class, args);
}
}
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>de.example</groupId>
<artifactId>operator</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>operator</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>17</java.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-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.javaoperatorsdk</groupId>
<artifactId>operator-framework-spring-boot-starter</artifactId>
<version>5.4.1</version>
</dependency>
<dependency>
<groupId>io.javaoperatorsdk</groupId>
<artifactId>operator-framework-spring-boot-starter-test</artifactId>
<version>5.4.1</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j2-impl</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.fabric8</groupId>
<artifactId>crd-generator-apt</artifactId>
<version>6.11.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk18on</artifactId>
<version>1.77</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk18on</artifactId>
<version>1.77</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Maybe someone can see where the issue is?
Upvotes: 0
Views: 411
Reputation: 44
Issue was that the newest version of operatorsdk was not using the newest version of fabric8. After changing my dependency version of crd generator to 6.9.2 as is in the dependency tree for operator SDK, the code runs flawlessly.
Upvotes: 0