解决 K8sApi 部署后报 Unknown apiVersionKind apps/v1/Deployment is it registered?
该功能在本地调试时是正常的, 部署到服务器时报错。
Jdk11 + SpringBoot 2.7.5, 依赖:
<dependency>
<groupId>io.kubernetes</groupId>
<artifactId>client-java</artifactId>
<version>20.0.0</version>
</dependency>
在执行: (V1Deployment)Yaml.load(yamlContent)
时报错: Unknown apiVersionKind apps/v1/Deployment is it registered?
经分析 /mnt/app/mvn-repo/io/kubernetes/client-java/20.0.0/client-java-20.0.0-sources.jar!/io/kubernetes/client/util/ModelMapper.java
getClassNamesFromPackage
方法有问题,原代码如下:
private static List<String> getClassNamesFromPackage(ClassLoader classLoader, String pkg) throws IOException {
ArrayList<String> names = new ArrayList<>();
String packageName = pkg.replace(".", "/");
URL packageURL = classLoader.getResource(packageName);
if (packageURL.getProtocol().equals("jar")) {
processJarPackage(packageURL, packageName, pkg, names);
} else {
processFilePackage(packageURL, pkg, names);
}
return names;
}
private static void processJarPackage(URL packageURL, String packageName, String pkg, ArrayList<String> names) throws IOException {
String jarFileName = URLDecoder.decode(packageURL.getFile(), "UTF-8");
JarFile jf = null;
// jar: client in repository; nested: client in a fat jar
if (jarFileName.startsWith("jar:") || jarFileName.startsWith("nested:")) {
jf = ((JarURLConnection) packageURL.openConnection()).getJarFile();
}
// file: client is a file in target (unit test)
if (jarFileName.startsWith("file:") ) {
jarFileName = jarFileName.substring(5, jarFileName.indexOf("!"));
jf = new JarFile(jarFileName);
}
if (jf == null) {
logger.error("Loading classes from jar with error packageURL: {}", jarFileName);
return;
}
logger.info("Loading classes from jar {}", jarFileName);
Enumeration<JarEntry> jarEntries = jf.entries();
while (jarEntries.hasMoreElements()) {
processJarEntry(jarEntries.nextElement(), packageName, pkg, names);
}
jf.close();
}
private static void processJarEntry(JarEntry jarEntry, String packageName, String pkg, ArrayList<String> names) {
String entryName = jarEntry.getName();
if (entryName.startsWith(packageName) && entryName.length() > packageName.length() + 5) {
entryName = entryName.substring(packageName.length() + 1, entryName.lastIndexOf('.'));
names.add(pkg + "." + entryName);
}
}
原因是,在部署环境下, 扫描包时出错,扫描不到。修复如下:
private static boolean inited = false;
static void init() {
if (inited) {
return;
}
inited = true;
initApiGroupMap();
initApiVersionList();
var names = findResources("classpath*:io/kubernetes/client/openapi/models/**/*.class");
var modelMapperClass = ModelMapper.class;
Field preBuiltField = null;
try {
preBuiltField = modelMapperClass.getDeclaredField("preBuiltClassesByGVK");
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
}
preBuiltField.setAccessible(true);
Map<GroupVersionKind, Class<?>> preBuiltClassesByGVK = null;
try {
preBuiltClassesByGVK = (Map<GroupVersionKind, Class<?>>) preBuiltField.get(null);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
for (String classInfo : names) {
Class<?> clazz = loadClass(classInfo, Yaml.class.getClassLoader());
if (!KubernetesObject.class.isAssignableFrom(clazz)
&& !KubernetesListObject.class.isAssignableFrom(clazz)) {
continue;
}
Pair<String, String> groupAndOther = getApiGroup(clazz.getSimpleName());
Pair<String, String> versionAndOther = getApiVersion(groupAndOther.getRight());
String group = Strings.nullToEmpty(groupAndOther.getLeft());
String version = versionAndOther.getLeft();
String kind = versionAndOther.getRight();
preBuiltClassesByGVK.put(new GroupVersionKind(group, version, kind), clazz);
}
}
private static Pair<String, String> getApiGroup(String name) {
return preBuiltApiGroups.entrySet().stream()
.filter(e -> name.startsWith(e.getKey()))
.map(e -> new ImmutablePair<>(e.getValue(), name.substring(e.getKey().length())))
.findFirst()
.orElse(new ImmutablePair<>(null, name));
}
private static Pair<String, String> getApiVersion(String name) {
return preBuiltApiVersions.stream()
.filter(v -> name.startsWith(v))
.map(v -> new ImmutablePair<>(v.toLowerCase(), name.substring(v.length())))
.findFirst()
.orElse(new ImmutablePair<>(null, name));
}
private static Map<String, String> preBuiltApiGroups = new HashMap<>();
private static void initApiGroupMap() {
preBuiltApiGroups.put("Admissionregistration", "admissionregistration.k8s.io");
preBuiltApiGroups.put("Apiextensions", "apiextensions.k8s.io");
preBuiltApiGroups.put("Apiregistration", "apiregistration.k8s.io");
preBuiltApiGroups.put("Apps", "apps");
preBuiltApiGroups.put("Authentication", "authentication.k8s.io");
preBuiltApiGroups.put("Authorization", "authorization.k8s.io");
preBuiltApiGroups.put("Autoscaling", "autoscaling");
preBuiltApiGroups.put("Batch", "batch");
preBuiltApiGroups.put("Certificates", "certificates.k8s.io");
preBuiltApiGroups.put("Core", "");
preBuiltApiGroups.put("Extensions", "extensions");
preBuiltApiGroups.put("Events", "events.k8s.io");
preBuiltApiGroups.put("FlowControl", "flowcontrol.apiserver.k8s.io");
preBuiltApiGroups.put("Networking", "networking.k8s.io");
preBuiltApiGroups.put("Policy", "policy");
preBuiltApiGroups.put("RbacAuthorization", "rbac.authorization.k8s.io");
preBuiltApiGroups.put("Scheduling", "scheduling.k8s.io");
preBuiltApiGroups.put("Settings", "settings.k8s.io");
preBuiltApiGroups.put("Storage", "storage.k8s.io");
}
private static List<String> preBuiltApiVersions = new ArrayList<>();
private static void initApiVersionList() {
// Order important
preBuiltApiVersions.add("V2beta1");
preBuiltApiVersions.add("V2beta2");
preBuiltApiVersions.add("V2alpha1");
preBuiltApiVersions.add("V1beta2");
preBuiltApiVersions.add("V1beta1");
preBuiltApiVersions.add("V1alpha1");
preBuiltApiVersions.add("V1");
preBuiltApiVersions.add("V2");
}
private static Class<?> loadClass(String name, ClassLoader classLoader) {
try {
return Class.forName(name, false, classLoader);
} catch (ClassNotFoundException e) {
return null;
}
}
作者:NewSea 出处:http://newsea.cnblogs.com/
QQ,MSN:iamnewsea@hotmail.com 如无特别标记说明,均为NewSea原创,版权私有,翻载必纠。欢迎交流,转载,但要在页面明显位置给出原文连接。谢谢。 |