diff --git a/druid-admin/pom.xml b/druid-admin/pom.xml
index aba972401..617fe62db 100644
--- a/druid-admin/pom.xml
+++ b/druid-admin/pom.xml
@@ -10,7 +10,7 @@
com.alibaba
druid-admin
- 1.2.12
+ 1.2.22
druid-admin
Demo project for Spring Boot
@@ -66,7 +66,7 @@
com.alibaba
druid
- 1.2.12
+ 1.2.22
@@ -83,6 +83,21 @@
org.apache.httpcomponents
httpclient
+
+
+
+ io.kubernetes
+ client-java
+ 16.0.3
+
+
+
+
+ com.squareup.okhttp3
+ okhttp
+ 3.14.9
+
+
diff --git a/druid-admin/src/main/java/com/alibaba/druid/admin/DruidAdminApplication.java b/druid-admin/src/main/java/com/alibaba/druid/admin/DruidAdminApplication.java
index 073eee2ff..d6043e109 100644
--- a/druid-admin/src/main/java/com/alibaba/druid/admin/DruidAdminApplication.java
+++ b/druid-admin/src/main/java/com/alibaba/druid/admin/DruidAdminApplication.java
@@ -30,6 +30,12 @@ public class DruidAdminApplication {
if (properties.getLoginPassword() != null) {
registrationBean.addInitParameter("loginPassword", properties.getLoginPassword());
}
+ if (properties.getKubeConfigFilePath() != null) {
+ registrationBean.addInitParameter("kubeConfigFilePath", properties.getKubeConfigFilePath());
+ }
+ if (properties.getK8sNamespace() != null) {
+ registrationBean.addInitParameter("k8sNamespace", properties.getK8sNamespace());
+ }
return registrationBean;
}
diff --git a/druid-admin/src/main/java/com/alibaba/druid/admin/config/MonitorProperties.java b/druid-admin/src/main/java/com/alibaba/druid/admin/config/MonitorProperties.java
index e537c6604..0e3a92ff5 100644
--- a/druid-admin/src/main/java/com/alibaba/druid/admin/config/MonitorProperties.java
+++ b/druid-admin/src/main/java/com/alibaba/druid/admin/config/MonitorProperties.java
@@ -29,4 +29,14 @@ public class MonitorProperties {
* 访问路径
*/
private String contextPath;
+
+ /**
+ * k8s集群访问凭证
+ */
+ private String kubeConfigFilePath;
+
+ /**
+ * k8s集群命名空间
+ */
+ private String k8sNamespace;
}
diff --git a/druid-admin/src/main/java/com/alibaba/druid/admin/model/dto/DataSourceResult.java b/druid-admin/src/main/java/com/alibaba/druid/admin/model/dto/DataSourceResult.java
index 3a6188c77..db8d7985d 100644
--- a/druid-admin/src/main/java/com/alibaba/druid/admin/model/dto/DataSourceResult.java
+++ b/druid-admin/src/main/java/com/alibaba/druid/admin/model/dto/DataSourceResult.java
@@ -118,7 +118,7 @@ public class DataSourceResult {
@JSONField(name = "RemoveAbandoned")
private boolean RemoveAbandoned;
@JSONField(name = "ClobOpenCount")
- private int ClobOpenCount;
+ private long ClobOpenCount;
@JSONField(name = "BlobOpenCount")
private int BlobOpenCount;
@JSONField(name = "KeepAliveCheckCount")
diff --git a/druid-admin/src/main/java/com/alibaba/druid/admin/service/K8sDiscoveryClient.java b/druid-admin/src/main/java/com/alibaba/druid/admin/service/K8sDiscoveryClient.java
new file mode 100644
index 000000000..fdec5b0a2
--- /dev/null
+++ b/druid-admin/src/main/java/com/alibaba/druid/admin/service/K8sDiscoveryClient.java
@@ -0,0 +1,62 @@
+package com.alibaba.druid.admin.service;
+
+import com.alibaba.druid.admin.model.ServiceNode;
+import io.kubernetes.client.openapi.ApiClient;
+import io.kubernetes.client.openapi.ApiException;
+import io.kubernetes.client.openapi.Configuration;
+import io.kubernetes.client.openapi.apis.CoreV1Api;
+import io.kubernetes.client.openapi.models.V1Pod;
+import io.kubernetes.client.openapi.models.V1PodList;
+import io.kubernetes.client.openapi.models.V1Service;
+import io.kubernetes.client.util.ClientBuilder;
+import io.kubernetes.client.util.KubeConfig;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.stereotype.Component;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Component
+public class K8sDiscoveryClient {
+
+ public Map getK8sPodsInfo(List serviceNames, String kubeConfigFilePath, String namespace) throws IOException, ApiException {
+ InputStream inputStream = new ClassPathResource(kubeConfigFilePath).getInputStream();
+ InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
+ ApiClient client = ClientBuilder.kubeconfig(KubeConfig.loadKubeConfig(reader)).build();
+ Configuration.setDefaultApiClient(client);
+ CoreV1Api api = new CoreV1Api();
+ List serviceNodes = new ArrayList<>();
+ V1PodList podList = api.listNamespacedPod(namespace, null, null, null, null, null, null, null, null, null, null);
+ for (String serviceName : serviceNames) {
+ V1Service service = api.readNamespacedService(serviceName, namespace, null);
+ List servicePods = podList.getItems().stream().filter(i -> Objects.requireNonNull(Objects.requireNonNull(i.getMetadata()).getName()).startsWith(serviceName)).collect(Collectors.toList());
+ for (V1Pod pod : servicePods) {
+ String podId = pod.getMetadata().getUid();
+ String podIp = pod.getStatus().getPodIP();
+ Integer port = Objects.requireNonNull(Objects.requireNonNull(service.getSpec()).getPorts()).stream().filter(i -> serviceName.equalsIgnoreCase(i.getName())).findFirst().get().getPort();
+ ServiceNode serviceNode = new ServiceNode();
+ serviceNode.setId(podId);
+ serviceNode.setPort(port);
+ serviceNode.setAddress(podIp);
+ serviceNode.setServiceName(serviceName);
+ serviceNodes.add(serviceNode);
+ MonitorStatService.serviceIdMap.put(podId, serviceNode);
+ log.info("pod info: " + serviceNode);
+ }
+ }
+ return serviceNodes.stream().collect(Collectors.toMap(i -> i.getServiceName() + "-" + i.getAddress() + "-" + i.getPort(),
+ Function.identity(), (v1, v2) -> v2));
+ }
+
+
+}
diff --git a/druid-admin/src/main/java/com/alibaba/druid/admin/service/MonitorStatService.java b/druid-admin/src/main/java/com/alibaba/druid/admin/service/MonitorStatService.java
index 9bdedb404..0218c5af7 100644
--- a/druid-admin/src/main/java/com/alibaba/druid/admin/service/MonitorStatService.java
+++ b/druid-admin/src/main/java/com/alibaba/druid/admin/service/MonitorStatService.java
@@ -2,12 +2,7 @@ package com.alibaba.druid.admin.service;
import com.alibaba.druid.admin.config.MonitorProperties;
import com.alibaba.druid.admin.model.ServiceNode;
-import com.alibaba.druid.admin.model.dto.ConnectionResult;
-import com.alibaba.druid.admin.model.dto.DataSourceResult;
-import com.alibaba.druid.admin.model.dto.SqlDetailResult;
-import com.alibaba.druid.admin.model.dto.SqlListResult;
-import com.alibaba.druid.admin.model.dto.WallResult;
-import com.alibaba.druid.admin.model.dto.WebResult;
+import com.alibaba.druid.admin.model.dto.*;
import com.alibaba.druid.admin.util.HttpUtil;
import com.alibaba.druid.stat.DruidStatServiceMBean;
import com.alibaba.druid.support.http.stat.WebAppStatManager;
@@ -18,18 +13,19 @@ import com.alibaba.druid.util.StringUtils;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
+import com.alibaba.fastjson2.JSONWriter;
+import com.google.common.base.Strings;
+import com.google.common.collect.Lists;
+import io.kubernetes.client.openapi.ApiException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.stereotype.Component;
+import org.springframework.util.CollectionUtils;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
+import java.io.IOException;
+import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
@@ -44,7 +40,7 @@ public class MonitorStatService implements DruidStatServiceMBean {
public static final int RESULT_CODE_ERROR = -1;
private static final int DEFAULT_PAGE = 1;
- private static final int DEFAULT_PER_PAGE_COUNT = Integer.MAX_VALUE;
+ private static final int DEFAULT_PER_PAGE_COUNT = 1000;
private static final String ORDER_TYPE_DESC = "desc";
private static final String ORDER_TYPE_ASC = "asc";
private static final String DEFAULT_ORDER_TYPE = ORDER_TYPE_ASC;
@@ -60,13 +56,25 @@ public class MonitorStatService implements DruidStatServiceMBean {
@Autowired
private MonitorProperties monitorProperties;
+ @Autowired
+ private K8sDiscoveryClient k8sDiscoveryClient;
+
/**
* 获取所有服务信息
*
* @return
*/
- public Map getAllServiceNodeMap(){
+ public Map getAllServiceNodeMap() {
List services = discoveryClient.getServices();
+ List applications = monitorProperties.getApplications();
+ String kubeConfig = monitorProperties.getKubeConfigFilePath();
+ if (CollectionUtils.isEmpty(services) && !Strings.isNullOrEmpty(kubeConfig)) {
+ try {
+ return k8sDiscoveryClient.getK8sPodsInfo(applications, kubeConfig, monitorProperties.getK8sNamespace());
+ } catch (IOException | ApiException e) {
+ log.error("get k8s resource fail: ", e);
+ }
+ }
List serviceNodes = new ArrayList<>();
for (String service : services) {
List instances = discoveryClient.getInstances(service);
@@ -79,7 +87,7 @@ public class MonitorStatService implements DruidStatServiceMBean {
int port = instance.getPort();
String serviceId = instance.getServiceId();
// 根据前端参数采集指定的服务
- if (monitorProperties.getApplications().contains(serviceId)) {
+ if (applications.contains(serviceId)) {
ServiceNode serviceNode = new ServiceNode();
serviceNode.setId(instanceId);
serviceNode.setPort(port);
@@ -100,11 +108,18 @@ public class MonitorStatService implements DruidStatServiceMBean {
* @param parameters
* @return
*/
- public Map getServiceAllNodeMap(Map parameters){
+ public Map getServiceAllNodeMap(Map parameters) {
String requestServiceName = parameters.get("serviceName");
List services = discoveryClient.getServices();
+ String kubeConfig = monitorProperties.getKubeConfigFilePath();
+ if (CollectionUtils.isEmpty(services) && !Strings.isNullOrEmpty(kubeConfig)) {
+ try {
+ return k8sDiscoveryClient.getK8sPodsInfo(Lists.newArrayList(requestServiceName), kubeConfig, monitorProperties.getK8sNamespace());
+ } catch (IOException | ApiException e) {
+ log.error("get k8s resource fail: ", e);
+ }
+ }
List serviceNodes = new ArrayList<>();
-
for (String service : services) {
List instances = discoveryClient.getInstances(service);
for (ServiceInstance instance : instances) {
@@ -130,6 +145,7 @@ public class MonitorStatService implements DruidStatServiceMBean {
return serviceNodes.stream().collect(Collectors.toMap(i -> i.getServiceName() + "-" + i.getAddress() + "-" + i.getPort(),
Function.identity(), (v1, v2) -> v2));
}
+
@Override
public String service(String url) {
Map parameters = getParameters(url);
@@ -343,7 +359,13 @@ public class MonitorStatService implements DruidStatServiceMBean {
}
}
List