SpringBoot 调用 K8s metrics-server
起因
官方 API io.kubernetes.client-java
无法调用 metrics-server API
解决
ApiClient 内部会创建一个 OkHttpClient 用于发送 http 请求,该 clinet 包含授权参数等信息
K8sConfig
public class K8sConfig {
public static ApiClient getApiClient() {
ApiClient client = null;
try {
File file = new File("E:\\k3s.yaml");
client = ClientBuilder.kubeconfig(KubeConfig.loadKubeConfig(new FileReader(file))).build();
client.setDebugging(true);
Configuration.setDefaultApiClient(client);
} catch (IOException e) {
log.error("K8s ApiClient 初始化失败!");
}
return client;
}
}
MetricsService
@Service
public class MetricsService {
private ApiClient apiClient;
private static final String BASE_URL="/apis/metrics.k8s.io/v1beta1";
private static final String URL_NODES = "/nodes";
private static final String URL_PODS = "/pods";
private static final String URL_NAMESPACES = "/namespaces/";
public MetricsService() {
this.apiClient = K8sConfig.getApiClient();
}
/**
* 获取集群节点的资源统计信息
*/
public MetricsNodeList getNodeMetrics() throws IOException, ApiException {
String path = BASE_URL + URL_NODES;
Call call = buildCall(path, "GET");
ApiResponse<MetricsNodeList> r = apiClient.execute(call, MetricsNodeList.class);
return r.getData();
}
/**
* 获取所有pods的资源统计信息
*/
public MetricsPodList getPodMetrics() throws IOException, ApiException {
String path = BASE_URL + URL_PODS;
Call call = buildCall(path, "GET");
ApiResponse<MetricsPodList> r = apiClient.execute(call, MetricsPodList.class);
return r.getData();
}
/**
* 获取namespace下pods的资源统计信息
*/
public MetricsPodList getPodsMetrics(String namespace) throws IOException, ApiException {
String path = BASE_URL + URL_NAMESPACES + namespace + URL_PODS;
Call call = buildCall(path, "GET");
ApiResponse<MetricsPodList> r = apiClient.execute(call, MetricsPodList.class);
return r.getData();
}
/**
* 构建Call
*/
private Call buildCall(String path, String method) throws ApiException {
List<Pair> localVarQueryParams = new ArrayList<>();
List<Pair> localVarCollectionQueryParams = new ArrayList<>();
Map<String, String> localVarHeaderParams = new HashMap<>();
localVarHeaderParams.put("Accept", apiClient.selectHeaderAccept(new String[]{"*/*"}));
localVarHeaderParams.put("Content-Type", apiClient.selectHeaderContentType(new String[]{}));
Map<String, String> localVarCookieParams = new HashMap<>();
Map<String, Object> localVarFormParams = new HashMap<>();
String[] localVarAuthNames = new String[]{"BearerToken"};
return apiClient.buildCall(path, method, localVarQueryParams, localVarCollectionQueryParams, null, localVarHeaderParams, localVarCookieParams, localVarFormParams, localVarAuthNames, null);
}
}
Models
@Data
public class MetricsNodeList {
private String kind;
private String apiVersion;
private V1ListMeta metadata;
private List<MetricsNode> items;
@Data
public static class MetricsNode{
private V1ObjectMeta metadata;
private DateTime timestamp;
private String window;
private MetricsUsage usage;
}
}
@Data
public class MetricsPodList {
private String kind;
private String apiVersion;
private V1ListMeta metadata;
private List<MetricsPod> items;
@Data
public static class MetricsPod{
private V1ObjectMeta metadata;
private DateTime timestamp;
private String window;
private List<MetricsPodContainer> containers;
}
@Data
public static class MetricsPodContainer{
private String name;
private MetricsUsage usage;
}
}
public class MetricsUsage {
private static Map<String,Double> UNIT_CPU = new HashMap<>();
private static Map<String,Double> UNIT_MEMORY = new HashMap<>();
static {
UNIT_CPU.put("n", Math.pow(10, -6));
UNIT_CPU.put("u", Math.pow(10, -3));
UNIT_CPU.put("m", Math.pow(10, 0));
UNIT_CPU.put("", Math.pow(10, 3));
UNIT_CPU.put("k", Math.pow(10, 6));
UNIT_CPU.put("M", Math.pow(10, 9));
UNIT_CPU.put("G", Math.pow(10, 3*4));
UNIT_CPU.put("T", Math.pow(10, 3*5));
UNIT_CPU.put("P", Math.pow(10, 3*6));
UNIT_CPU.put("E", Math.pow(10, 3*7));
UNIT_MEMORY.put("Ki", Math.pow(1024, -1));
UNIT_MEMORY.put("Mi", Math.pow(1024, 0));
UNIT_MEMORY.put("Gi", Math.pow(1024, 1));
UNIT_MEMORY.put("Ti", Math.pow(1024, 2));
UNIT_MEMORY.put("Pi", Math.pow(1024, 3));
UNIT_MEMORY.put("Ei", Math.pow(1024, 4));
}
private String cpu;
private String memory;
public String getCpu() {
return commomUnifiedUnit(cpu,1,UNIT_CPU) + "m";
}
public void setCpu(String cpu) {
this.cpu = cpu;
}
public String getMemory() {
return commomUnifiedUnit(memory, 2, UNIT_MEMORY) + "Mi";
}
public void setMemory(String memory) {
this.memory = memory;
}
/**
* 获取的cpu和memory是带单位的字符串,加入转换逻辑,cpu统一单位为m,memory统一单位为Mi,如果不需要转换单位可以去掉相关逻辑
*/
private static String commomUnifiedUnit(String unitValStr, int unitLength, Map<String, Double> unitMap) {
Long r = 0L;
if(unitValStr == null) {
return "0";
}
String unit = unitValStr.substring(unitValStr.length() - unitLength, unitValStr.length());
String val = unitValStr.substring(0, unitValStr.length() - unitLength);
if(unit.matches("\\d")) {
unit = "";
val = unitValStr;
}
Double factor = unitMap.get(unit);
if(factor == null) {
throw new IllegalArgumentException("无法解析单位:" + unitValStr);
}
r = Math.round(Integer.parseInt(val) * factor);
return r + "";
}
}
参考:https://blog.csdn.net/suo082407128/article/details/106804811