一、前言

上篇介绍了如何安装metrics-server,本篇主要介绍如何使用java程序远程调用metrics-server的api

二、代码调用k8s集群

kubernetes-client为kubernetes官方维护的访问集群的api,各种语言基本都有,kubernetes-client/java为java版的api,用法示例

import io.kubernetes.client.openapi.ApiClient;
import io.kubernetes.client.openapi.ApiException;
import io.kubernetes.client.openapi.Configuration;
import io.kubernetes.client.openapi.apis.CoreV1Api;
import io.kubernetes.client.openapi.models.V1Pod;
import io.kubernetes.client.openapi.models.V1PodList;
import io.kubernetes.client.util.Config;

import java.io.IOException;

public class Example {
    public static void main(String[] args) throws IOException, ApiException{
        ApiClient client = Config.fromConfig("G:/config");
        Configuration.setDefaultApiClient(client);

        CoreV1Api api = new CoreV1Api();
        V1PodList list = api.listPodForAllNamespaces(null, null, null, null, null, null, null, null, null);
        for (V1Pod item : list.getItems()) {
            System.out.println(item.getMetadata().getName());
        }
    }
}

该API的核心类就是ApiClinet,使用Config类中各种重载的fromConfig方法来得到ApiClient
kubernetes API的授权方式有三种:

  • ClientCertificateAuthentication 客户端证书授权
  • UsernamePasswordAuthentication 用户名密码授权
  • AccessTokenAuthentication AccessToken(访问令牌)授权

示例中使用的是第一种方式,G:/config为k8s集群master节点.kube下的config文件,即证书
maven依赖

<dependency>
    <groupId>io.kubernetes</groupId>
    <artifactId>client-java</artifactId>
    <version>8.0.2</version><!--版本根据github官网描述及自身k8s版本自选-->
</dependency>

三、java调用metrics-server API

遗憾的是官方标准API中没有metrics-server的,那我们如何调用呢?网上有人使用kubernetes-client/gen生成包含metrics-server API的jar,具体可参考这里, kubernetes-client本身就是使用kubernetes-client/gen生成的,但该方案问题较多

  • 自动生成使用繁琐,不易掌握,学习成本高
  • 生成jar是基于官方某个版本,一旦需要升级版本,需要重新生成
  • 如果使用maven,则需要把生成jar维护到maven库中,需要持续维护
  • 一旦开发人员更换,后续接手人难以维护该代码

有没有别的方案呢?
通过查看源码,发现kubernetes-client/java是对okhttp3的封装,k8s集群对外提供http接口,kubernetes-client/java使用okhttp3访问
ApiClient在创建时,内部会构建一个OkHttpClient用于发送http请求,该clinet会包含授权参数
因此,只要使用ApiClient即可,示例

  1. 引入kubernetes-client/javamaven依赖
  2. 核心API类:MetricsServerApi
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.lenovo.brain.controlagent.metrics.dto.MetricsNodeList;
import com.lenovo.brain.controlagent.metrics.dto.MetricsPodList;

import io.kubernetes.client.openapi.ApiClient;
import io.kubernetes.client.openapi.ApiException;
import io.kubernetes.client.openapi.ApiResponse;
import io.kubernetes.client.openapi.Configuration;
import io.kubernetes.client.openapi.Pair;
import okhttp3.Call;
/**
 * 
 * @author suozq
 *
 */
public class MetricsServerApi {
	private ApiClient localVarApiClient;
	
	public final static String BASE_URL="/apis/metrics.k8s.io/v1beta1";
	
	private String url_get_nodes="/nodes";
	
	private String url_get_namespace_pods = "/namespaces/{namespace}/pods";

	public MetricsServerApi() {
		this(Configuration.getDefaultApiClient());
	}

	public MetricsServerApi(ApiClient apiClient) {
		this.localVarApiClient = apiClient;
	}
	
	public ApiClient getApiClient() {
        return localVarApiClient;
    }

    public void setApiClient(ApiClient apiClient) {
        this.localVarApiClient = apiClient;
    }
    
    /**
     *   获取集群各个node节点的cpu和内存用量
     */
    public MetricsNodeList getNodesAndUsage() throws IOException, ApiException {
		String path = BASE_URL+url_get_nodes;
		Call call = buildGetSimpleCall(path, "GET");
		ApiResponse<MetricsNodeList> r = localVarApiClient.execute(call,MetricsNodeList.class);
		return r.getData();
	}
    
    /**
     * 获取namespace下pods的cpu和内存用量
     * @param namespace
     * @return
     * @throws IOException
     * @throws ApiException
     */
    public MetricsPodList getPodsAndUsage(String namespace) throws IOException, ApiException {
    	String path = new String(url_get_namespace_pods);
    	path=path.replaceAll("\\{namespace\\}", namespace);
    	path = BASE_URL+path;
    	Call call = buildGetSimpleCall(path, "GET");
    	ApiResponse<MetricsPodList> r = localVarApiClient.execute(call,MetricsPodList.class);
    	return r.getData();
    }
    /**
     * 构建简单的Call
     */
    private Call buildGetSimpleCall(String path, String method) throws ApiException {
    	String[] localVarAuthNames = new String[] { "BearerToken" };
    	List<Pair> localVarQueryParams = new ArrayList<Pair>();
    	List<Pair> localVarCollectionQueryParams = new ArrayList<Pair>();
    	
    	Map<String, String> localVarHeaderParams = new HashMap<String, String>();
    	Map<String, String> localVarCookieParams = new HashMap<String, String>();
    	Map<String, Object> localVarFormParams = new HashMap<String, Object>();
    	final String[] localVarAccepts = {
    			"*/*"
    	};
    	final String localVarAccept = localVarApiClient.selectHeaderAccept(localVarAccepts);
    	if (localVarAccept != null) {
    		localVarHeaderParams.put("Accept", localVarAccept);
    	}
    	
    	final String[] localVarContentTypes = {
    	};
    	final String localVarContentType = localVarApiClient.selectHeaderContentType(localVarContentTypes);
    	localVarHeaderParams.put("Content-Type", localVarContentType);
    	
    	return localVarApiClient.buildCall(path, method, localVarQueryParams, localVarCollectionQueryParams, null, localVarHeaderParams, localVarCookieParams, localVarFormParams, localVarAuthNames, null);
    }
}
  1. model类
import java.util.List;

import org.joda.time.DateTime;

import io.kubernetes.client.openapi.models.V1ListMeta;
import io.kubernetes.client.openapi.models.V1ObjectMeta;
/**
 * 
 * @author suozq
 *
 */
public class MetricsNodeList {
	
	private String kind;
	private String apiVersion;
	private V1ListMeta metadata;
	private List<MetricsNode> items;
	
	
	public static class MetricsNode{
		private V1ObjectMeta metadata;
		private DateTime timestamp;
		private String window;
		private MetricsUsage usage;
		
		public DateTime getTimestamp() {
			return timestamp;
		}
		public void setTimestamp(DateTime timestamp) {
			this.timestamp = timestamp;
		}
		public String getWindow() {
			return window;
		}
		public void setWindow(String window) {
			this.window = window;
		}
		public MetricsUsage getUsage() {
			return usage;
		}
		public void setUsage(MetricsUsage usage) {
			this.usage = usage;
		}
		public V1ObjectMeta getMetadata() {
			return metadata;
		}
		public void setMetadata(V1ObjectMeta metadata) {
			this.metadata = metadata;
		}
		
	}


	public String getKind() {
		return kind;
	}


	public void setKind(String kind) {
		this.kind = kind;
	}


	public String getApiVersion() {
		return apiVersion;
	}


	public void setApiVersion(String apiVersion) {
		this.apiVersion = apiVersion;
	}

	public List<MetricsNode> getItems() {
		return items;
	}


	public void setItems(List<MetricsNode> items) {
		this.items = items;
	}


	public V1ListMeta getMetadata() {
		return metadata;
	}


	public void setMetadata(V1ListMeta metadata) {
		this.metadata = metadata;
	}	
}

/**
 * 
 * @author suozq
 *
 */
import java.util.List;

import org.joda.time.DateTime;

import io.kubernetes.client.openapi.models.V1ListMeta;
import io.kubernetes.client.openapi.models.V1ObjectMeta;

public class MetricsPodList {
	private String kind;
	private String apiVersion;
	private V1ListMeta metadata;
	private List<MetricsPod> items;
	
	public static class MetricsPod{
		private V1ObjectMeta metadata;
		private DateTime timestamp;
		private String window;
		private List<MetricsPodContainer> containers;
		
		public DateTime getTimestamp() {
			return timestamp;
		}
		public void setTimestamp(DateTime timestamp) {
			this.timestamp = timestamp;
		}
		public String getWindow() {
			return window;
		}
		public void setWindow(String window) {
			this.window = window;
		}
		public List<MetricsPodContainer> getContainers() {
			return containers;
		}
		public void setContainers(List<MetricsPodContainer> containers) {
			this.containers = containers;
		}
		public V1ObjectMeta getMetadata() {
			return metadata;
		}
		public void setMetadata(V1ObjectMeta metadata) {
			this.metadata = metadata;
		}
	}
	
	public static class MetricsPodContainer{
		private String name;
		private MetricsUsage usage;
		public String getName() {
			return name;
		}
		public void setName(String name) {
			this.name = name;
		}
		public MetricsUsage getUsage() {
			return usage;
		}
		public void setUsage(MetricsUsage usage) {
			this.usage = usage;
		}
	}

	public String getKind() {
		return kind;
	}

	public void setKind(String kind) {
		this.kind = kind;
	}

	public String getApiVersion() {
		return apiVersion;
	}

	public void setApiVersion(String apiVersion) {
		this.apiVersion = apiVersion;
	}

	

	public List<MetricsPod> getItems() {
		return items;
	}

	public void setItems(List<MetricsPod> items) {
		this.items = items;
	}

	public V1ListMeta getMetadata() {
		return metadata;
	}

	public void setMetadata(V1ListMeta metadata) {
		this.metadata = metadata;
	}
	
}
import java.util.HashMap;
import java.util.Map;
/**
 * 
 * @author suozq
 *
 */
public class MetricsUsage {
	//获取的cpu和memory是带单位的字符串,加入转换逻辑,cpu统一单位为m,memory统一单位为Mi,如果不需要转换单位可以去掉相关逻辑
	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 cpu;
	}

	public void setCpu(String cpu) {
		this.cpu = cpu;
	}

	public String getMemory() {
		return memory;
	}

	public void setMemory(String memory) {
		this.memory = memory;
	}
	
	public static Long commomUnifiedUnit(String unitValStr,int unitLength,Map<String,Double> unitMap) {
		Long r = 0l;
		if(unitValStr == null) {
			return r;
		}
		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;
	}
	
	public  Long getCpuInM() {
		return commomUnifiedUnit(cpu,1,UNIT_CPU);
	}
	
	public Long getMemoryInMi() {
		return commomUnifiedUnit(memory, 2, UNIT_MEMORY);
	}	
}
  1. 使用
import io.kubernetes.client.openapi.ApiClient;
import io.kubernetes.client.openapi.ApiException;
import io.kubernetes.client.openapi.Configuration;
import io.kubernetes.client.openapi.apis.CoreV1Api;
import io.kubernetes.client.openapi.models.V1Pod;
import io.kubernetes.client.openapi.models.V1PodList;
import io.kubernetes.client.util.Config;

import java.io.IOException;
/**
 * 
 * @author suozq
 *
 */
public class Example {
    public static void main(String[] args) throws IOException, ApiException {
		ApiClient client = Config.fromConfig("G:/config");
		MetricsServerApi metricsServerApi = new MetricsServerApi(client);
        MetricsNodeList metricsNodeList = metricsServerApi.getNodesAndUsage();
	    for(MetricsNode mn:metricsNodeList.getItems()){
	    	MetricsUsage mu = mn.getUsage();
	    	System.out.println(mu.getCpuInM());//cpu单位转为m
	    	System.out.println(mu.getMemoryInMi());//内存单位转为Mi
	    }
	}
}
Logo

开源、云原生的融合云平台

更多推荐