Skip to content

Proposal: Shared Resource Ownership #164

Description

@avarei

I had a little discussion with @davidmdm that I would like to continue here.

At the Moment Yoke does not change resources it did not create in the release context of the specific release.

But in some situations It can be benificial to have multiple CRs manage a single Resource or for an existing resource to be partiall in partially added to management

This could be a resource

  • which only needs to exist once but is a dependency for each
  • where each CR manages different kinds of fields

By setting ownerReferences to a resource that is release specific we ensure the shared resource is not garbage collected, when another owner is deleted until all ownerReferences have are deleted (for this reason blockOwnerDeletion should be considered with extra care)

By using server-side apply with a fieldManager that is specific to a given release the API Server detects and automatically prohibits conflicting applies.

This would make the yoke metadata fields obsolete.

When a release is deleted the managedFields would remain unless cleaned up.
Yoke could potentially use a finalizer on the releases' secret or the ATC CR to clean up the managedFields section on all resources it was a manager for and orphan them.
It would also be possible to apply an empty resource like this which would remove all fields only managed by this resource.
here's an example for the latter variant:

k create svc clusterip --tcp=80 --tcp=8080 test --dry-run=client -oyaml | k apply -f - --server-side --field-manager=yoke/namespace/release1
k create svc clusterip --tcp=80 --tcp=8081 test --dry-run=client -oyaml | k apply -f - --server-side --field-manager=yoke/namespace/release2
k apply -f - --server-side --field-manager=yoke/namespace/release1 <<EOF
apiVersion: v1
kind: Service
metadata:
  name: test
  namespace: default
EOF

The Service is created with port 80 and 8080, then 8081 is added and with the third command the field-manager yoke/namespace/release1 is removed, as well as port 8080.

heres an example how this could look like from the perspective of the shared managed resource

apiVersion: v1
kind: Service
metadata:
  ownerReferences:
  - apiVersion: apps/v1
    kind: Secret
    name: yoke.abc
    uid: abc123
  - apiVersion: apps/v1
    kind: Secret
    name: yoke.def
    uid: def456
  managedFields:
  - apiVersion: v1
    fieldsType: FieldsV1
    fieldsV1:
      f:metadata:
        f:labels:
          f:app: {}
      f:spec:
        f:ports:
          k:{"port":80,"protocol":"TCP"}:
            .: {}
            f:name: {}
            f:port: {}
            f:protocol: {}
            f:targetPort: {}
          k:{"port":8080,"protocol":"TCP"}:
            .: {}
            f:name: {}
            f:port: {}
            f:protocol: {}
            f:targetPort: {}
        f:selector: {}
        f:type: {}
    manager: yoke/namespace/name1
    operation: Apply
    time: "2025-06-08T21:20:50Z"
  - apiVersion: v1
    fieldsType: FieldsV1
    fieldsV1:
      f:metadata:
        f:labels:
          f:app: {}
      f:spec:
        f:ports:
          k:{"port":80,"protocol":"TCP"}:
            .: {}
            f:name: {}
            f:port: {}
            f:protocol: {}
            f:targetPort: {}
          k:{"port":8081,"protocol":"TCP"}:
            .: {}
            f:name: {}
            f:port: {}
            f:protocol: {}
            f:targetPort: {}
        f:selector: {}
        f:type: {}
    manager: yoke/namespace/name2
    operation: Apply
    time: "2025-06-08T21:20:59Z"
  name: test
  namespace: default
  resourceVersion: "60392"
  uid: 959a5d48-2c8a-4cac-b610-1a58d4bc6780
spec:
  clusterIP: 10.105.216.15
  clusterIPs:
  - 10.105.216.15
  internalTrafficPolicy: Cluster
  ipFamilies:
  - IPv4
  ipFamilyPolicy: SingleStack
  ports:
  - name: "80"
    port: 80
    protocol: TCP
    targetPort: 80
  - name: "8080"
    port: 8080
    protocol: TCP
    targetPort: 8080
  - name: "8081"
    port: 8081
    protocol: TCP
    targetPort: 8081
  selector:
    app: test
  sessionAffinity: None
  type: ClusterIP
status:
  loadBalancer: {}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions