forked from Gitlink/microservices
Compare commits
30 Commits
master
...
dev_monito
| Author | SHA1 | Date |
|---|---|---|
|
|
15aa7016b9 | |
|
|
f96cee3f4a | |
|
|
055b26ee29 | |
|
|
368a45e8b2 | |
|
|
2c5f0518ca | |
|
|
06fbbf7208 | |
|
|
6613950ff8 | |
|
|
8184eb2401 | |
|
|
213aee5587 | |
|
|
274af358dd | |
|
|
58bf8326c5 | |
|
|
5e19e53b94 | |
|
|
2be36ca12e | |
|
|
ad405c912e | |
|
|
39d43e3d68 | |
|
|
1eefa65c32 | |
|
|
c6b4a1bd80 | |
|
|
21ba1ce6bd | |
|
|
dd870b3cd3 | |
|
|
417d440549 | |
|
|
67b2e9ce7c | |
|
|
32b83749e2 | |
|
|
010d5e5354 | |
|
|
94e0be0e71 | |
|
|
2845d19aae | |
|
|
97b1c9437c | |
|
|
b0f9e06e18 | |
|
|
f58af4b0b5 | |
|
|
78cbd4b0ee | |
|
|
fca8490bdd |
|
|
@ -1,15 +1,16 @@
|
||||||
package com.microservices.system.api;
|
package com.microservices.system.api;
|
||||||
|
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.microservices.common.core.constant.SecurityConstants;
|
||||||
import com.microservices.common.core.constant.ServiceNameConstants;
|
import com.microservices.common.core.constant.ServiceNameConstants;
|
||||||
|
import com.microservices.common.core.constant.TokenConstants;
|
||||||
import com.microservices.system.api.factory.RemoteGatewayFallbackFactory;
|
import com.microservices.system.api.factory.RemoteGatewayFallbackFactory;
|
||||||
import feign.Response;
|
import feign.Response;
|
||||||
import org.springframework.cloud.openfeign.FeignClient;
|
import org.springframework.cloud.openfeign.FeignClient;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -28,6 +29,14 @@ public interface RemoteGatewayService {
|
||||||
@PostMapping("/sentinel/auth/login")
|
@PostMapping("/sentinel/auth/login")
|
||||||
Response loginSentinel(@RequestParam("username") String username, @RequestParam("password") String password);
|
Response loginSentinel(@RequestParam("username") String username, @RequestParam("password") String password);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登录Rancher
|
||||||
|
*
|
||||||
|
* @return 响应
|
||||||
|
*/
|
||||||
|
@PostMapping("/rancher/v3-public/localProviders/local?action=login")
|
||||||
|
Response loginRancher(@RequestBody JSONObject loginBody);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 登录Nacos
|
* 登录Nacos
|
||||||
*
|
*
|
||||||
|
|
@ -43,4 +52,15 @@ public interface RemoteGatewayService {
|
||||||
*/
|
*/
|
||||||
@PostMapping("/portainer/api/auth")
|
@PostMapping("/portainer/api/auth")
|
||||||
Response loginPortainer(@RequestBody JSONObject loginBody);
|
Response loginPortainer(@RequestBody JSONObject loginBody);
|
||||||
|
|
||||||
|
@GetMapping("/prometheus/api/v1/query")
|
||||||
|
JSONObject getPrometheusQueryRes(@RequestParam("query") String query,
|
||||||
|
@RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||||
|
|
||||||
|
@GetMapping("/prometheus/api/v1/query_range")
|
||||||
|
JSONObject getPrometheusQueryRangeRes(@RequestParam("query") String query,
|
||||||
|
@RequestParam("step") Long step,
|
||||||
|
@RequestParam("start") Long start,
|
||||||
|
@RequestParam("end") Long end,
|
||||||
|
@RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
package com.microservices.system.api;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.microservices.common.core.constant.SecurityConstants;
|
||||||
|
import com.microservices.common.core.constant.ServiceNameConstants;
|
||||||
|
import com.microservices.common.core.constant.TokenConstants;
|
||||||
|
import com.microservices.system.api.factory.RemoteGatewayFallbackFactory;
|
||||||
|
import com.microservices.system.api.factory.RemoteRancherFallbackFactory;
|
||||||
|
import feign.Response;
|
||||||
|
import org.springframework.cloud.openfeign.FeignClient;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 网关
|
||||||
|
*
|
||||||
|
* @author microservices
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@FeignClient(contextId = "RemoteRancherService", value = ServiceNameConstants.GATEWAY_SERVICE, fallbackFactory = RemoteRancherFallbackFactory.class)
|
||||||
|
public interface RemoteRancherService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取命名空间列表
|
||||||
|
*
|
||||||
|
* @return 响应
|
||||||
|
*/
|
||||||
|
@GetMapping("/rancher/v3/clusters/{cluster_id}/namespaces")
|
||||||
|
JSONObject getK8sNamespaceList(@PathVariable("cluster_id") String cluster_id,
|
||||||
|
@RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||||
|
|
||||||
|
@GetMapping("/rancher/k8s/clusters/{cluster_id}/v1/apps.daemonsets?exclude=metadata.managedFields")
|
||||||
|
JSONObject getK8sDaemonsetsList(@PathVariable("cluster_id") String cluster_id,
|
||||||
|
@RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||||
|
|
||||||
|
@GetMapping("/rancher/k8s/clusters/{cluster_id}/v1/apps.deployments?exclude=metadata.managedFields")
|
||||||
|
JSONObject getK8sDeployList(@PathVariable("cluster_id") String cluster_id,
|
||||||
|
@RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||||
|
|
||||||
|
@GetMapping("/rancher/k8s/clusters/{cluster_id}/v1/apps.statefulsets?exclude=metadata.managedFields")
|
||||||
|
JSONObject getK8sStatefulList(@PathVariable("cluster_id") String cluster_id,
|
||||||
|
@RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||||
|
|
||||||
|
@GetMapping("/rancher/k8s/clusters/{cluster_id}/v1/nodes?exclude=metadata.managedFields")
|
||||||
|
JSONObject getK8sClusterNodeList(@PathVariable("cluster_id") String cluster_id,
|
||||||
|
@RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||||
|
|
||||||
|
@GetMapping("/rancher/k8s/clusters/{cluster_id}/v1/{fullKind}/{namespace}/{applicationName}")
|
||||||
|
JSONObject getK8sApplicationDetail(@PathVariable("cluster_id") String cluster_id,
|
||||||
|
@PathVariable("fullKind") String fullKind,
|
||||||
|
@PathVariable("namespace") String namespace,
|
||||||
|
@PathVariable("applicationName") String applicationName,
|
||||||
|
@RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||||
|
|
||||||
|
@GetMapping("/rancher/k8s/clusters/{cluster_id}/v1/pods/{namespace}")
|
||||||
|
JSONObject getK8sPodListByNamespace(@PathVariable("cluster_id") String cluster_id,
|
||||||
|
@PathVariable("namespace") String namespace,
|
||||||
|
@RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||||
|
|
||||||
|
@GetMapping("/rancher/k8s/clusters/{cluster_id}/v1/services/{nginxApplicationId}")
|
||||||
|
JSONObject getK8sServiceByApplicationId(@PathVariable("cluster_id") String cluster_id,
|
||||||
|
@PathVariable("nginxApplicationId") String nginxApplicationId,
|
||||||
|
@RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||||
|
}
|
||||||
|
|
@ -25,7 +25,12 @@ public class RemoteGatewayFallbackFactory implements FallbackFactory<RemoteGatew
|
||||||
return new RemoteGatewayService() {
|
return new RemoteGatewayService() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Response loginSentinel(String password, String username) {
|
public Response loginSentinel(String username, String password) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response loginRancher(JSONObject loginBody) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -36,7 +41,16 @@ public class RemoteGatewayFallbackFactory implements FallbackFactory<RemoteGatew
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Response loginPortainer(JSONObject loginBody) {
|
public Response loginPortainer(JSONObject loginBody) {
|
||||||
System.out.println(throwable.getMessage());
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JSONObject getPrometheusQueryRes(String query, String token) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JSONObject getPrometheusQueryRangeRes(String query, Long step, Long start, Long end, String token) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
package com.microservices.system.api.factory;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.microservices.system.api.RemoteGatewayService;
|
||||||
|
import com.microservices.system.api.RemoteRancherService;
|
||||||
|
import feign.Response;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.cloud.openfeign.FallbackFactory;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户服务降级处理
|
||||||
|
*
|
||||||
|
* @author microservices
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class RemoteRancherFallbackFactory implements FallbackFactory<RemoteRancherService> {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(RemoteRancherFallbackFactory.class);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RemoteRancherService create(Throwable throwable) {
|
||||||
|
log.error("Rancher服务调用失败:{}", throwable.getMessage());
|
||||||
|
return new RemoteRancherService() {
|
||||||
|
@Override
|
||||||
|
public JSONObject getK8sNamespaceList(String cluster_id, String token) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JSONObject getK8sDaemonsetsList(String cluster_id, String token) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JSONObject getK8sDeployList(String cluster_id, String token) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JSONObject getK8sStatefulList(String cluster_id, String token) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JSONObject getK8sClusterNodeList(String cluster_id, String token) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JSONObject getK8sApplicationDetail(String cluster_id, String fullKind, String namespace, String applicationName, String token) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JSONObject getK8sPodListByNamespace(String cluster_id, String namespace, String token) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JSONObject getK8sServiceByApplicationId(String cluster_id, String nginxApplicationId, String token) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -6,3 +6,4 @@ com.microservices.system.api.factory.RemoteCmsFallbackFactory
|
||||||
com.microservices.system.api.factory.RemoteZoneFallbackFactory
|
com.microservices.system.api.factory.RemoteZoneFallbackFactory
|
||||||
com.microservices.system.api.factory.RemotePmsFallbackFactory
|
com.microservices.system.api.factory.RemotePmsFallbackFactory
|
||||||
com.microservices.system.api.factory.RemoteGatewayFallbackFactory
|
com.microservices.system.api.factory.RemoteGatewayFallbackFactory
|
||||||
|
com.microservices.system.api.factory.RemoteRancherFallbackFactory
|
||||||
|
|
|
||||||
|
|
@ -213,6 +213,11 @@ public class CacheConstants {
|
||||||
*/
|
*/
|
||||||
public final static String SENTINEL_TOKEN = "sentinel_token";
|
public final static String SENTINEL_TOKEN = "sentinel_token";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rancher Token缓存Key
|
||||||
|
*/
|
||||||
|
public final static String RANCHER_TOKEN = "rancher_token";
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Nacos Token缓存Key
|
* Nacos Token缓存Key
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,11 @@ public class SecurityConstants
|
||||||
*/
|
*/
|
||||||
public static final String USER_KEY = "user_key";
|
public static final String USER_KEY = "user_key";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户Token
|
||||||
|
*/
|
||||||
|
public static final String TOKEN = "token";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 组织ID
|
* 组织ID
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -22,9 +22,16 @@ public class TokenConstants {
|
||||||
* Sentinel令牌标识
|
* Sentinel令牌标识
|
||||||
*/
|
*/
|
||||||
public static final String Sentinel_Token_Key = "sentinel_dashboard_cookie";
|
public static final String Sentinel_Token_Key = "sentinel_dashboard_cookie";
|
||||||
|
/**
|
||||||
|
* Rancher令牌标识
|
||||||
|
*/
|
||||||
|
public static final String Rancher_Cookie_Token_Key = "R_SESS";
|
||||||
|
/**
|
||||||
|
* Portainer令牌标识
|
||||||
|
*/
|
||||||
public static final String Portainer_Token_Key = "portainer_api_key";
|
public static final String Portainer_Token_Key = "portainer_api_key";
|
||||||
/**
|
/**
|
||||||
* Sentinel令牌标识
|
* Nacos令牌标识
|
||||||
*/
|
*/
|
||||||
public static final String Nacos_Token_Key = "Accesstoken";
|
public static final String Nacos_Token_Key = "Accesstoken";
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package com.microservices.common.core.threadPool;
|
package com.microservices.common.core.threadPool;
|
||||||
|
|
||||||
|
import com.microservices.common.core.constant.TokenConstants;
|
||||||
import com.microservices.common.core.context.SecurityContextHolder;
|
import com.microservices.common.core.context.SecurityContextHolder;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
@ -37,6 +38,9 @@ public class ThreadPoolExecutorWrap extends ThreadPoolExecutor {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
|
if(contextValue != null&&contextValue.containsKey("user_key")){
|
||||||
|
contextValue.put(TokenConstants.AUTHENTICATION, contextValue.get("user_key"));
|
||||||
|
}
|
||||||
SecurityContextHolder.setLocalMap(contextValue);
|
SecurityContextHolder.setLocalMap(contextValue);
|
||||||
// 用户任务逻辑
|
// 用户任务逻辑
|
||||||
task.run();
|
task.run();
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ public class GenericsTableDataInfo<T> implements Serializable {
|
||||||
/**
|
/**
|
||||||
* 面包屑数据
|
* 面包屑数据
|
||||||
*/
|
*/
|
||||||
@ApiModelProperty("面包屑数据")
|
@ApiModelProperty(value = "面包屑数据",hidden = true)
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL) //为空时隐藏
|
@JsonInclude(JsonInclude.Include.NON_NULL) //为空时隐藏
|
||||||
private List<Breadcrumb> breadcrumb;
|
private List<Breadcrumb> breadcrumb;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ public class GlobalResponseFilter implements GlobalFilter, Ordered {
|
||||||
String lowerUrl = request.getURI().getPath().toLowerCase();
|
String lowerUrl = request.getURI().getPath().toLowerCase();
|
||||||
ServerHttpResponse originalResponse = exchange.getResponse();
|
ServerHttpResponse originalResponse = exchange.getResponse();
|
||||||
DataBufferFactory bufferFactory = originalResponse.bufferFactory();
|
DataBufferFactory bufferFactory = originalResponse.bufferFactory();
|
||||||
|
|
||||||
// 当请求为Nacos时,Nacos返回的所有非JSON响应都会被自动转换为结构化的错误信息,同时将HTTP状态码设置为200,适合用于规范化微服务架构的响应格式。
|
// 当请求为Nacos时,Nacos返回的所有非JSON响应都会被自动转换为结构化的错误信息,同时将HTTP状态码设置为200,适合用于规范化微服务架构的响应格式。
|
||||||
if (lowerUrl.startsWith("/nacos")) {
|
if (lowerUrl.startsWith("/nacos")) {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,10 @@ public class ThirdPartyToolServiceImpl implements ThirdPartyToolService {
|
||||||
public String portainerUsername;
|
public String portainerUsername;
|
||||||
@Value("${thirdPartyTools.portainer.auth.password:}")
|
@Value("${thirdPartyTools.portainer.auth.password:}")
|
||||||
public String portainerPassword;
|
public String portainerPassword;
|
||||||
|
@Value("${thirdPartyTools.rancher.auth.username:}")
|
||||||
|
public String rancherUsername;
|
||||||
|
@Value("${thirdPartyTools.rancher.auth.password:}")
|
||||||
|
public String rancherPassword;
|
||||||
@Value("${thirdPartyTools.portainer.endpoints:}")
|
@Value("${thirdPartyTools.portainer.endpoints:}")
|
||||||
public Integer portainerEndpoints;
|
public Integer portainerEndpoints;
|
||||||
ThreadPoolExecutor threadPoolExecutor = CustomExecutorFactory.threadPoolExecutor;
|
ThreadPoolExecutor threadPoolExecutor = CustomExecutorFactory.threadPoolExecutor;
|
||||||
|
|
@ -106,6 +110,44 @@ public class ThirdPartyToolServiceImpl implements ThirdPartyToolService {
|
||||||
throw new ServiceException("Sentinel服务获取Token失败");
|
throw new ServiceException("Sentinel服务获取Token失败");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 处理Rancher请求
|
||||||
|
if (lowerUrl.startsWith("/rancher")) {
|
||||||
|
String rancherToken = null;
|
||||||
|
if (redisService.hasKey(CacheConstants.RANCHER_TOKEN)) {
|
||||||
|
rancherToken = redisService.getCacheObject(CacheConstants.RANCHER_TOKEN);
|
||||||
|
} else {
|
||||||
|
JSONObject loginRancherBody = new JSONObject();
|
||||||
|
loginRancherBody.put("description", "api session");
|
||||||
|
loginRancherBody.put("responseType", "cookie");
|
||||||
|
loginRancherBody.put("username", rancherUsername);
|
||||||
|
loginRancherBody.put("password", rancherPassword);
|
||||||
|
|
||||||
|
// 网关采用异步架构,所以此处需要通过异步请求获取Sentinel Token
|
||||||
|
Future<Response> future = threadPoolExecutor.submit(() -> remoteGatewayService.loginRancher(loginRancherBody));
|
||||||
|
try {
|
||||||
|
Response response = future.get(1, TimeUnit.SECONDS);
|
||||||
|
Map<String, Collection<String>> header = response.headers();
|
||||||
|
if (header != null && header.containsKey("set-cookie")) {
|
||||||
|
String rancherCookie = header.get("set-cookie").iterator().next();
|
||||||
|
rancherToken = getValueByCookieKey(rancherCookie,TokenConstants.Rancher_Cookie_Token_Key);
|
||||||
|
//Rancher登录状态默认15小时失效,将Rancher Token缓存过期时间调整为14分钟
|
||||||
|
redisService.setCacheObject(CacheConstants.RANCHER_TOKEN, rancherToken, 14L, TimeUnit.HOURS);
|
||||||
|
|
||||||
|
}
|
||||||
|
} catch (TimeoutException e) {
|
||||||
|
log.error("获取Rancher Token超时");
|
||||||
|
} catch (InterruptedException | ExecutionException e) {
|
||||||
|
log.error("获取Rancher Token失败:{}", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotEmpty(rancherToken)) {
|
||||||
|
ServletUtils.removeHeader(mutate, TokenConstants.AUTHENTICATION);
|
||||||
|
mutate.header(TokenConstants.AUTHENTICATION, TokenConstants.PREFIX + rancherToken);
|
||||||
|
} else {
|
||||||
|
throw new ServiceException("Rancher服务获取Token失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
// 处理Nacos请求
|
// 处理Nacos请求
|
||||||
if (lowerUrl.startsWith("/nacos")) {
|
if (lowerUrl.startsWith("/nacos")) {
|
||||||
String nacosToken = null;
|
String nacosToken = null;
|
||||||
|
|
@ -229,4 +271,20 @@ public class ThirdPartyToolServiceImpl implements ThirdPartyToolService {
|
||||||
log.error("[第三方工具请求处理异常]请求路径:{},异常信息:{}", exchange.getRequest().getPath(), msg);
|
log.error("[第三方工具请求处理异常]请求路径:{},异常信息:{}", exchange.getRequest().getPath(), msg);
|
||||||
return ServletUtils.webFluxResponseWriter(exchange.getResponse(), ExceptionMsgConstants.SYSTEM_EXEC_ERROR, code);
|
return ServletUtils.webFluxResponseWriter(exchange.getResponse(), ExceptionMsgConstants.SYSTEM_EXEC_ERROR, code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过指定Key获取Cookie中指定值
|
||||||
|
*/
|
||||||
|
private static String getValueByCookieKey(String cookie, String key) {
|
||||||
|
if (cookie != null) {
|
||||||
|
String[] cookies = StringUtils.split(cookie, ';');
|
||||||
|
for (String cookieItem : cookies) {
|
||||||
|
if (cookieItem.contains(key)) {
|
||||||
|
String token = StringUtils.remove(cookieItem, key+"=");
|
||||||
|
return StringUtils.remove(token, " ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,127 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<parent>
|
||||||
|
<groupId>com.microservices</groupId>
|
||||||
|
<artifactId>microservices-modules</artifactId>
|
||||||
|
<version>3.6.2</version>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>microservices-modules-mon</artifactId>
|
||||||
|
|
||||||
|
<description>
|
||||||
|
microservices-modules-mon运维监控模块
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
|
||||||
|
<!-- SpringCloud Alibaba Nacos -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- SpringCloud Alibaba Nacos Config -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- SpringCloud Alibaba Sentinel -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- SpringBoot Actuator -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Swagger UI -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.springfox</groupId>
|
||||||
|
<artifactId>springfox-swagger-ui</artifactId>
|
||||||
|
<version>${swagger.fox.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Mysql Connector -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>mysql</groupId>
|
||||||
|
<artifactId>mysql-connector-java</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Microservices Common Async -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.microservices</groupId>
|
||||||
|
<artifactId>microservices-common-async</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Microservices Common DataSource -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.microservices</groupId>
|
||||||
|
<artifactId>microservices-common-datasource</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Microservices Common DataScope -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.microservices</groupId>
|
||||||
|
<artifactId>microservices-common-datascope</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Microservices Common Log -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.microservices</groupId>
|
||||||
|
<artifactId>microservices-common-log</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Microservices Common Swagger -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.microservices</groupId>
|
||||||
|
<artifactId>microservices-common-swagger</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.microservices</groupId>
|
||||||
|
<artifactId>microservices-common-security</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.security</groupId>
|
||||||
|
<artifactId>spring-security-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.microservices</groupId>
|
||||||
|
<artifactId>microservices-common-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.microservices</groupId>
|
||||||
|
<artifactId>microservices-common-httpClient</artifactId>
|
||||||
|
<version>3.6.2</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<finalName>${project.artifactId}</finalName>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>repackage</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
package com.microservices.mon;
|
||||||
|
|
||||||
|
import com.microservices.common.security.annotation.EnableCustomConfig;
|
||||||
|
import com.microservices.common.security.annotation.EnableRyFeignClients;
|
||||||
|
import com.microservices.common.swagger.annotation.EnableCustomSwagger2;
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 运维监控模块
|
||||||
|
*
|
||||||
|
* @author otto
|
||||||
|
*/
|
||||||
|
@EnableCustomConfig
|
||||||
|
@EnableCustomSwagger2
|
||||||
|
@EnableRyFeignClients
|
||||||
|
@SpringBootApplication
|
||||||
|
public class MicroservicesMonApplication {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(MicroservicesMonApplication.class, args);
|
||||||
|
System.out.println("(♥◠‿◠)ノ゙ 运维监控模块启动成功 ლ(´ڡ`ლ)゙ \n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,75 @@
|
||||||
|
package com.microservices.mon.k8s.controller;
|
||||||
|
|
||||||
|
import com.microservices.common.core.web.controller.BaseController;
|
||||||
|
import com.microservices.common.core.web.domain.GenericsAjaxResult;
|
||||||
|
import com.microservices.common.core.web.page.GenericsTableDataInfo;
|
||||||
|
import com.microservices.mon.k8s.domain.*;
|
||||||
|
import com.microservices.mon.k8s.service.IK8sDashboardService;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("dashboard")
|
||||||
|
@Api(tags = "微服务大屏")
|
||||||
|
public class K8sDashboardController extends BaseController {
|
||||||
|
@Autowired
|
||||||
|
private IK8sDashboardService k8sNamespaceService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取命名空间列表
|
||||||
|
*/
|
||||||
|
@ApiOperation(value = "获取命名空间列表")
|
||||||
|
@GetMapping("/namespace/list")
|
||||||
|
public GenericsTableDataInfo<K8sNamespace> namespaceList() {
|
||||||
|
return new GenericsTableDataInfo<>(k8sNamespaceService.getNamespaceDetailList(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "获取集群节点列表")
|
||||||
|
@GetMapping("/cluster/Nodelist")
|
||||||
|
public GenericsTableDataInfo<K8sClusterNode> clusterNodeList() {
|
||||||
|
return new GenericsTableDataInfo<>(k8sNamespaceService.getClusterNodeList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "获取应用Pod Ip列表")
|
||||||
|
@GetMapping("/application/{kind}/{namespace}/{applicationName}/podIdList")
|
||||||
|
public GenericsTableDataInfo<String> applicationPodIdList(@PathVariable("kind") String kind, @PathVariable("namespace") String namespace, @PathVariable("applicationName") String applicationName) {
|
||||||
|
return new GenericsTableDataInfo<>(k8sNamespaceService.getApplicationPodIdList(kind, namespace, applicationName));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "获取集群状态数据")
|
||||||
|
@GetMapping("/cluster/status")
|
||||||
|
public GenericsAjaxResult<K8sClusterStatus> clusterStatus() {
|
||||||
|
return GenericsAjaxResult.success(k8sNamespaceService.getClusterStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "集群每秒请求率(QPS)")
|
||||||
|
@GetMapping("/cluster/qps")
|
||||||
|
public GenericsTableDataInfo<MetricCommonData> clusterQps() {
|
||||||
|
return new GenericsTableDataInfo<>(k8sNamespaceService.getClusterQps());
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "最近24小时应用接口请求次数")
|
||||||
|
@GetMapping("/cluster/applicationRequestCount")
|
||||||
|
public GenericsTableDataInfo<ApplicationRequestCountData> applicationRequestCount() {
|
||||||
|
return new GenericsTableDataInfo<>(k8sNamespaceService.getApplicationRequestCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "获取Pod容器状态")
|
||||||
|
@GetMapping("/cluster/podContainerStatus/{containerID}")
|
||||||
|
public GenericsAjaxResult<K8sPodContainerStatus> podContainerStatus(@PathVariable("containerID") String containerID) {
|
||||||
|
return GenericsAjaxResult.success(k8sNamespaceService.getPodContainerStatus(containerID));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "获取服务器节点状态")
|
||||||
|
@GetMapping("/cluster/nodeStatus/{nodeIp}")
|
||||||
|
public GenericsAjaxResult<K8sNodeStatus> nodeStatus(@PathVariable("nodeIp") String nodeIp) {
|
||||||
|
return GenericsAjaxResult.success(k8sNamespaceService.getNodeStatus(nodeIp));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
package com.microservices.mon.k8s.domain;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ApiModel("应用请求次数对象")
|
||||||
|
public class ApplicationRequestCountData {
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "序号")
|
||||||
|
private Integer number;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "应用名称")
|
||||||
|
private String applicationAlias;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "请求次数")
|
||||||
|
private Long requestCount;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
package com.microservices.mon.k8s.domain;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ApiModel("K8S应用")
|
||||||
|
public class K8sApplication {
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "应用Id")
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "应用名称")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "应用别名")
|
||||||
|
private String alias;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "应用类型")
|
||||||
|
private String kind;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "所属命名空间")
|
||||||
|
private String namespace;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "副本数量")
|
||||||
|
private Integer replicas;
|
||||||
|
|
||||||
|
@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";
|
||||||
|
} else if ("StatefulSet".equals(kind)) {
|
||||||
|
return "apps.statefulsets";
|
||||||
|
} else if("Deployment".equals(kind)){
|
||||||
|
return "apps.deployments";
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
package com.microservices.mon.k8s.domain;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ApiModel("集群节点")
|
||||||
|
public class K8sClusterNode {
|
||||||
|
@ApiModelProperty(value = "节点标识")
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "节点名称")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "节点IP")
|
||||||
|
private String ip;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "节点角色(Master/Worker)")
|
||||||
|
private String role;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "是否就绪")
|
||||||
|
private Boolean Ready;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,123 @@
|
||||||
|
package com.microservices.mon.k8s.domain;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.microservices.mon.k8s.domain.vo.PrometheusResVo;
|
||||||
|
import com.microservices.mon.k8s.domain.vo.PrometheusResultVo;
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ApiModel("集群状态")
|
||||||
|
public class K8sClusterStatus {
|
||||||
|
@ApiModelProperty(value = "集群节点数量")
|
||||||
|
private Integer nodeCount;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "不可用节点数量")
|
||||||
|
private Integer unavailableNodeCount;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "Pod使用率")
|
||||||
|
private Float podUsage;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "CPU使用率")
|
||||||
|
private Float cpuUsage;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "内存使用率")
|
||||||
|
private Float memoryUsage;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "最近24小时请求总数")
|
||||||
|
private Long totalRequestCountToday;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "最近24小时请求平均处理时间(单位:ms)")
|
||||||
|
private Float averageRequestProcessingTimeToday;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "最近24小时请求成功率")
|
||||||
|
private Float requestSuccessRateToday;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "微服务应用数量")
|
||||||
|
private Integer microserviceApplicationCount;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "最近24小时微服务重启次数")
|
||||||
|
private Integer microserviceRestartCountToday;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "微服务Pod运行状态(Key代表状态,Value代表数量)")
|
||||||
|
private HashMap<String, Integer> podStatus;
|
||||||
|
|
||||||
|
public void setNodeCount(PrometheusResVo prometheusResVo) {
|
||||||
|
this.nodeCount = Integer.parseInt(getPromStringValue(prometheusResVo));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUnavailableNodeCount(PrometheusResVo prometheusResVo) {
|
||||||
|
this.unavailableNodeCount = Integer.parseInt(getPromStringValue(prometheusResVo));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCpuUsage(PrometheusResVo prometheusResVo) {
|
||||||
|
this.cpuUsage = Float.parseFloat(getPromStringValue(prometheusResVo));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPodUsage(PrometheusResVo prometheusResVo) {
|
||||||
|
this.podUsage = Float.parseFloat(getPromStringValue(prometheusResVo));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMemoryUsage(PrometheusResVo prometheusResVo) {
|
||||||
|
this.memoryUsage = Float.parseFloat(getPromStringValue(prometheusResVo));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTotalRequestCountToday(PrometheusResVo prometheusResVo) {
|
||||||
|
this.totalRequestCountToday = Long.parseLong(getPromStringValue(prometheusResVo));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAverageRequestProcessingTimeToday(PrometheusResVo prometheusResVo) {
|
||||||
|
this.averageRequestProcessingTimeToday = Float.parseFloat(getPromStringValue(prometheusResVo));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRequestSuccessRateToday(PrometheusResVo prometheusResVo) {
|
||||||
|
this.requestSuccessRateToday = Float.parseFloat(getPromStringValue(prometheusResVo));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMicroserviceApplicationCount(List<K8sNamespace> k8sNamespaceList) {
|
||||||
|
this.microserviceApplicationCount = k8sNamespaceList.stream().map(x -> x.getApplicationList().size()).reduce(0, Integer::sum);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMicroserviceRestartCountToday(PrometheusResVo prometheusResVo) {
|
||||||
|
this.microserviceRestartCountToday = (int) Float.parseFloat(getPromStringValue(prometheusResVo));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPodStatus(PrometheusResVo prometheusResVo) {
|
||||||
|
HashMap<String, Integer> podStatus = new HashMap<>();
|
||||||
|
if (prometheusResVo != null && prometheusResVo.isSuccess()) {
|
||||||
|
List<PrometheusResultVo> resultList = prometheusResVo.getData().getResult();
|
||||||
|
for (PrometheusResultVo result : resultList) {
|
||||||
|
Integer value = result.getValue().getIntValue(1);
|
||||||
|
switch (result.getMetric().getString("phase")) {
|
||||||
|
case "Running":
|
||||||
|
podStatus.put("运行中", value);
|
||||||
|
break;
|
||||||
|
case "Pending":
|
||||||
|
podStatus.put("等待中", value);
|
||||||
|
break;
|
||||||
|
case "Succeeded":
|
||||||
|
podStatus.put("运行已完成", value);
|
||||||
|
break;
|
||||||
|
case "Failed":
|
||||||
|
podStatus.put("运行失败", value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.podStatus = podStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getPromStringValue(PrometheusResVo prometheusResVo) {
|
||||||
|
String value = "";
|
||||||
|
if (prometheusResVo != null && prometheusResVo.isSuccess()) {
|
||||||
|
PrometheusResultVo result = prometheusResVo.getData().getResult().get(0);
|
||||||
|
return result.getValue().getString(1);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
package com.microservices.mon.k8s.domain;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ApiModel("命名空间")
|
||||||
|
public class K8sNamespace {
|
||||||
|
@ApiModelProperty(value = "命名空间标识")
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "命名空间键值")
|
||||||
|
private String key;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "命名空间名称")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "命名空间别名(中文)")
|
||||||
|
private String alias;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "应用列表")
|
||||||
|
private List<K8sApplication> applicationList;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
package com.microservices.mon.k8s.domain;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ApiModel("K8S Node状态")
|
||||||
|
public class K8sNodeStatus {
|
||||||
|
@ApiModelProperty(value = "节点IP")
|
||||||
|
private String nodeIp;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "CPU使用率")
|
||||||
|
private Float cpuUsage;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "内存使用率")
|
||||||
|
private Float memoryUsage;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
package com.microservices.mon.k8s.domain;
|
||||||
|
|
||||||
|
import com.microservices.mon.k8s.domain.vo.PrometheusResVo;
|
||||||
|
import com.microservices.mon.k8s.domain.vo.PrometheusResultVo;
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ApiModel("K8S Pod状态")
|
||||||
|
public class K8sPodContainerStatus {
|
||||||
|
@ApiModelProperty(value = "Pod名称")
|
||||||
|
private String podName;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "CPU使用率")
|
||||||
|
private Float cpuUsage;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "内存使用情况")
|
||||||
|
private String memoryUsage;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
package com.microservices.mon.k8s.domain;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ApiModel("指标通用对象")
|
||||||
|
public class MetricCommonData {
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "时间")
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private Date date;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "指标值")
|
||||||
|
private Float value;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
package com.microservices.mon.k8s.domain.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class PrometheusDataVo {
|
||||||
|
// 查询结果类型
|
||||||
|
String resultType;
|
||||||
|
// 应用类型
|
||||||
|
List<PrometheusResultVo> result;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
package com.microservices.mon.k8s.domain.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class PrometheusResVo {
|
||||||
|
// 状态(success代表成功)
|
||||||
|
String status;
|
||||||
|
// 数据
|
||||||
|
PrometheusDataVo data;
|
||||||
|
|
||||||
|
public boolean isSuccess() {
|
||||||
|
return "success".equals(status)
|
||||||
|
&& data != null
|
||||||
|
&& !data.getResult().isEmpty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
package com.microservices.mon.k8s.domain.vo;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONArray;
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class PrometheusResultVo {
|
||||||
|
// 指标数据
|
||||||
|
JSONObject metric;
|
||||||
|
// 指标值
|
||||||
|
JSONArray value;
|
||||||
|
// 范围查询时指标值
|
||||||
|
JSONArray values;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
package com.microservices.mon.k8s.domain.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class RancherApplicationStateVo {
|
||||||
|
|
||||||
|
// Daemonsets-期望数量
|
||||||
|
Integer desiredNumberScheduled;
|
||||||
|
|
||||||
|
// Daemonsets-就绪数量
|
||||||
|
Integer numberReady;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Deploy/Stateful-就绪副本数
|
||||||
|
Integer readyReplicas;
|
||||||
|
|
||||||
|
// Stateful-有效副本数
|
||||||
|
Integer availableReplicas;
|
||||||
|
|
||||||
|
// Deploy/Stateful-副本数量
|
||||||
|
Integer replicas;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
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;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class RancherApplicationVo {
|
||||||
|
// 标识
|
||||||
|
String id;
|
||||||
|
// 应用类型
|
||||||
|
String kind;
|
||||||
|
// 元数据
|
||||||
|
RancherMetadataVo metadata;
|
||||||
|
// 状态
|
||||||
|
RancherApplicationStateVo status;
|
||||||
|
|
||||||
|
|
||||||
|
public K8sApplication toK8sApplication() {
|
||||||
|
K8sApplication target = new K8sApplication();
|
||||||
|
BeanUtils.copyProperties(this, target);
|
||||||
|
if (metadata.getAnnotations() != null && metadata.getAnnotations().containsKey("mon-name")) {
|
||||||
|
target.setAlias(metadata.getAnnotations().getString("mon-name"));
|
||||||
|
}
|
||||||
|
target.setName(metadata.getName());
|
||||||
|
if ("DaemonSet".equals(kind)) {
|
||||||
|
target.setReplicas(status.getDesiredNumberScheduled());
|
||||||
|
target.setReadyReplicas(status.getNumberReady());
|
||||||
|
} else if ("StatefulSet".equals(kind)) {
|
||||||
|
target.setReplicas(status.getReplicas());
|
||||||
|
target.setReadyReplicas(status.getAvailableReplicas());
|
||||||
|
} 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
package com.microservices.mon.k8s.domain.vo;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONArray;
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class RancherClusterNodeStateVo {
|
||||||
|
|
||||||
|
// ip地址
|
||||||
|
JSONArray addresses;
|
||||||
|
|
||||||
|
// 资源分配
|
||||||
|
JSONObject allocatable;
|
||||||
|
|
||||||
|
// 节点状况
|
||||||
|
JSONArray conditions;
|
||||||
|
|
||||||
|
// 节点信息
|
||||||
|
JSONObject nodeInfo;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
package com.microservices.mon.k8s.domain.vo;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONArray;
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.microservices.common.core.utils.bean.BeanUtils;
|
||||||
|
import com.microservices.mon.k8s.domain.K8sApplication;
|
||||||
|
import com.microservices.mon.k8s.domain.K8sClusterNode;
|
||||||
|
import com.microservices.mon.k8s.domain.K8sNamespace;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class RancherClusterNodeVo {
|
||||||
|
// 标识
|
||||||
|
String id;
|
||||||
|
// 元数据
|
||||||
|
RancherMetadataVo metadata;
|
||||||
|
// 节点状态
|
||||||
|
RancherClusterNodeStateVo status;
|
||||||
|
|
||||||
|
public K8sClusterNode toK8sClusterNode() {
|
||||||
|
K8sClusterNode target = new K8sClusterNode();
|
||||||
|
BeanUtils.copyProperties(this, target);
|
||||||
|
if (metadata.getLabels() != null && metadata.getLabels().containsKey("node-role.kubernetes.io/control-plane")) {
|
||||||
|
target.setRole("Master");
|
||||||
|
}else{
|
||||||
|
target.setRole("Worker");
|
||||||
|
}
|
||||||
|
target.setName(metadata.getName());
|
||||||
|
if(status!=null&&status.getAddresses()!=null){
|
||||||
|
JSONArray addresses=status.getAddresses();
|
||||||
|
for (int i = 0; i < addresses.size(); i++) {
|
||||||
|
JSONObject jsonObject = addresses.getJSONObject(i);
|
||||||
|
if (jsonObject.getString("type").equals("InternalIP")) {
|
||||||
|
target.setIp(jsonObject.getString("address"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
JSONArray conditions=status.getConditions();
|
||||||
|
for (int i = 0; i < conditions.size(); i++) {
|
||||||
|
JSONObject jsonObject = conditions.getJSONObject(i);
|
||||||
|
if (jsonObject.getString("type").equals("Ready")) {
|
||||||
|
target.setReady(jsonObject.getBoolean("status"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
package com.microservices.mon.k8s.domain.vo;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONArray;
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class RancherMetadataVo {
|
||||||
|
// 所属命名空间
|
||||||
|
String namespace;
|
||||||
|
// 创建时间
|
||||||
|
Date creationTimestamp;
|
||||||
|
// 描述
|
||||||
|
JSONObject annotations;
|
||||||
|
// 关联数据
|
||||||
|
JSONArray relationships;
|
||||||
|
// 标签
|
||||||
|
JSONObject labels;
|
||||||
|
// 名称
|
||||||
|
String name;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
package com.microservices.mon.k8s.domain.vo;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.microservices.common.core.utils.bean.BeanUtils;
|
||||||
|
import com.microservices.mon.k8s.domain.K8sNamespace;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class RancherNamespaceVo {
|
||||||
|
// 描述
|
||||||
|
JSONObject annotations;
|
||||||
|
//创建时间
|
||||||
|
Date created;
|
||||||
|
// 标识
|
||||||
|
String id;
|
||||||
|
// 标签
|
||||||
|
JSONObject labels;
|
||||||
|
// 名称
|
||||||
|
String name;
|
||||||
|
// 状态
|
||||||
|
String state;
|
||||||
|
|
||||||
|
public K8sNamespace toK8sNamespace() {
|
||||||
|
K8sNamespace target = new K8sNamespace();
|
||||||
|
BeanUtils.copyProperties(this, target);
|
||||||
|
target.setKey(labels.getString("mon-key"));
|
||||||
|
target.setAlias(annotations.getString("mon-name"));
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
package com.microservices.mon.k8s.domain.vo;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONArray;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class RancherPodStateVo {
|
||||||
|
|
||||||
|
// Pod状况
|
||||||
|
JSONArray conditions;
|
||||||
|
|
||||||
|
// Pod Ip
|
||||||
|
String podIP;
|
||||||
|
|
||||||
|
// 启动时间
|
||||||
|
Date startTime;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +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;
|
||||||
|
// 元数据
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
package com.microservices.mon.k8s.domain.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class RancherServicePortsVo {
|
||||||
|
|
||||||
|
// 端口名称
|
||||||
|
String name;
|
||||||
|
|
||||||
|
// 映射端口
|
||||||
|
Integer nodePort;
|
||||||
|
|
||||||
|
// 内部端口
|
||||||
|
Integer port;
|
||||||
|
|
||||||
|
// 协议
|
||||||
|
String protocol;
|
||||||
|
|
||||||
|
// 目标端口
|
||||||
|
Integer targetPort;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
package com.microservices.mon.k8s.domain.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class RancherServiceSpecVo {
|
||||||
|
|
||||||
|
// 端口映射列表
|
||||||
|
List<RancherServicePortsVo> ports;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
package com.microservices.mon.k8s.domain.vo;
|
||||||
|
|
||||||
|
import com.microservices.common.core.utils.bean.BeanUtils;
|
||||||
|
import com.microservices.mon.k8s.domain.K8sApplication;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class RancherServiceVo {
|
||||||
|
// 标识
|
||||||
|
String id;
|
||||||
|
// 元数据
|
||||||
|
RancherMetadataVo metadata;
|
||||||
|
// 状态
|
||||||
|
RancherServiceSpecVo spec;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
package com.microservices.mon.k8s.service;
|
||||||
|
|
||||||
|
import com.microservices.mon.k8s.domain.*;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface IK8sDashboardService {
|
||||||
|
List<K8sNamespace> getNamespaceDetailList(boolean needPod);
|
||||||
|
|
||||||
|
List<K8sClusterNode> getClusterNodeList();
|
||||||
|
|
||||||
|
List<String> getApplicationPodIdList(String kind, String namespace,String applicationName);
|
||||||
|
|
||||||
|
K8sClusterStatus getClusterStatus();
|
||||||
|
|
||||||
|
List<MetricCommonData> getClusterQps();
|
||||||
|
|
||||||
|
List<ApplicationRequestCountData> getApplicationRequestCount();
|
||||||
|
|
||||||
|
K8sPodContainerStatus getPodContainerStatus(String containerID);
|
||||||
|
|
||||||
|
K8sNodeStatus getNodeStatus(String nodeIp);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
package com.microservices.mon.k8s.service;
|
||||||
|
|
||||||
|
import com.microservices.mon.k8s.domain.K8sClusterStatus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 运维监控Service异步接口
|
||||||
|
*/
|
||||||
|
public interface IMonCommonAsyncService {
|
||||||
|
|
||||||
|
K8sClusterStatus getClusterStatus(String query);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
package com.microservices.mon.k8s.service.impl;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public abstract class CommonService {
|
||||||
|
@Value("${rancher.cluster_id}")
|
||||||
|
public String cluster_id;
|
||||||
|
|
||||||
|
@Value("${rancher.nginxApplicationId}")
|
||||||
|
public String nginxApplicationId;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,258 @@
|
||||||
|
package com.microservices.mon.k8s.service.impl;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONArray;
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.microservices.common.core.context.SecurityContextHolder;
|
||||||
|
import com.microservices.common.core.utils.DateUtils;
|
||||||
|
import com.microservices.common.core.utils.StringUtils;
|
||||||
|
import com.microservices.mon.k8s.domain.*;
|
||||||
|
import com.microservices.mon.k8s.domain.vo.*;
|
||||||
|
import com.microservices.mon.k8s.service.IK8sDashboardService;
|
||||||
|
import com.microservices.mon.k8s.service.IMonCommonAsyncService;
|
||||||
|
import com.microservices.mon.k8s.utils.PromQLConstant;
|
||||||
|
import com.microservices.system.api.RemoteGatewayService;
|
||||||
|
import com.microservices.system.api.RemoteRancherService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class K8SDashboardServiceImpl extends CommonService implements IK8sDashboardService {
|
||||||
|
@Autowired
|
||||||
|
private RemoteRancherService remoteRancherService;
|
||||||
|
@Autowired
|
||||||
|
private IMonCommonAsyncService monCommonAsyncService;
|
||||||
|
@Autowired
|
||||||
|
private RemoteGatewayService remoteGatewayService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<K8sNamespace> getNamespaceDetailList(boolean needPod) {
|
||||||
|
List<RancherApplicationVo> rancherApplicationVoList = new ArrayList<>();
|
||||||
|
//调用rancher远程接口获取所有daemonsets列表
|
||||||
|
JSONObject daemonsetsJsonObject = remoteRancherService.getK8sDaemonsetsList(cluster_id, SecurityContextHolder.getUserKey());
|
||||||
|
if (daemonsetsJsonObject != null && daemonsetsJsonObject.containsKey("data")) {
|
||||||
|
rancherApplicationVoList.addAll(daemonsetsJsonObject.getJSONArray("data").toList(RancherApplicationVo.class));
|
||||||
|
}
|
||||||
|
//调用rancher远程接口获取所有deploy列表
|
||||||
|
JSONObject deployJsonObject = remoteRancherService.getK8sDeployList(cluster_id, SecurityContextHolder.getUserKey());
|
||||||
|
if (deployJsonObject != null && deployJsonObject.containsKey("data")) {
|
||||||
|
rancherApplicationVoList.addAll(deployJsonObject.getJSONArray("data").toList(RancherApplicationVo.class));
|
||||||
|
}
|
||||||
|
//调用rancher远程接口获取所有Stateful列表
|
||||||
|
JSONObject statefulJsonObject = remoteRancherService.getK8sStatefulList(cluster_id, SecurityContextHolder.getUserKey());
|
||||||
|
if (statefulJsonObject != null && statefulJsonObject.containsKey("data")) {
|
||||||
|
rancherApplicationVoList.addAll(statefulJsonObject.getJSONArray("data").toList(RancherApplicationVo.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将rancher对象转换为k8s对象
|
||||||
|
List<K8sApplication> k8sApplicationList = rancherApplicationVoList.stream().map(RancherApplicationVo::toK8sApplication).collect(Collectors.toList());
|
||||||
|
List<K8sNamespace> k8sNamespaceList = getK8sNamespaceList();
|
||||||
|
for (int i = 0; i < k8sNamespaceList.size(); i++) {
|
||||||
|
K8sNamespace k8sNamespace = k8sNamespaceList.get(i);
|
||||||
|
List<K8sApplication> namespaceApplicationList = k8sApplicationList
|
||||||
|
.stream()
|
||||||
|
.filter(k8sApplication -> k8sApplication.getNamespace().equals(k8sNamespace.getName()))
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<K8sClusterNode> getClusterNodeList() {
|
||||||
|
List<RancherClusterNodeVo> rancherClusterNodeVoList;
|
||||||
|
//调用rancher远程接口获取集群节点列表
|
||||||
|
JSONObject clusterNodeJsonObject = remoteRancherService.getK8sClusterNodeList(cluster_id, SecurityContextHolder.getUserKey());
|
||||||
|
if (clusterNodeJsonObject != null && clusterNodeJsonObject.containsKey("data")) {
|
||||||
|
rancherClusterNodeVoList = clusterNodeJsonObject.getJSONArray("data").toList(RancherClusterNodeVo.class);
|
||||||
|
return rancherClusterNodeVoList.stream().map(RancherClusterNodeVo::toK8sClusterNode).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getApplicationPodIdList(String kind, String namespace, String applicationName) {
|
||||||
|
JSONObject applicationJson = remoteRancherService.getK8sApplicationDetail(cluster_id, K8sApplication.getApplicationFullKind(kind), namespace, applicationName, SecurityContextHolder.getUserKey());
|
||||||
|
RancherApplicationVo rancherApplicationVo = applicationJson.toJavaObject(RancherApplicationVo.class);
|
||||||
|
if (rancherApplicationVo != null && rancherApplicationVo.getMetadata() != null && rancherApplicationVo.getMetadata().getRelationships() != null) {
|
||||||
|
JSONArray relationships = rancherApplicationVo.getMetadata().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);
|
||||||
|
JSONObject podListJson = remoteRancherService.getK8sPodListByNamespace(cluster_id, namespace, SecurityContextHolder.getUserKey());
|
||||||
|
if (podListJson != null && podListJson.containsKey("data")) {
|
||||||
|
List<RancherPodVo> rancherPodVoList = podListJson.getJSONArray("data").toList(RancherPodVo.class);
|
||||||
|
List<RancherPodVo> applicationToPodList = rancherPodVoList.stream()
|
||||||
|
.filter(rancherPodVo -> rancherPodVo.getMetadata().getLabels().containsKey("app") && rancherPodVo.getMetadata().getLabels().get("app").equals(appName))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
return applicationToPodList.stream().map(x -> x.getStatus().getPodIP()).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public K8sClusterStatus getClusterStatus() {
|
||||||
|
return monCommonAsyncService.getClusterStatus(PromQLConstant.CLUSTER_NODE_COUNT(cluster_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<MetricCommonData> getClusterQps() {
|
||||||
|
List<MetricCommonData> metricCommonDataList = new ArrayList<>();
|
||||||
|
Date now = DateUtils.getNowDate();
|
||||||
|
long endTime = now.getTime() / 1000;
|
||||||
|
Long startTime = now.getTime() / 1000 - 60 * 60;
|
||||||
|
JSONObject nodeCountJson = remoteGatewayService.getPrometheusQueryRangeRes(PromQLConstant.CLUSTER_QPS, 14L, startTime, endTime, SecurityContextHolder.getUserKey());
|
||||||
|
if (nodeCountJson != null && nodeCountJson.containsKey("data")) {
|
||||||
|
PrometheusResVo prometheusResVo = nodeCountJson.toJavaObject(PrometheusResVo.class);
|
||||||
|
if (prometheusResVo != null && prometheusResVo.isSuccess()) {
|
||||||
|
PrometheusResultVo prometheusResultVo = prometheusResVo.getData().getResult().get(0);
|
||||||
|
if (prometheusResultVo.getValues() != null) {
|
||||||
|
for (int i = 0; i < prometheusResultVo.getValues().size(); i++) {
|
||||||
|
JSONArray value = prometheusResultVo.getValues().getJSONArray(i);
|
||||||
|
MetricCommonData metricCommonData = new MetricCommonData();
|
||||||
|
metricCommonData.setDate(new Date(value.getLong(0) * 1000));
|
||||||
|
String valueStr=String.format("%.2f",value.getFloatValue(1));
|
||||||
|
metricCommonData.setValue(Float.parseFloat(valueStr));
|
||||||
|
metricCommonDataList.add(metricCommonData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (metricCommonDataList.isEmpty()) {
|
||||||
|
for (int i = 0; i < 7; i++) {
|
||||||
|
MetricCommonData metricCommonData = new MetricCommonData();
|
||||||
|
metricCommonData.setDate(new Date(endTime * 1000));
|
||||||
|
metricCommonData.setValue(0F);
|
||||||
|
metricCommonDataList.add(metricCommonData);
|
||||||
|
endTime -= 60 * 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
metricCommonDataList.sort(Comparator.comparing(MetricCommonData::getDate));
|
||||||
|
return metricCommonDataList;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ApplicationRequestCountData> getApplicationRequestCount() {
|
||||||
|
List<ApplicationRequestCountData> applicationRequestCountDataList = new ArrayList<>();
|
||||||
|
HashMap<String, String> portMap = new HashMap<>();
|
||||||
|
JSONObject nginxSvcJson = remoteRancherService.getK8sServiceByApplicationId(cluster_id, nginxApplicationId, SecurityContextHolder.getUserKey());
|
||||||
|
if (nginxSvcJson != null) {
|
||||||
|
RancherServiceVo rancherServiceVo = nginxSvcJson.toJavaObject(RancherServiceVo.class);
|
||||||
|
for (RancherServicePortsVo rancherServicePortsVo : rancherServiceVo.getSpec().getPorts()) {
|
||||||
|
// 获取端口描述
|
||||||
|
String portAlias = rancherServiceVo.getMetadata().getAnnotations().getString(rancherServicePortsVo.getName());
|
||||||
|
portMap.put(String.valueOf(rancherServicePortsVo.getPort()), portAlias);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
JSONObject applicationRequestCountJson = remoteGatewayService.getPrometheusQueryRes(PromQLConstant.APPLICATION_REQUEST_COUNT, SecurityContextHolder.getUserKey());
|
||||||
|
if (applicationRequestCountJson != null) {
|
||||||
|
PrometheusResVo prometheusResVo = applicationRequestCountJson.toJavaObject(PrometheusResVo.class);
|
||||||
|
if (prometheusResVo != null && prometheusResVo.isSuccess()) {
|
||||||
|
List<PrometheusResultVo> resultList = prometheusResVo.getData().getResult();
|
||||||
|
int number = 1;
|
||||||
|
for (PrometheusResultVo result : resultList) {
|
||||||
|
ApplicationRequestCountData applicationRequestCountData = new ApplicationRequestCountData();
|
||||||
|
applicationRequestCountData.setNumber(number++);
|
||||||
|
JSONObject metric = result.getMetric();
|
||||||
|
String port = metric.getString("server_port");
|
||||||
|
applicationRequestCountData.setApplicationAlias(port);
|
||||||
|
if (portMap.containsKey(port)) {
|
||||||
|
applicationRequestCountData.setApplicationAlias(portMap.get(port));
|
||||||
|
}
|
||||||
|
Long value = result.getValue().getLongValue(1);
|
||||||
|
applicationRequestCountData.setRequestCount(value);
|
||||||
|
applicationRequestCountDataList.add(applicationRequestCountData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return applicationRequestCountDataList;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public K8sPodContainerStatus getPodContainerStatus(String containerID) {
|
||||||
|
K8sPodContainerStatus k8sPodContainerStatus = new K8sPodContainerStatus();
|
||||||
|
JSONObject cpuUsageJson = remoteGatewayService.getPrometheusQueryRes(PromQLConstant.POD_CPU_USAGE(containerID), SecurityContextHolder.getUserKey());
|
||||||
|
PrometheusResVo cpuPrometheusResVo = cpuUsageJson.toJavaObject(PrometheusResVo.class);
|
||||||
|
if (cpuPrometheusResVo != null && cpuPrometheusResVo.isSuccess()) {
|
||||||
|
PrometheusResultVo result = cpuPrometheusResVo.getData().getResult().get(0);
|
||||||
|
k8sPodContainerStatus.setPodName(result.getMetric().getString("container_label_io_kubernetes_pod_name"));
|
||||||
|
k8sPodContainerStatus.setCpuUsage(result.getValue().getFloatValue(1));
|
||||||
|
}
|
||||||
|
JSONObject memoryUsageJson = remoteGatewayService.getPrometheusQueryRes(PromQLConstant.POD_MEMORY_USAGE(containerID), SecurityContextHolder.getUserKey());
|
||||||
|
PrometheusResVo memoryPrometheusResVo = memoryUsageJson.toJavaObject(PrometheusResVo.class);
|
||||||
|
if (memoryPrometheusResVo != null && memoryPrometheusResVo.isSuccess()) {
|
||||||
|
PrometheusResultVo result = memoryPrometheusResVo.getData().getResult().get(0);
|
||||||
|
Long memoryByte = result.getValue().getLong(1);
|
||||||
|
float memoryMb = (float) memoryByte / 1024 / 1024;
|
||||||
|
if (memoryMb > 1024) {
|
||||||
|
k8sPodContainerStatus.setMemoryUsage(String.format("%.2f GiB", memoryMb / 1024));
|
||||||
|
} else {
|
||||||
|
k8sPodContainerStatus.setMemoryUsage(String.format("%.2f mib", memoryMb));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return k8sPodContainerStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public K8sNodeStatus getNodeStatus(String nodeIp) {
|
||||||
|
K8sNodeStatus k8sNodeStatus = new K8sNodeStatus();
|
||||||
|
k8sNodeStatus.setNodeIp(nodeIp);
|
||||||
|
JSONObject cpuUsageJson = remoteGatewayService.getPrometheusQueryRes(PromQLConstant.NODE_CPU_USAGE(nodeIp), SecurityContextHolder.getUserKey());
|
||||||
|
PrometheusResVo cpuPrometheusResVo = cpuUsageJson.toJavaObject(PrometheusResVo.class);
|
||||||
|
if (cpuPrometheusResVo != null && cpuPrometheusResVo.isSuccess()) {
|
||||||
|
PrometheusResultVo result = cpuPrometheusResVo.getData().getResult().get(0);
|
||||||
|
k8sNodeStatus.setCpuUsage(result.getValue().getFloatValue(1));
|
||||||
|
}
|
||||||
|
JSONObject memoryUsageJson = remoteGatewayService.getPrometheusQueryRes(PromQLConstant.NODE_MEMORY_USAGE(nodeIp), SecurityContextHolder.getUserKey());
|
||||||
|
PrometheusResVo memoryPrometheusResVo = memoryUsageJson.toJavaObject(PrometheusResVo.class);
|
||||||
|
if (memoryPrometheusResVo != null && memoryPrometheusResVo.isSuccess()) {
|
||||||
|
PrometheusResultVo result = memoryPrometheusResVo.getData().getResult().get(0);
|
||||||
|
k8sNodeStatus.setMemoryUsage(result.getValue().getFloatValue(1));
|
||||||
|
}
|
||||||
|
return k8sNodeStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<K8sNamespace> getK8sNamespaceList() {
|
||||||
|
List<K8sNamespace> k8sNamespaceList = new ArrayList<>();
|
||||||
|
List<RancherNamespaceVo> rancherNamespaceVoList;
|
||||||
|
//调用rancher远程接口获取所有命名空间列表
|
||||||
|
JSONObject namespaceJsonObject = remoteRancherService.getK8sNamespaceList(cluster_id, SecurityContextHolder.getUserKey());
|
||||||
|
if (namespaceJsonObject != null && namespaceJsonObject.containsKey("data")) {
|
||||||
|
rancherNamespaceVoList = namespaceJsonObject.getJSONArray("data").toList(RancherNamespaceVo.class);
|
||||||
|
for (RancherNamespaceVo rancherNamespaceVo : rancherNamespaceVoList) {
|
||||||
|
// 仅获取拥有mon-key标签的命名空间
|
||||||
|
if (rancherNamespaceVo.getLabels().containsKey("mon-key")) {
|
||||||
|
K8sNamespace k8sNamespace = rancherNamespaceVo.toK8sNamespace();
|
||||||
|
k8sNamespaceList.add(k8sNamespace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return k8sNamespaceList;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,123 @@
|
||||||
|
package com.microservices.mon.k8s.service.impl;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.microservices.common.core.context.SecurityContextHolder;
|
||||||
|
import com.microservices.common.core.exception.ServiceException;
|
||||||
|
import com.microservices.mon.k8s.domain.K8sClusterStatus;
|
||||||
|
import com.microservices.mon.k8s.domain.K8sNamespace;
|
||||||
|
import com.microservices.mon.k8s.domain.vo.PrometheusResVo;
|
||||||
|
import com.microservices.mon.k8s.service.IK8sDashboardService;
|
||||||
|
import com.microservices.mon.k8s.service.IMonCommonAsyncService;
|
||||||
|
import com.microservices.mon.k8s.utils.CustomExecutorFactory;
|
||||||
|
import com.microservices.mon.k8s.utils.PromQLConstant;
|
||||||
|
import com.microservices.system.api.RemoteGatewayService;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class MonCommonAsyncServiceImpl extends CommonService implements IMonCommonAsyncService {
|
||||||
|
@Autowired
|
||||||
|
private RemoteGatewayService remoteGatewayService;
|
||||||
|
@Autowired
|
||||||
|
@Lazy
|
||||||
|
private IK8sDashboardService k8sDashboardService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public K8sClusterStatus getClusterStatus(String query) {
|
||||||
|
K8sClusterStatus k8sClusterStatus = new K8sClusterStatus();
|
||||||
|
CountDownLatch countDownLatch = new CountDownLatch(9);
|
||||||
|
CustomExecutorFactory.threadPoolExecutor.execute(() -> {
|
||||||
|
try {
|
||||||
|
JSONObject nodeCountJson = remoteGatewayService.getPrometheusQueryRes(PromQLConstant.CLUSTER_NODE_COUNT(cluster_id), SecurityContextHolder.getUserKey());
|
||||||
|
k8sClusterStatus.setNodeCount(nodeCountJson.toJavaObject(PrometheusResVo.class));
|
||||||
|
} finally {
|
||||||
|
countDownLatch.countDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
CustomExecutorFactory.threadPoolExecutor.execute(() -> {
|
||||||
|
try {
|
||||||
|
JSONObject unavailableNodeCountJson = remoteGatewayService.getPrometheusQueryRes(PromQLConstant.CLUSTER_UNAVAILABLE_NODE_COUNT(cluster_id), SecurityContextHolder.getUserKey());
|
||||||
|
k8sClusterStatus.setUnavailableNodeCount(unavailableNodeCountJson.toJavaObject(PrometheusResVo.class));
|
||||||
|
} finally {
|
||||||
|
countDownLatch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
CustomExecutorFactory.threadPoolExecutor.execute(() -> {
|
||||||
|
try {
|
||||||
|
JSONObject cpuUsageJson = remoteGatewayService.getPrometheusQueryRes(PromQLConstant.CLUSTER_CPU_USAGE(cluster_id), SecurityContextHolder.getUserKey());
|
||||||
|
k8sClusterStatus.setCpuUsage(cpuUsageJson.toJavaObject(PrometheusResVo.class));
|
||||||
|
} finally {
|
||||||
|
countDownLatch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
CustomExecutorFactory.threadPoolExecutor.execute(() -> {
|
||||||
|
try {
|
||||||
|
JSONObject podUsageJson = remoteGatewayService.getPrometheusQueryRes(PromQLConstant.CLUSTER_POD_USAGE(cluster_id), SecurityContextHolder.getUserKey());
|
||||||
|
k8sClusterStatus.setPodUsage(podUsageJson.toJavaObject(PrometheusResVo.class));
|
||||||
|
} finally {
|
||||||
|
countDownLatch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
CustomExecutorFactory.threadPoolExecutor.execute(() -> {
|
||||||
|
try {
|
||||||
|
JSONObject memoryUsageJson = remoteGatewayService.getPrometheusQueryRes(PromQLConstant.CLUSTER_MEMORY_USAGE(cluster_id), SecurityContextHolder.getUserKey());
|
||||||
|
k8sClusterStatus.setMemoryUsage(memoryUsageJson.toJavaObject(PrometheusResVo.class));
|
||||||
|
} finally {
|
||||||
|
countDownLatch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
CustomExecutorFactory.threadPoolExecutor.execute(() -> {
|
||||||
|
try {
|
||||||
|
JSONObject totalRequestCountTodayJson = remoteGatewayService.getPrometheusQueryRes(PromQLConstant.TOTAL_REQUEST_COUNT_TODAY, SecurityContextHolder.getUserKey());
|
||||||
|
k8sClusterStatus.setTotalRequestCountToday(totalRequestCountTodayJson.toJavaObject(PrometheusResVo.class));
|
||||||
|
} finally {
|
||||||
|
countDownLatch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
CustomExecutorFactory.threadPoolExecutor.execute(() -> {
|
||||||
|
try {
|
||||||
|
JSONObject averageRequestProcessingTimeTodayJson = remoteGatewayService.getPrometheusQueryRes(PromQLConstant.AVERAGE_REQUEST_PROCESSING_TIME_TODAY, SecurityContextHolder.getUserKey());
|
||||||
|
k8sClusterStatus.setAverageRequestProcessingTimeToday(averageRequestProcessingTimeTodayJson.toJavaObject(PrometheusResVo.class));
|
||||||
|
} finally {
|
||||||
|
countDownLatch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
CustomExecutorFactory.threadPoolExecutor.execute(() -> {
|
||||||
|
try {
|
||||||
|
JSONObject requestSuccessRateTodayJson = remoteGatewayService.getPrometheusQueryRes(PromQLConstant.REQUEST_SUCCESS_RATE_TODAY, SecurityContextHolder.getUserKey());
|
||||||
|
k8sClusterStatus.setRequestSuccessRateToday(requestSuccessRateTodayJson.toJavaObject(PrometheusResVo.class));
|
||||||
|
} finally {
|
||||||
|
countDownLatch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
CustomExecutorFactory.threadPoolExecutor.execute(() -> {
|
||||||
|
try {
|
||||||
|
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());
|
||||||
|
k8sClusterStatus.setMicroserviceRestartCountToday(microserviceRestartCountTodayJson.toJavaObject(PrometheusResVo.class));
|
||||||
|
|
||||||
|
JSONObject podStatusJson = remoteGatewayService.getPrometheusQueryRes(PromQLConstant.POD_STATUS(cluster_id,namespaceNameList), SecurityContextHolder.getUserKey());
|
||||||
|
k8sClusterStatus.setPodStatus(podStatusJson.toJavaObject(PrometheusResVo.class));
|
||||||
|
} finally {
|
||||||
|
countDownLatch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
countDownLatch.await();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
log.error("集群状态获取失败:{0}", e);
|
||||||
|
throw new ServiceException("集群状态获取失败");
|
||||||
|
}
|
||||||
|
return k8sClusterStatus;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
package com.microservices.mon.k8s.utils;
|
||||||
|
|
||||||
|
import com.microservices.common.core.exception.ServiceException;
|
||||||
|
import com.microservices.common.core.threadPool.ThreadPoolExecutorWrap;
|
||||||
|
|
||||||
|
import java.util.concurrent.ArrayBlockingQueue;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 线程池工厂
|
||||||
|
*
|
||||||
|
* @author OTTO
|
||||||
|
*/
|
||||||
|
public class CustomExecutorFactory {
|
||||||
|
/**
|
||||||
|
* 创建线程池
|
||||||
|
* 存在并发处理的情况,设置核心线程为2,设置有界队列长度为100,最大线程数为10
|
||||||
|
* 当超出队列已满且达到最大线程数时抛出异常
|
||||||
|
* Ncpu=CPU数量
|
||||||
|
* Ucpu=目标CPU的使用率,0<=Ucpu<=1
|
||||||
|
* W/C=任务等待时间与任务计算时间的比率
|
||||||
|
* Nthreads =Ncpu*Ucpu*(1+W/C)
|
||||||
|
*/
|
||||||
|
public static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutorWrap(
|
||||||
|
4
|
||||||
|
, 10
|
||||||
|
, 10
|
||||||
|
, TimeUnit.SECONDS
|
||||||
|
, new ArrayBlockingQueue<>(100)
|
||||||
|
, Executors.defaultThreadFactory()
|
||||||
|
, (r, executor) -> {
|
||||||
|
throw new ServiceException("目前处理的人太多了,请稍后再试");
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
package com.microservices.mon.k8s.utils;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prometheus查询常量
|
||||||
|
*/
|
||||||
|
public class PromQLConstant {
|
||||||
|
public static String CLUSTER_NODE_COUNT(String clusterId) {
|
||||||
|
return String.format("sum(kube_node_info{cluster=~\"%s\"})", clusterId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String CLUSTER_UNAVAILABLE_NODE_COUNT(String clusterId) {
|
||||||
|
return String.format("sum(kube_node_spec_unschedulable{cluster=~\"%s\"})", clusterId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String CLUSTER_CPU_USAGE(String clusterId) {
|
||||||
|
return String.format("(sum(kube_pod_container_resource_requests{cluster=~\"%s\",resource=\"cpu\"})/ sum(kube_node_status_allocatable{cluster=~\"%s\",resource=\"cpu\"}))*100", clusterId, clusterId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String CLUSTER_POD_USAGE(String clusterId) {
|
||||||
|
return String.format("(sum(kube_pod_info{cluster=~\"%s\"}) / sum(kube_node_status_allocatable{cluster=~\"%s\",resource=\"pods\"}))*100", clusterId, clusterId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String CLUSTER_MEMORY_USAGE(String clusterId) {
|
||||||
|
return String.format("(sum(kube_pod_container_resource_requests{cluster=~\"%s\",resource=\"memory\"}) / sum(kube_node_status_allocatable{cluster=~\"%s\",resource=\"memory\"}))*100", clusterId, clusterId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final String TOTAL_REQUEST_COUNT_TODAY = "round(sum(increase(nginx_http_response_count_total[1d])))";
|
||||||
|
public static final String AVERAGE_REQUEST_PROCESSING_TIME_TODAY = "sum(rate(nginx_http_response_time_seconds_sum[1d]))*1000";
|
||||||
|
public static final String REQUEST_SUCCESS_RATE_TODAY = "(sum(nginx_http_response_count_total{status=~\"2.*|3.*\"})/sum(nginx_http_response_count_total))*100";
|
||||||
|
|
||||||
|
public static String MICROSERVICE_RESTART_COUNT_TODAY(String clusterId, List<String> namespaceNameList) {
|
||||||
|
return String.format("sum(increase(kube_pod_container_status_restarts_total{cluster=~\"%s\",namespace=~\"%s\"}[1d]))", clusterId, String.join("|", namespaceNameList));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String POD_STATUS(String clusterId, List<String> namespaceNameList) {
|
||||||
|
return String.format("sum(kube_pod_status_phase{cluster=~\"%s\",namespace=~\"%s\", phase!=\"Unknown\"}) by (phase)", clusterId, String.join("|", namespaceNameList));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String APPLICATION_REQUEST_COUNT = "sort_desc(round(sum(increase(nginx_http_response_count_total[1d])) by (server_port)))";
|
||||||
|
public static String CLUSTER_QPS = "sum(rate(nginx_http_response_time_seconds_count[10m])) ";
|
||||||
|
|
||||||
|
public static String POD_CPU_USAGE(String containerId) {
|
||||||
|
return String.format("sum without (dc,from,id) (irate(container_cpu_user_seconds_total{container_label_io_kubernetes_sandbox_id=\"%s\"}[5m]) * 100)", containerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String POD_MEMORY_USAGE(String containerId) {
|
||||||
|
return String.format("sum without (dc,from,id) (container_memory_usage_bytes{container_label_io_kubernetes_sandbox_id=\"%s\"} - container_memory_cache{container_label_io_kubernetes_sandbox_id=\"%s\"})", containerId, containerId);
|
||||||
|
}
|
||||||
|
public static String NODE_CPU_USAGE(String nodeIp) {
|
||||||
|
return String.format("(sum by(instance) (irate(node_cpu_seconds_total{ip=\"%s\",mode!=\"idle\"}[1m])) / on(instance) group_left sum by (instance)((irate(node_cpu_seconds_total{ip=\"%s\"}[1m])))) * 100", nodeIp, nodeIp);
|
||||||
|
}
|
||||||
|
public static String NODE_MEMORY_USAGE(String nodeIp) {
|
||||||
|
return String.format("100 - ((node_memory_MemAvailable_bytes{ip=\"%s\"} * 100) / node_memory_MemTotal_bytes{ip=\"%s\"})", nodeIp, nodeIp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
Spring Boot Version: ${spring-boot.version}
|
||||||
|
Spring Application Name: ${spring.application.name}
|
||||||
|
_
|
||||||
|
(_)
|
||||||
|
_ __ _ _ ___ _ _ _ ______ _ __ ___ ___ _ __
|
||||||
|
| '__| | | |/ _ \| | | | |______| '_ ` _ \ / _ \| '_ \
|
||||||
|
| | | |_| | (_) | |_| | | | | | | | | (_) | | | |
|
||||||
|
|_| \__,_|\___/ \__, |_| |_| |_| |_|\___/|_| |_|
|
||||||
|
__/ |
|
||||||
|
|___/
|
||||||
|
|
||||||
|
# using Big
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
# Tomcat
|
||||||
|
server:
|
||||||
|
port: 9120
|
||||||
|
|
||||||
|
# Spring
|
||||||
|
spring:
|
||||||
|
application:
|
||||||
|
# 应用名称
|
||||||
|
name: microservices-mon
|
||||||
|
config:
|
||||||
|
activate:
|
||||||
|
# 环境配置
|
||||||
|
on-profile:
|
||||||
|
prod
|
||||||
|
cloud:
|
||||||
|
sentinel:
|
||||||
|
# 取消控制台懒加载
|
||||||
|
eager: true
|
||||||
|
nacos:
|
||||||
|
discovery:
|
||||||
|
# 服务注册地址
|
||||||
|
server-addr: ${nacos_ip}:${nacos_port}
|
||||||
|
username: ${nacos_username}
|
||||||
|
password: ${nacos_password}
|
||||||
|
config:
|
||||||
|
# 配置中心地址
|
||||||
|
server-addr: ${nacos_ip}:${nacos_port}
|
||||||
|
username: ${nacos_username}
|
||||||
|
password: ${nacos_password}
|
||||||
|
# 配置文件格式
|
||||||
|
file-extension: yml
|
||||||
|
# 共享配置
|
||||||
|
shared-configs:
|
||||||
|
- { dataId: "application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}",refresh: true }
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
# Tomcat
|
||||||
|
server:
|
||||||
|
port: 9120
|
||||||
|
|
||||||
|
# Spring
|
||||||
|
spring:
|
||||||
|
application:
|
||||||
|
# 应用名称
|
||||||
|
name: microservices-mon
|
||||||
|
profiles:
|
||||||
|
# 环境配置
|
||||||
|
active: dev
|
||||||
|
cloud:
|
||||||
|
sentinel:
|
||||||
|
# 取消控制台懒加载
|
||||||
|
eager: true
|
||||||
|
nacos:
|
||||||
|
discovery:
|
||||||
|
# 服务注册地址
|
||||||
|
server-addr: 172.168.15.201:8848
|
||||||
|
username: nacos
|
||||||
|
password: nacos
|
||||||
|
config:
|
||||||
|
# 配置中心地址
|
||||||
|
server-addr: 172.168.15.201:8848
|
||||||
|
username: nacos
|
||||||
|
password: nacos
|
||||||
|
# 配置文件格式
|
||||||
|
file-extension: yml
|
||||||
|
# 共享配置
|
||||||
|
shared-configs:
|
||||||
|
- { dataId: "application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}",refresh: true }
|
||||||
|
|
@ -0,0 +1,101 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<configuration scan="true" scanPeriod="60 seconds" debug="false">
|
||||||
|
<!-- 日志存放路径 -->
|
||||||
|
<property name="log.path" value="logs/microservices-mon"/>
|
||||||
|
<!-- 日志输出格式 -->
|
||||||
|
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n"/>
|
||||||
|
|
||||||
|
<!-- 控制台输出 -->
|
||||||
|
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
<encoder>
|
||||||
|
<pattern>${log.pattern}</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<!-- 系统日志输出 -->
|
||||||
|
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
|
<file>${log.path}/info.log</file>
|
||||||
|
<!-- 循环政策:基于时间创建日志文件 -->
|
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||||
|
<!-- 日志文件名格式 -->
|
||||||
|
<fileNamePattern>${log.path}/info.%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||||
|
<!-- 日志最大的历史 60天 -->
|
||||||
|
<maxHistory>60</maxHistory>
|
||||||
|
</rollingPolicy>
|
||||||
|
<encoder>
|
||||||
|
<pattern>${log.pattern}</pattern>
|
||||||
|
</encoder>
|
||||||
|
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||||
|
<!-- 过滤的级别 -->
|
||||||
|
<level>INFO</level>
|
||||||
|
<!-- 匹配时的操作:接收(记录) -->
|
||||||
|
<onMatch>ACCEPT</onMatch>
|
||||||
|
<!-- 不匹配时的操作:拒绝(不记录) -->
|
||||||
|
<onMismatch>DENY</onMismatch>
|
||||||
|
</filter>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
|
<file>${log.path}/error.log</file>
|
||||||
|
<!-- 循环政策:基于时间创建日志文件 -->
|
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||||
|
<!-- 日志文件名格式 -->
|
||||||
|
<fileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||||
|
<!-- 日志最大的历史 60天 -->
|
||||||
|
<maxHistory>60</maxHistory>
|
||||||
|
</rollingPolicy>
|
||||||
|
<encoder>
|
||||||
|
<pattern>${log.pattern}</pattern>
|
||||||
|
</encoder>
|
||||||
|
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||||
|
<!-- 过滤的级别 -->
|
||||||
|
<level>ERROR</level>
|
||||||
|
<!-- 匹配时的操作:接收(记录) -->
|
||||||
|
<onMatch>ACCEPT</onMatch>
|
||||||
|
<!-- 不匹配时的操作:拒绝(不记录) -->
|
||||||
|
<onMismatch>DENY</onMismatch>
|
||||||
|
</filter>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<!-- 系统模块日志级别控制 -->
|
||||||
|
<logger name="com.microservices" level="info"/>
|
||||||
|
<!-- Spring日志级别控制 -->
|
||||||
|
<logger name="org.springframework" level="warn"/>
|
||||||
|
|
||||||
|
<!-- add converter for %tid -->
|
||||||
|
<conversionRule conversionWord="tid"
|
||||||
|
converterClass="org.apache.skywalking.apm.toolkit.log.logback.v1.x.LogbackPatternConverter"/>
|
||||||
|
<!-- add converter for %sw_ctx -->
|
||||||
|
<conversionRule conversionWord="sw_ctx"
|
||||||
|
converterClass="org.apache.skywalking.apm.toolkit.log.logback.v1.x.LogbackSkyWalkingContextPatternConverter"/>
|
||||||
|
|
||||||
|
<appender name="skywalking_grpc"
|
||||||
|
class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender">
|
||||||
|
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
|
||||||
|
<layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.mdc.TraceIdMDCPatternLogbackLayout">
|
||||||
|
<Pattern>
|
||||||
|
{
|
||||||
|
"level": "%level",
|
||||||
|
"tid": "%tid",
|
||||||
|
"skyWalkingContext": "%sw_ctx",
|
||||||
|
"thread": "%thread",
|
||||||
|
"class": "%logger{1.}:%L",
|
||||||
|
"message": "%message",
|
||||||
|
"stackTrace": "%exception{10}"
|
||||||
|
}
|
||||||
|
</Pattern>
|
||||||
|
</layout>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<root level="info">
|
||||||
|
<appender-ref ref="skywalking_grpc"/>
|
||||||
|
<appender-ref ref="console"/>
|
||||||
|
</root>
|
||||||
|
|
||||||
|
<!--系统操作日志-->
|
||||||
|
<root level="info">
|
||||||
|
<appender-ref ref="file_info"/>
|
||||||
|
<appender-ref ref="file_error"/>
|
||||||
|
</root>
|
||||||
|
</configuration>
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
<artifactId>microservices-modules-pms</artifactId>
|
<artifactId>microservices-modules-pms</artifactId>
|
||||||
|
|
||||||
<description>
|
<description>
|
||||||
microservices-modules-pms特色专区模块
|
microservices-modules-pms项目管理模块
|
||||||
</description>
|
</description>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@
|
||||||
<module>microservices-modules-wiki</module>
|
<module>microservices-modules-wiki</module>
|
||||||
<module>microservices-modules-dss</module>
|
<module>microservices-modules-dss</module>
|
||||||
<module>microservices-modules-dms</module>
|
<module>microservices-modules-dms</module>
|
||||||
|
<module>microservices-modules-mon</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
<artifactId>microservices-modules</artifactId>
|
<artifactId>microservices-modules</artifactId>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue