同一个 Kubernetes 对象可以用多个 API 版本读写,它们是同一份数据的不同视图。这篇拿 HPA 的 v1 和 v2 对照着读,把 etcd 里存的版本解码出来,再看弃用警告是怎么从服务端传到你终端的,以及 kubectl 到底请求了哪个版本。
v2:apiVersion=autoscaling/v2;spec 的键 ['behavior', 'maxReplicas', 'metrics', 'minReplicas', 'scaleTargetRef'];metrics 有 2 项:cpu=50%, memory=70%
v1:apiVersion=autoscaling/v1;spec 的键 ['maxReplicas', 'minReplicas', 'scaleTargetRef', 'targetCPUUtilizationPercentage'];targetCPUUtilizationPercentage=50
v1 多出来的注解:autoscaling.alpha.kubernetes.io/behavior, autoscaling.alpha.kubernetes.io/conditions, autoscaling.alpha.kubernetes.io/metrics
autoscaling.alpha.kubernetes.io/metrics = [{"type":"Resource","resource":{"name":"memory","targetAverageUtilization":70}}]
v2 的注解里有 autoscaling.alpha 开头的吗:False同一个 HPA,v2 读出来 spec 有 metrics(CPU 50%、内存 70% 两项)和 behavior。v1 的 schema 里只有 targetCPUUtilizationPercentage,装不下的内存指标、behavior 和 conditions 被写进 autoscaling.alpha.kubernetes.io/metrics、/behavior、/conditions 三个注解里,所以旧客户端读到的是个“降级”的视图。用 v1 去改这个对象时要特别小心别把这些注解当普通注解弄丢了。
用 autoscaling/v1 创建 h2:horizontalpodautoscaler.autoscaling/h2 created h1:etcd 里的值 1334 字节,开头 b'k8s\x00'(k8s 的 protobuf 封装),解出的 apiVersion=autoscaling/v2 kind=HorizontalPodAutoscaler h2:etcd 里的值 1006 字节,开头 b'k8s\x00'(k8s 的 protobuf 封装),解出的 apiVersion=autoscaling/v2 kind=HorizontalPodAutoscaler
不管用 v2 还是 v1 创建,etcd 里的值都以 k8s\x00 开头(内置资源用 protobuf 封装),解出的类型头都是 autoscaling/v2 HorizontalPodAutoscaler。写入时先转成存储版本,读取时再转成请求的版本。注意内置资源在 etcd 里不是 JSON(CRD 才是)。
kubectl get endpoints -n default 的输出:
NAME ENDPOINTS AGE
kubernetes 172.18.0.3:6443 22m
Warning: v1 Endpoints is deprecated in v1.33+; use discovery.k8s.io/v1 EndpointSlice
/metrics 里的弃用记录:
# TYPE apiserver_requested_deprecated_apis gauge
apiserver_requested_deprecated_apis{group="",removed_release="",resource="endpoints",subresource="",version="v1"} 1
apiserver_requested_deprecated_apis{group="k5.example.com",removed_release="",resource="things",subresource="",version="v1beta1"} 1
响应头里的警告:299 - "v1 Endpoints is deprecated in v1.33+; use discovery.k8s.io/v1 EndpointSlice"
kubectl get things.v1beta1.k5.example.com:Warning: k5.example.com/v1beta1 Thing 已弃用,请改用 k5.example.com/v1 Thing | No resources found in k5 namespace.
kubectl get things.v1.k5.example.com:No resources found in k5 namespace.读 v1 的 Endpoints,服务端在响应头里加了 Warning: 299 - "v1 Endpoints is deprecated in v1.33+; use discovery.k8s.io/v1 EndpointSlice",kubectl 把它打印在输出末尾。/metrics 里 apiserver_requested_deprecated_apis 是 gauge:请求过就是 1,不是请求次数,标签里有 removed_release(会被移除的版本,这里为空)。自己的 CRD 也可以给版本标 deprecated: true 并写自定义的 deprecationWarning,用旧版本读就会收到,metrics 里也会多出对应的一行。
kubectl api-versions 里 autoscaling 的版本:autoscaling/v1 autoscaling/v2 /apis/autoscaling:preferredVersion=autoscaling/v2;versions 的顺序 ['autoscaling/v2', 'autoscaling/v1'] kubectl get hpa 实际请求的路径:/apis/autoscaling/v2/namespaces/k5/horizontalpodautoscalers?limit=500 kubectl get horizontalpodautoscalers.v1.autoscaling 实际请求的路径:/apis/autoscaling/v1/namespaces/k5/horizontalpodautoscalers?limit=500 kubectl get horizontalpodautoscalers.v2.autoscaling 实际请求的路径:/apis/autoscaling/v2/namespaces/k5/horizontalpodautoscalers?limit=500 kubectl get hpa.v1.autoscaling(短名带版本) 实际请求的路径:/apis/autoscaling/v2/namespaces/k5/horizontalpodautoscalers?limit=500
/apis/autoscaling 返回 preferredVersion: autoscaling/v2,versions 里 v2 排在前面。kubectl get hpa 请求 /apis/autoscaling/v2/…;想读 v1 要写全名 horizontalpodautoscalers.v1.autoscaling。hpa.v1.autoscaling 这种“短名加版本”的写法版本会被忽略,仍然请求 v2——排查旧版本问题时要用 -v=6 确认请求路径。