一、背景介绍
我司使用的是阿里云的Kubernetes容器服务,也没有什么版本发布系统,测试人员测试完毕以后,直接更新了阿里云的服务镜像地址,如下
虽然,阿里云在界面中也提供了历史版本的查看功能,但是我们想把这部分信息集中存放起来并提供查询功能,该怎么处理呢?
二、实现思路
我们优先想到的是阿里云可以提供相关的API接口,给我们获取到这些信息,奈何阿里云对于Kubernetes容器服务都没有API接口,让我们自行对接原生Kubernetes服务的API。
与此同时,我的另外一位同事对prometheus的监控项和k8s event进行了整理和查找,k8sevent里面并没有发现相关的信息,但是prometheus中是有相关监控项的。
三、简单实现,通过Prometheus
Prometheus的实现如下方语句
changes(kube_deployment_status_observed_generation[5m])!=0
但是上面的监控项存在一个致命缺点,当deployment自动扩容缩容时也会变化,因此需要使用如下语句
changes(kube_deployment_status_observed_generation[5m])!=0 and changes(kube_deployment_status_replicas_available[5m]) == 0
通过以上语句,我们基本实现了获取是哪个namespace的哪个deployment发布了新版本,通过prometheus报警发出的时间,也可以大致判断出发版的时间(相差两三分钟)。可是在我们实际的生产应用中发现会出现不少误报的情况。
四、更加精确详细,K8S API
prometheus的监控数据中没有版本信息,并且时间上有些偏差,因此我们决定使用Kubernetes原生API,经过一番查找,用google搜索kubernetes deployment history 等信息也没有相关的发现,最后在github里发现一个issue[参考资料1], list_namespaced_replica_set 或者 list_replica_set_for_all_namespaces 中存储了相关信息,终于有所收获。
接下来就是分析下接口返回内容,并对有效数据进行提取了,我们的代码如下,供大家参考:
from kubernetes import client, config
config.load_kube_config(config_file='./config')
api_instance = client.AppsV1Api()
def get_images_from_namespace( namespace: str) -> dict:
output = dict()
repl = api_instance.list_namespaced_replica_set(namespace=namespace)
for replica_set in repl.items:
if 'app' not in replica_set.metadata.labels:
app_name = f'{replica_set.spec.template.spec.service_account}'
else:
app_name = f'{replica_set.metadata.labels["app"]}'
if app_name not in output:
output[app_name] = []
app_record = dict()
if 'deployment.kubernetes.io/revision' in replica_set.metadata.annotations:
app_record['revision'] = replica_set.metadata.annotations['deployment.kubernetes.io/revision']
app_record['creation_timestamp'] = replica_set.metadata.creation_timestamp
app_record['containers'] = list()
for container in replica_set.spec.template.spec.containers:
app_record['containers'].append(container.image)
output[app_name].append(app_record)
return output
print(get_images_from_namespace(namespace='default'))
代码运行效果:
{
'gitlab-aliyun-deploy': [{
'revision': '1',
'creation_timestamp': datetime.datetime(2020, 7, 16, 6, 17, 23, tzinfo = tzutc()),
'containers': ['reg.ipcpu.com/juestest/my-deploy:1131-5d6f0278']
}, {
'revision': '3',
'creation_timestamp': datetime.datetime(2020, 7, 16, 8, 40, 37, tzinfo = tzutc()),
'containers': ['reg.ipcpu.com/juestest/my-deploy:1139-3a5695af']
}, {
'revision': '2',
'creation_timestamp': datetime.datetime(2020, 7, 16, 8, 25, 51, tzinfo = tzutc()),
'containers': ['reg.ipcpu.com/juestest/my-deploy:1139-3a5695af']
}]
}
五、更科学,使用watch接口
在生产环境中,由于每天发版的次数都在数十上百次,采集上面这个接口每次返回海量的日志,一是对带宽,二是对API接口造成比较大的压力。好在K8S本身就有watch接口,来监听变化内容。
from kubernetes import client, config, watch
import json
config.load_kube_config(config_file='./config')
v1 = client.AppsV1Api()
w = watch.Watch()
for event in w.stream(func=v1.list_replica_set_for_all_namespaces):
print('=======')
print(event['type'])
print(event['object'])
六、参考资料
https://github.com/kubernetes-client/python/issues/694
转载请注明:IPCPU-网络之路 » 如何获取到Kubernetes中的版本发布信息