Skip to content

Custom resource reflection for namespace offloading (OwnershipShared) #3330

Open

Description

@sinadarbouy

Describe the problem you are having (if any)

Liqo namespace offloading extends a namespace across clusters and reflects a fixed set of native Kubernetes resources (ConfigMaps, Secrets, Services, PVCs, etc.) through the Virtual Kubelet. It does not support user-defined Custom Resources (CRs).

This is a blocker for multi-cluster setups where:

  • A consumer offloads a namespace to a provider (twin namespace).
  • CRs are created or updated on the consumer.
  • A controller on the provider reconciles the remote CR and writes its status.
  • The consumer needs the desired spec propagated remotely and the resulting status reflected locally.

Historically, Liqo supported peering-level CR replication through the CRD replicator, but that mechanism was removed and was not integrated with namespace offloading. There is currently no supported, generic way to reflect selected namespaced GVRs across an offloaded namespace pair.

Describe the solution you would like

Add generic, opt-in Custom Resource reflection to the Virtual Kubelet.

Operators configure arbitrary namespaced Group/Version/Resources (GVRs) through Helm:

offloading:
  reflection:
    customResources:
      - group: example.io
        version: v1
        resource: widgets
        workers: 2
        type: AllowList

The configuration is propagated to VkOptionsTemplate. For every configured GVR, the Virtual Kubelet starts a dynamic, unstructured reflector when a namespace is activated through the existing NamespaceMap lifecycle.

Reflection follows OwnershipShared semantics:

  • spec: consumer/local → provider/remote
  • status: provider/remote → consumer/local

Custom Resource reflection defaults to AllowList. Individual CR instances opt in with:

metadata:
  annotations:
    liqo.io/allow-reflection: "true"

An empty customResources list means that Custom Resource reflection is disabled. No application-specific CRDs are hardcoded in Liqo.

Describe the user value of this feature

  • Enables operators based on Custom Resources to work across offloaded namespaces.
  • Preserves clear ownership: the consumer owns desired state, while the provider reconciles it and owns status.
  • Reuses the existing Virtual Kubelet reflection model and namespace lifecycle.
  • Supports arbitrary namespaced CRDs without coupling Liqo to a specific application or operator.
  • Keeps the feature disabled by default and requires explicit GVR and per-object opt-in.

Describe your proposed solution

The implementation is centered on the Virtual Kubelet reflection subsystem rather than changes to NamespaceOffloading or new liqoctl flags.

Configuration and API

  • Add a customResources list to VkOptionsTemplate.
  • Expose it through the Helm value offloading.reflection.customResources.
  • Each entry contains group, version, resource, workers, and reflection type.
  • Do not add customResources to NamespaceOffloading.
  • Do not add a liqoctl --replicate-cr flag.

Reflection

  • Implement a generic reflector using dynamic Kubernetes clients and unstructured objects.
  • Register one reflector for each configured GVR.
  • Start and stop reflectors through the existing NamespaceMap / Virtual Kubelet namespace lifecycle.
  • Create or update the remote object from the local desired state.
  • Propagate remote status back through the local status subresource.
  • Preserve the normal Liqo reflection annotations, labels, policies, and cleanup behavior.

RBAC

  • Generate local and remote Virtual Kubelet RBAC rules from the configured GVR list.
  • Grant only the verbs required for reflection and status synchronization.
  • Keep the default RBAC unchanged when the list is empty.

MVP scope and limitations

  • OwnershipShared semantics only: spec local → remote and status remote → local.
  • Namespaced Custom Resources only; cluster-scoped resources are not supported.
  • Compatible CRDs must already exist on both clusters; Liqo does not install CRDs.
  • Default policy is AllowList using liqo.io/allow-reflection: "true".
  • Existing VirtualNodes may need to be recreated or re-peered after changing the configured GVR list so that configuration and RBAC are refreshed.
  • The controller for a reflected type should run on one side only to prevent competing reconciliations.
  • Remote changes to spec are overwritten by the local desired state.
  • Cross-resource references and hardcoded namespaces inside a CR are copied as-is and may require application-level handling.

Validation

The design has been validated with bidirectional peering and selected-name namespace mappings:

  • Annotated CR instances were reflected from the consumer namespace to its remote twin.
  • Provider-side status updates were reflected back to the local CR.
  • Unannotated CR instances were not reflected under the default AllowList policy.
  • No application-specific CRD types were required in the implementation.

Do you volunteer to implement this feature?

  • I want to implement this feature

Code of Conduct

  • I agree to follow this project's Code of Conduct

Activity

  1. changed the title [-]Custom resource replication for namespace offloading (RemoteToLocal)[/-] [+]Custom resource replication for namespace offloading (Bidirectional + RemoteToLocal)[/+] on Jul 16, 2026
  2. changed the title [-]Custom resource replication for namespace offloading (Bidirectional + RemoteToLocal)[/-] [+]Custom resource replication for namespace offloading (OwnershipShared)[/+] on Jul 21, 2026
  3. changed the title [-]Custom resource replication for namespace offloading (OwnershipShared)[/-] [+]Custom resource reflection for namespace offloading (OwnershipShared)[/+] on Jul 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions