未加--save-config执行kubectl create:为何Service有字段管理器而ServiceAccount无
在CAPI集群中,使用kubectl apply和kubectl create创建Service(或Pod)时,二者的managedFields几乎一致(仅存在last-applied-configuration这类预期差异),但ServiceAccount的表现却截然不同——kubectl create创建的ServiceAccount完全没有managedFields,而kubectl apply创建的则包含明确的字段管理器记录。
Service(或Pod)的创建对比
kubectl create 结果
$ k get svc my-service -oyaml --show-managed-fields apiVersion: v1 kind: Service metadata: creationTimestamp: "2024-01-26T18:40:15Z" managedFields: - apiVersion: v1 fieldsType: FieldsV1 fieldsV1: f:spec: f:internalTrafficPolicy: {} f:ports: .: {} k:{"port":80,"protocol":"TCP"}: .: {} f:port: {} f:protocol: {} f:targetPort: {} f:selector: {} f:sessionAffinity: {} f:type: {} manager: kubectl-create operation: Update time: "2024-01-26T18:40:15Z" name: my-service namespace: default resourceVersion: "548809" uid: 7d57743d-9b8d-4f04-850b-7ca6d5e1347a spec: clusterIP: 172.19.186.161 clusterIPs: - 172.19.186.161 internalTrafficPolicy: Cluster ipFamilies: - IPv4 ipFamilyPolicy: SingleStack ports: - port: 80 protocol: TCP targetPort: 9376 selector: app.kubernetes.io/name: MyApp sessionAffinity: None type: ClusterIP status: loadBalancer: {}
kubectl apply 结果
$ k get svc my-service -oyaml --show-managed-fields apiVersion: v1 kind: Service metadata: annotations: kubectl.kubernetes.io/last-applied-configuration: | {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"my-service","namespace":"default"},"spec":{"ports":[{"port":80,"protocol":"TCP","targetPort":9376}],"selector":{"app.kubernetes.io/name":"MyApp"}}} creationTimestamp: "2024-01-26T18:41:00Z" managedFields: - apiVersion: v1 fieldsType: FieldsV1 fieldsV1: f:metadata: f:annotations: .: {} f:kubectl.kubernetes.io/last-applied-configuration: {} f:spec: f:internalTrafficPolicy: {} f:ports: .: {} k:{"port":80,"protocol":"TCP"}: .: {} f:port: {} f:protocol: {} f:targetPort: {} f:selector: {} f:sessionAffinity: {} f:type: {} manager: kubectl-client-side-apply operation: Update time: "2024-01-26T18:41:00Z" name: my-service namespace: default resourceVersion: "548931" uid: 8a378bcc-b70e-441b-8b55-463f7700e1f3 spec: clusterIP: 172.19.141.7 clusterIPs: - 172.19.141.7 internalTrafficPolicy: Cluster ipFamilies: - IPv4 ipFamilyPolicy: SingleStack ports: - port: 80 protocol: TCP targetPort: 9376 selector: app.kubernetes.io/name: MyApp sessionAffinity: None type: ClusterIP status: loadBalancer: {}
结果:二者的managedFields结构几乎一致,仅存在kubectl-client-side-apply管理器添加的last-applied-configuration注解差异。
ServiceAccount的创建对比
kubectl create 结果
$ k get sa -oyaml --show-managed-fields apiVersion: v1 items: - apiVersion: v1 kind: ServiceAccount metadata: creationTimestamp: "2024-01-24T15:11:24Z" name: build-robot namespace: default resourceVersion: "7337504" uid: e2414d28-d897-4099-ac5d-699c89835615 secrets: - name: build-robot-token-77p6d
kubectl apply 结果
$ k get sa -oyaml --show-managed-fields apiVersion: v1 items: - apiVersion: v1 kind: ServiceAccount metadata: annotations: kubectl.kubernetes.io/last-applied-configuration: | {"apiVersion":"v1","kind":"ServiceAccount","metadata":{"annotations":{},"name":"build-robot","namespace":"default"}} creationTimestamp: "2024-01-24T15:10:55Z" managedFields: - apiVersion: v1 fieldsType: FieldsV1 fieldsV1: f:secrets: .: {} k:{"name":"build-robot-token-8rqgq"}: {} manager: kube-controller-manager operation: Update time: "2024-01-24T15:10:55Z" - apiVersion: v1 fieldsType: FieldsV1 fieldsV1: f:metadata: f:annotations: .: {} f:kubectl.kubernetes.io/last-applied-configuration: {} manager: kubectl-client-side-apply operation: Update time: "2024-01-24T15:10:55Z" name: build-robot namespace: default resourceVersion: "7337399" uid: 0bac2513-844f-4526-b374-3642bdf26838 secrets: - name: build-robot-token-8rqgq
结果:kubectl create创建的ServiceAccount完全没有managedFields条目,而kubectl apply创建的则包含kubectl-client-side-apply和kube-controller-manager两个字段管理器的记录。
原因分析
字段管理器的设置逻辑差异
对于Service、Pod这类常规资源,kubectl create在调用Kubernetes API时会明确设置fieldManager=kubectl-create参数,API Server会根据这个参数生成对应的managedFields条目,记录该资源的初始创建者。
但针对ServiceAccount资源,部分版本的kubectl create sa命令使用了特殊的客户端逻辑,未在API请求中携带fieldManager参数。API Server在接收未指定fieldManager的创建请求时,不会生成managedFields条目。kube-controller-manager的后续处理
ServiceAccount创建后,kube-controller-manager会自动为其生成关联的Token Secret并更新资源。- 对于
kubectl apply创建的ServiceAccount,由于初始请求携带了fieldManager=kubectl-client-side-apply,API Server已经生成了managedFields,后续控制器的更新会以kube-controller-manager作为字段管理器添加新的条目。 - 对于
kubectl create创建的ServiceAccount,因为没有初始的managedFields,控制器的更新也不会触发managedFields的生成,最终导致该资源完全没有字段管理器记录。
- 对于
版本或集群配置影响
部分较新的kubectl版本已经修复了这个问题,kubectl create sa会正确设置fieldManager参数,但在CAPI集群使用的特定版本中可能仍存在此行为差异。
内容的提问来源于stack exchange,提问作者subtleseeker

