作者:Jordan Liggitt(谷歌)
作为Kubernetes的维护者,我们一直在寻找在保持兼容性的同时提高可用性的方法。在开发特性、分类bug和回答支持问题的过程中,我们积累了有助于Kubernetes用户了解的信息。在过去,信息的共享仅限于发布说明、公告电子邮件、文档和博客文章等外部方法。除非有人知道该信息并设法找到它,否则他们不会从中受益。
在Kubernetes v1.19中,我们添加了一个特性,允许Kubernetes API服务器向API客户机发送警告。警告是使用标准的Warning响应头发送的,因此它不会以任何方式更改状态代码或响应体。这允许服务器发送警告,任何API客户端都可以轻松读取,同时保持与以前的客户端版本兼容。
警告在kubectl v1.19+的stderr输出和k8s.io/client-go客户端库v0.19.0+的日志输出。k8s.io/client-go的设定可以按进程或按客户端覆盖。
弃用的警告
我们使用这个新功能的第一种方式是,对使用已弃用的API(deprecated API)发送警告。
Kubernetes是一个快速发展的大型项目。即使对于全职从事项目的人来说,跟上每个版本中的变化也是一件令人生畏的事情。一种重要的改变是API的弃用。随着Kubernetes中的API升级到GA版本,预发布的API版本将被弃用并最终被删除。
即使有一个延长的弃用期,并且在发布说明中包含了弃用,它们仍然很难跟踪。在弃用期间,预发布API仍然有效,允许多个版本转换为稳定的API版本。然而,我们发现,用户通常甚至没有意识到他们所依赖的API版本已经弃用,直到他们升级到不再提供它的版本。
从v1.19开始,每当向弃用的REST API发出请求时,都会在API响应的同时返回一个警告。此警告包括有关API将不再可用的版本的详细信息,以及替换的API版本。
因为警告来自服务器,在客户端被拦截,所以它适用于所有的kubectl命令,包括像kubectl apply这样的高级命令,和像kubectl get --raw这样的低级命令:
这有助于受弃用影响的人知道他们发出的请求已被弃用,他们需要多长时间来解决这个问题,以及他们应该使用什么API来替代。当用户应用自己没有创建的清单时,这尤其有用,这样他们就有时间联系作者,要求更新版本。
我们还意识到,使用已弃用API的人通常不是负责升级集群的同一个人,因此我们添加了两个面向管理员的工具,以帮助跟踪已弃用API的使用情况,并确定何时升级是安全的。
指标
从Kubernetes v1.19开始,当向已弃用的REST API端点发出请求时,在kube-apiserver进程中将apiserver_requested_deprecated_apis度量指标设置为1。此指标具有API group、version、resource、subresource的标签,以及一个removed_version标签,该标签指示不再提供API的Kubernetes版本。
这是一个使用kubectl、prom2json和jq的示例查询,用于确定API服务器的当前实例请求了哪些弃用的API:
kubectl get --raw /metrics | prom2json | jq '
.[] | select(.name=="apiserver_requested_deprecated_apis").metrics[].labels
'
输出:
{
"group": "extensions",
"removed_release": "1.22",
"resource": "ingresses",
"subresource": "",
"version": "v1beta1"
}
{
"group": "rbac.authorization.k8s.io",
"removed_release": "1.22",
"resource": "clusterroles",
"subresource": "",
"version": "v1beta1"
}
这显示了弃用的extensions/v1beta1 Ingress和rbac.authorization.k8s.io/v1beta1 ClusterRole API在此服务器上被请求,将在v1.22中被删除。
我们可以将这些信息与apiserver_request_total指标连接起来,以获得关于向这些API发出的请求的更多细节:
kubectl get --raw /metrics | prom2json | jq '
# set $deprecated to a list of deprecated APIs
[
.[] |
select(.name=="apiserver_requested_deprecated_apis").metrics[].labels |
{group,version,resource}
] as $deprecated
|
# select apiserver_request_total metrics which are deprecated
.[] | select(.name=="apiserver_request_total").metrics[] |
select(.labels | {group,version,resource} as $key | $deprecated | index($key))
'
输出:
{
"labels": {
"code": "0",
"component": "apiserver",
"contentType": "application/vnd.kubernetes.protobuf;stream=watch",
"dry_run": "",
"group": "extensions",
"resource": "ingresses",
"scope": "cluster",
"subresource": "",
"verb": "WATCH",
"version": "v1beta1"
},
"value": "21"
}
{
"labels": {
"code": "200",
"component": "apiserver",
"contentType": "application/vnd.kubernetes.protobuf",
"dry_run": "",
"group": "extensions",
"resource": "ingresses",
"scope": "cluster",
"subresource": "",
"verb": "LIST",
"version": "v1beta1"
},
"value": "1"
}
{
"labels": {
"code": "200",
"component": "apiserver",
"contentType": "application/json",
"dry_run": "",
"group": "rbac.authorization.k8s.io",
"resource": "clusterroles",
"scope": "cluster",
"subresource": "",
"verb": "LIST",
"version": "v1beta1"
},
"value": "1"
}
输出显示,只对这些API发出读请求,大多数请求是为了监视已弃用的Ingress API。
你还可以通过以下Prometheus查询找到该信息,该查询返回关于对将在v1.22中删除的已弃用API的请求的信息:
apiserver_requested_deprecated_apis{removed_version="1.22"} * on(group,version,resource,subresource)
group_right() apiserver_request_total
审计注释
指标是检查是否正在使用弃用API,以及使用速度的一种快速方法,但是它们没有包含足够的信息来识别特定的客户机或API对象。从Kubernetes v1.19开始,对已弃用API的请求的审计事件包括一个审计注释"k8s.io/deprecated":"true"。管理员可以使用这些审计事件来标识需要更新的特定客户端或对象。
Custom Resource Definitions
从v1.19开始,除了API服务器警告已弃用API的功能外,CustomResourceDefinition还可以指示它所定义的资源的特定版本已被弃用。当API请求自定义资源的已弃用版本时,将返回一条警告消息,与内置API的行为相匹配。
如果需要,CustomResourceDefinition的作者还可以为每个版本定制警告。这允许他们提供一个指向迁移指南的指针,或者在需要时提供其他信息。
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
name: crontabs.example.com
spec:
versions:
- name: v1alpha1
# This indicates the v1alpha1 version of the custom resource is deprecated.
# API requests to this version receive a warning in the server response.
deprecated: true
# This overrides the default warning returned to clients making v1alpha1 API requests.
deprecationWarning: "example.com/v1alpha1 CronTab is deprecated; use example.com/v1 CronTab (see http://example.com/v1alpha1-v1)"
...
- name: v1beta1
# This indicates the v1beta1 version of the custom resource is deprecated.
# API requests to this version receive a warning in the server response.
# A default warning message is returned for this version.
deprecated: true
...
- name: v1
...
Admission Webhooks
Admission webhook是与Kubernetes集成自定义策略或验证的主要方式。从v1.19开始,admission webhook可以返回警告消息,这些消息被传递到请求API客户端。警告可以与允许或拒绝录取回答一起返回。
例如,允许一个请求,但警告一个已知的配置不工作,admission webhook可以发送这样的响应:
{
"apiVersion": "admission.k8s.io/v1",
"kind": "AdmissionReview",
"response": {
"uid": "<value from request.uid>",
"allowed": true,
"warnings": [
".spec.memory: requests >1GB do not work on Fridays"
]
}
}
如果你正在实现一个webhook返回一个警告消息,这里有一些提示:
admission webhook使用这个新特性的方式有很多,我很期待看到人们会提出什么。这里有一些建议让你开始:
Kubectl严格模式
如果你想确保尽快注意到弃用并立即着手解决它们,kubectl在v1.19中添加了一个--warnings-as-errors选项。使用此选项调用时,kubectl将从服务器接收到的任何警告视为错误,并以非零退出代码退出:
这可以在CI作业中用于将清单应用到当前服务器,并且需要使用零退出代码传递,以表示CI作业成功。
未来的可能性
现在,我们已经有了一种方法,可以在上下文中向用户传递有用的信息,我们在考虑使用这种方法来改善用户使用Kubernetes的体验。我们讨论了的两个方面是关于已知有问题的值的警告,由于兼容性原因,我们不能完全拒绝这些值,以及关于使用不推荐使用的字段或字段值的警告(比如使用beta os/arch节点标签的selector,在v1.14弃用)。我很高兴看到这一领域的进展,Kubernetes的使用越来越容易。
Jordan Liggitt是谷歌的一名软件工程师,帮助领导Kubernetes的认证、授权和API工作。