feat(运维监控模块): 增加 Pod 信息展示并优化应用列表

1. 在 K8sApplication 中添加 podSelector 和 podList 字段
2. 新增 K8sApplicationPod 类用于表示 Pod 信息
3. 修改 getNamespaceDetailList 方法支持获取 Pod 信息
4. 优化应用列表展示,增加 Pod选择器和 Pod 列表
This commit is contained in:
OTTO 2025-05-22 14:07:10 +08:00
parent 5e19e53b94
commit 58bf8326c5
8 changed files with 90 additions and 12 deletions

View File

@ -28,7 +28,7 @@ public class K8sDashboardController extends BaseController {
@ApiOperation(value = "获取命名空间列表")
@GetMapping("/namespace/list")
public GenericsTableDataInfo<K8sNamespace> namespaceList() {
return new GenericsTableDataInfo<>(k8sNamespaceService.getNamespaceDetailList());
return new GenericsTableDataInfo<>(k8sNamespaceService.getNamespaceDetailList(true));
}
@ApiOperation(value = "获取集群节点列表")

View File

@ -4,6 +4,8 @@ import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
@Data
@ApiModel("K8S应用")
@ -27,8 +29,13 @@ public class K8sApplication {
@ApiModelProperty(value = "副本数量")
private Integer replicas;
@ApiModelProperty(value = "有效副本数量")
@ApiModelProperty(value = "有效副本数量(当有效副本数为0时代表应用失败呈现红色当有效副本数大于0但小于副本数时代表应用部分失败呈现橙色当有效副本数等于副本数代表应用正常呈现蓝色)")
private Integer readyReplicas;
@ApiModelProperty(value = "Pod选择器")
private String podSelector;
private List<K8sApplicationPod> podList;
public static String getApplicationFullKind(String kind) {
if("DaemonSet".equals(kind)){
return "apps.daemonsets";

View File

@ -0,0 +1,23 @@
package com.microservices.mon.k8s.domain;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel("K8S Pod")
public class K8sApplicationPod {
@ApiModelProperty(value = "Pod Id")
private String id;
@ApiModelProperty(value = "Pod名称")
private String name;
@ApiModelProperty(value = "Pod Ip")
private String ip;
@ApiModelProperty(value = "容器id")
private String containerID;
}

View File

@ -1,5 +1,8 @@
package com.microservices.mon.k8s.domain.vo;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.microservices.common.core.utils.StringUtils;
import com.microservices.common.core.utils.bean.BeanUtils;
import com.microservices.mon.k8s.domain.K8sApplication;
import lombok.Data;
@ -23,17 +26,29 @@ public class RancherApplicationVo {
target.setAlias(metadata.getAnnotations().getString("mon-name"));
}
target.setName(metadata.getName());
if("DaemonSet".equals(kind)){
if ("DaemonSet".equals(kind)) {
target.setReplicas(status.getDesiredNumberScheduled());
target.setReadyReplicas(status.getNumberReady());
}else if("StatefulSet".equals(kind)){
} else if ("StatefulSet".equals(kind)) {
target.setReplicas(status.getReplicas());
target.setReadyReplicas(status.getAvailableReplicas());
}else{
} else {
target.setReplicas(status.getReplicas());
target.setReadyReplicas(status.getReadyReplicas());
}
target.setNamespace(metadata.getNamespace());
JSONArray relationships = metadata.getRelationships();
for (int i = 0; i < relationships.size(); i++) {
JSONObject relationship = relationships.getJSONObject(i);
if (relationship.containsKey("toType") && "pod".equals(relationship.getString("toType"))) {
String selector = relationship.getString("selector");
if (StringUtils.isNotEmpty(selector) && selector.contains("app=")) {
String appName = selector.substring(selector.indexOf("=") + 1);
target.setPodSelector(appName);
}
}
}
return target;
}
}

View File

@ -1,17 +1,33 @@
package com.microservices.mon.k8s.domain.vo;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.microservices.common.core.utils.StringUtils;
import com.microservices.common.core.utils.bean.BeanUtils;
import com.microservices.mon.k8s.domain.K8sApplication;
import com.microservices.mon.k8s.domain.K8sApplicationPod;
import lombok.Data;
@Data
public class RancherPodVo {
// 标识
String id;
// 应用类型
String kind;
// 元数据
RancherMetadataVo metadata;
// 状态
RancherPodStateVo status;
public K8sApplicationPod toK8sApplicationPod() {
K8sApplicationPod target = new K8sApplicationPod();
BeanUtils.copyProperties(this, target);
target.setIp(status.getPodIP());
if (metadata != null) {
if (metadata.getAnnotations() != null) {
target.setContainerID(metadata.getAnnotations().getString("cni.projectcalico.org/containerID"));
}
target.setName(metadata.getName());
}
return target;
}
}

View File

@ -6,7 +6,7 @@ import java.util.HashMap;
import java.util.List;
public interface IK8sDashboardService {
List<K8sNamespace> getNamespaceDetailList();
List<K8sNamespace> getNamespaceDetailList(boolean needPod);
List<K8sClusterNode> getClusterNodeList();

View File

@ -28,7 +28,7 @@ public class K8SDashboardServiceImpl extends CommonService implements IK8sDashbo
private RemoteGatewayService remoteGatewayService;
@Override
public List<K8sNamespace> getNamespaceDetailList() {
public List<K8sNamespace> getNamespaceDetailList(boolean needPod) {
List<RancherApplicationVo> rancherApplicationVoList = new ArrayList<>();
//调用rancher远程接口获取所有daemonsets列表
JSONObject daemonsetsJsonObject = remoteRancherService.getK8sDaemonsetsList(cluster_id, SecurityContextHolder.getUserKey());
@ -51,10 +51,27 @@ public class K8SDashboardServiceImpl extends CommonService implements IK8sDashbo
List<K8sNamespace> k8sNamespaceList = getK8sNamespaceList();
for (int i = 0; i < k8sNamespaceList.size(); i++) {
K8sNamespace k8sNamespace = k8sNamespaceList.get(i);
k8sNamespace.setApplicationList(k8sApplicationList
List<K8sApplication> namespaceApplicationList = k8sApplicationList
.stream()
.filter(k8sApplication -> k8sApplication.getNamespace().equals(k8sNamespace.getName()))
.collect(Collectors.toList()));
.collect(Collectors.toList());
if (needPod) {
// 获取命名空间下pod列表
JSONObject podListJson = remoteRancherService.getK8sPodListByNamespace(cluster_id, k8sNamespace.getName(), SecurityContextHolder.getUserKey());
List<RancherPodVo> rancherPodVoList;
if (podListJson != null && podListJson.containsKey("data")) {
rancherPodVoList = podListJson.getJSONArray("data").toList(RancherPodVo.class);
for (int j = 0; j < namespaceApplicationList.size(); j++) {
K8sApplication k8sApplication = namespaceApplicationList.get(j);
List<RancherPodVo> applicationToPodList = rancherPodVoList.stream()
.filter(rancherPodVo -> rancherPodVo.getMetadata().getLabels().containsKey("app") && rancherPodVo.getMetadata().getLabels().get("app").equals(k8sApplication.getPodSelector()))
.collect(Collectors.toList());
k8sApplication.setPodList(applicationToPodList.stream().map(RancherPodVo::toK8sApplicationPod).collect(Collectors.toList()));
namespaceApplicationList.set(j, k8sApplication);
}
}
}
k8sNamespace.setApplicationList(namespaceApplicationList);
k8sNamespaceList.set(i, k8sNamespace);
}
return k8sNamespaceList;

View File

@ -100,7 +100,7 @@ public class MonCommonAsyncServiceImpl extends CommonService implements IMonComm
});
CustomExecutorFactory.threadPoolExecutor.execute(() -> {
try {
List<K8sNamespace> k8sNamespaceList = k8sDashboardService.getNamespaceDetailList();
List<K8sNamespace> k8sNamespaceList = k8sDashboardService.getNamespaceDetailList(false);
k8sClusterStatus.setMicroserviceApplicationCount(k8sNamespaceList);
List<String> namespaceNameList = k8sNamespaceList.stream().map(K8sNamespace::getName).collect(Collectors.toList());
JSONObject microserviceRestartCountTodayJson = remoteGatewayService.getPrometheusQueryRes(PromQLConstant.MICROSERVICE_RESTART_COUNT_TODAY(cluster_id,namespaceNameList), SecurityContextHolder.getUserKey());