1. 目的:简单监控pod
我想使用java监控k8s pod的资源的简单使用情况,但是k8s内部并没有采集资源的实现。
但是k8s提供了一套k8s的对接标准,只要适配这套标准,就可以通过kubelet采集资源数据,并且通过k8s api服务器输出。这些对于故障排查以及自动伸缩至关重要。
2. 部署指南
metrics-server是Kubernetes的一个集群范围内的聚合器,用于收集所有节点和Pods的资源使用信息,如CPU和内存。metrics指标统计器(github)
- 如果证书没问题,部署最新的metrics-server
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.4.1/components.yaml
- 如果你的集群使用自签名的证书,你可能需要添加参数来忽略 TLS 验证错误
把commponents.yaml wget下来后, 在 components.yaml 文件中,找到 metrics-server 的 Deployment 部分,并添加以下参数到 args:
- --kubelet-insecure-tls
- 查看是否部署成功
kubectl get deployment metrics-server -n kube-system
# 查看所有命名空间的pod资源
kubectl top pods -A
top 命令就可以使用了。
3. java Api调用
在官方提供的客户端 java库里是没有直接调用metrics的方法的。我们只能使用restful api进行访问,
- 添加maven依赖(获取tls上下文,如果只是过去资源可以不添加)
<dependency><groupId>io.kubernetes</groupId><artifactId>client-java</artifactId><version>18.0.0</version></dependency>
- 测试restful api(测试,可不做)
我这里是手动把证书导入到了postman(k8s的权限认证非常关键,没有权限是无法访问api的)
- java访问 restapi
我这里吧k8s 客户端和 rest http前后文都注入spring了,这样调用起来比较方便
注入k8s客户端
在这里插入代码片@Configuration
public class KubernetesClientConfig {@Beanpublic AppsV1Api appsV1Api(ApiClient apiClient) {return new AppsV1Api(apiClient);}}
注入8sRestTemplate
@Configuration
public class RestTemplateConfig {private final ApiClient apiClient;public RestTemplateConfig(ApiClient apiClient) {this.apiClient = apiClient;}@Beanpublic RestTemplate extendK8sRestTemplate() {return new RestTemplate(new OkHttp3ClientHttpRequestFactory(apiClient.getHttpClient()));}}
4. 定时任务读取该数据,存储到redis,保留60分钟,可以根据自动目的设置。
里面代码看起来比较杂乱,整体思路是使用上面注入的extendK8sRestTemplate访问api,然后存入redis,只保留30分钟
@Service
public class LogResourceTaskService implements TaskService {@Resourceprivate final RedisService redisService;@Resourceprivate final RestTemplate extendK8sRestTemplate;@Resourceprivate final KubernetesServiceImpl kubernetesServiceImpl;@Resourceprivate final ApiClient apiClient;public LogResourceTaskService(RedisService redisService,RestTemplate extendK8sRestTemplate, KubernetesServiceImpl kubernetesServiceImpl,ApiClient apiClient) {this.redisService = redisService;this.extendK8sRestTemplate = extendK8sRestTemplate;this.apiClient = apiClient;this.kubernetesServiceImpl = kubernetesServiceImpl;}@Overridepublic void work(String guid) {String mapKey0 = "metrics_cpu:"+PodDataSynConfig.CURRENT_POD;String mapKey1 = "metrics_memory:"+PodDataSynConfig.CURRENT_POD;String url = String.format("%s/apis/metrics.k8s.io/v1beta1/namespaces/%s/pods/%s", apiClient.getBasePath(),kubernetesServiceImpl.getNamespace(), PodDataSynConfig.CURRENT_POD);ResponseEntity<PodMetrics> response = extendK8sRestTemplate.getForEntity(url, PodMetrics.class);if (response.getBody() != null && response.hasBody()){if(response.getBody().getContainers() != null && response.getBody().getContainers().get(0) != null){String cpu = response.getBody().getContainers().get(0).getUsage().getCpu();String memory = response.getBody().getContainers().get(0).getUsage().getMemory();long timestamp = Instant.now().getEpochSecond();redisService.getRedisTemplate().opsForZSet().add(mapKey0, timestamp+":"+cpu,timestamp);redisService.getRedisTemplate().opsForZSet().add(mapKey1, timestamp+":"+memory,timestamp);}}removeOldData(mapKey0,mapKey1);}public void removeOldData(String key0, String key1) {long cutoffTimestamp = Instant.now().getEpochSecond() - 3600; // 60分钟前redisService.getRedisTemplate().opsForZSet().removeRangeByScore(key0, -Double.MAX_VALUE, cutoffTimestamp);redisService.getRedisTemplate().opsForZSet().removeRangeByScore(key1, -Double.MAX_VALUE, cutoffTimestamp);}}
4. 完工:
这样简单读取pod资源的任务就完成了,主要步骤就是 metrics server服务器的部署,然后使用restful api读取信息。