kubernetes 在对CRD的Scale子资源进行打补丁时出现错误(合并打补丁时为静默错误)

92vpleto  于 4个月前  发布在  Kubernetes
关注(0)|答案(5)|浏览(95)

发生了什么?
创建了一个CRD,并尝试通过patch子资源而不是通过顶层资源来更改其/scale子资源。
当合并应用/scale时,apiserver后端会有一个可怕的日志记录错误,但对象的托管字段已更新为不正确的值。
当应用/scale patch时,会向客户端返回一个错误:failed to create typed patch object (/; autoscaling/v1, Kind=Scale): no corresponding type for autoscaling/v1, Kind=Scale

预期会发生什么?

成功地应用补丁,并为拥有replicas字段的"scaler"字段管理器添加新的托管字段条目。

我们如何尽可能精确地重现它?

使用kubectl apply --server-side应用CRD:

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: noxus.mygroup.example.com
spec:
  group: mygroup.example.com
  names:
    plural: noxus
    singular: nonenglishnoxu
    shortNames:
      - foo
      - bar
      - abc
      - def
    kind: WishIHadChosenNoxu
    listKind: NoxuItemList
  scope: Namespaced
  versions:
    - name: v1
      served: true
      storage: true
      schema:
        openAPIV3Schema:
          type: object
          x-kubernetes-preserve-unknown-fields: true
      subresources:
        status: {}
        scale:
          specReplicasPath: .spec.replicas
          statusReplicasPath: .status.replicas
          labelSelectorPath: .status.anotherLabelSelector
  conversion:
    strategy: None

使用kubectl apply --server-side应用示例:

apiVersion: mygroup.example.com/v1
kind: WishIHadChosenNoxu
metadata:
  name: foo
  namespace: not-the-default
spec:
  num: 10
  replicas: 3

使用merge patch更改Scale子资源spec.replicas:

❯ kubectl patch foo foo --subresource='scale' --type='merge' -p '{"spec":{"replicas":3}}' --namespace="not-the-default" --field-manager="scaler"
scale.autoscaling/foo patched

查看服务器记录的错误:

E0306 12:51:16.136193   31856 fieldmanager.go:152] "[SHOULD NOT HAPPEN] failed to update managedFields" err="failed to convert new object (not-the-default/foo; autoscaling/v1, Kind=Scale) to smd typed: no corresponding type for autoscaling/v1, Kind=Scale" versionKind="autoscaling/v1, Kind=Scale" namespace="not-the-default" name="foo"

同时观察到,尽管字段已更新,但replicas的托管字段条目已被删除:

❯ kubectl get foo foo --namespace=not-the-default -o yaml --show-managed-fields
apiVersion: mygroup.example.com/v1
kind: WishIHadChosenNoxu
metadata:
  creationTimestamp: "2023-03-06T20:51:08Z"
  generation: 2
  managedFields:
  - apiVersion: mygroup.example.com/v1
    fieldsType: FieldsV1
    fieldsV1:
      f:spec:
        .: {}
        f:num: {}
    manager: kubectl
    operation: Apply
    time: "2023-03-06T20:51:08Z"
  name: foo
  namespace: not-the-default
  resourceVersion: "420"
  uid: 59014404-4fcb-4b12-a7f1-513c875de7f2
spec:
  num: 10
  replicas: 5

如果我不通过子资源更改副本,我的托管字段将按预期更新:

❯ kubectl patch foo foo --type='merge' -p '{"spec":{"replicas":6}}' --namespace="not-the-default" --field-manager="scaler"
wishihadchosennoxu.mygroup.example.com/foo patched

~/Desktop [⌛ 178ms]
❯ kubectl get foo foo --namespace=not-the-default -o yaml --show-managed-fields
apiVersion: mygroup.example.com/v1
kind: WishIHadChosenNoxu
metadata:
  creationTimestamp: "2023-03-06T20:51:08Z"
  generation: 3
  managedFields:
  - apiVersion: mygroup.example.com/v1
    fieldsType: FieldsV1
    fieldsV1:
      f:spec:
        .: {}
        f:num: {}
    manager: kubectl
    operation: Apply
    time: "2023-03-06T20:51:08Z"
  - apiVersion: mygroup.example.com/v1
    fieldsType: FieldsV1
    fieldsV1:
      f:spec:
        f:replicas: {}
    manager: scaler
    operation: Update
    time: "2023-03-06T20:56:21Z"
  name: foo
  namespace: not-the-default
  resourceVersion: "483"
  uid: 59014404-4fcb-4b12-a7f1-513c875de7f2
spec:
  num: 10
  replicas: 6

使用ApplyPatchType控制器通过更新状态也会产生相同的行为,只是与MergePatchType不同,它不会像它那样静默失败,而是向客户端返回错误:
failed to create typed patch object (/; autoscaling/v1, Kind=Scale): no corresponding type for autoscaling/v1, Kind=Scale

我们需要了解其他信息吗?

对于这种情况有一个集成测试,但由于它不提供任何openapi定义,因此在导致SSA对所有类型使用推断类型转换器的配置下运行测试apiserver。在测试中,Scale模型从未被查找。由于kube-apiserver提供了open api定义,因此强制执行查找并失败。
kubernetes/staging/src/k8s.io/apiextensions-apiserver/test/integration/subresources_test.go
第386行 964529b | funcTestApplyScaleSubresource(t*testing.T) { |
我认为查找失败是因为Scale类型是由构建器注入到CRD openapi规范中的,而没有它们的GVK。它们没有GVK,因为用于注入CRD类型的定义名称器在初始化为空方案时使用空方案初始化。该方案用于将具有GVK的扩展添加到定义中:
kubernetes/staging/src/k8s.io/apiextensions-apiserver/pkg/controller/openapi/builder/builder.go
第471行 68eea24 | namer=openapi.NewDefinitionNamer(runtime.NewScheme()) |

dy1byipe

dy1byipe1#

我不确定我完全理解这个。如果我使用一个普通的apiserver,它会无法应用缩放对象吗?测试过去通过是因为它没有OpenAPI?但是现在既然OpenAPI无处不在,它开始失败了吗?是这样的吗?

7bsow1i6

7bsow1i62#

这个测试曾经通过,因为它没有OpenAPI?但现在既然到处都有openapi,它就开始失败了?
不,测试仍然通过。我相信这是一个长期存在的bug,不是由最近的任何更改引起的。测试通过了,但它本不应该通过。它之所以通过,是因为测试环境根本不提供openapi模型,所以使用了SSA推断类型转换器:
kubernetes/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/customresource_handler.go
77fad93中的第683行到第689行
| vartypeConverter fieldmanager.TypeConverter=fieldmanager.NewDeducedTypeConverter() |
| iflen(openAPIModels) >0 { |
| typeConverter, err=fieldmanager.NewTypeConverter(openAPIModels, crd.Spec.PreserveUnknownFields) |
| iferr!=nil { |
| returnnil, err |
| } |
| } |
对于kube-apiserver,提供了openAPIModels,因此构造了类型转换器。但是类型转换器无法正确索引autoscaling/v1.Scale的定义。如果我使用一个普通的apiserver,它会在应用scale对象时失败吗?
是的,这会影响通过/scale子资源修补CRD示例的普通API服务器

v8wbuo2f

v8wbuo2f4#

这个问题已经超过一年没有更新了,应该重新进行优先级评估。
你可以:

  • 确认这个问题仍然与 /triage accepted (仅组织成员)相关
  • /close 关闭这个问题

有关优先级评估过程的更多详细信息,请参见 https://www.kubernetes.dev/docs/guide/issue-triage/
已接受移除优先级评估

相关问题