Skip to content

Deprecating ManagedProxyServiceResolver in cluster-proxy. #1249

@xuezhaojun

Description

@xuezhaojun

Executive Summary

Propose to deprecate and remove the ManagedProxyServiceResolver CRD in the next major release of cluster-proxy. This API was designed to expose arbitrary services from managed clusters to the hub cluster through the proxy tunnel. However, its complexity far exceeds the value it provides, especially given that simpler alternatives (service-proxy pattern and direct kube-apiserver access) already exist in the codebase.

Key Decision: We will adopt the service-proxy pattern as the recommended approach for service exposure, which provides the same core functionality with significantly reduced complexity.


API Complexity Analysis

Multi-Layer Dependency Chain

The ManagedProxyServiceResolver API requires understanding and correctly configuring a complex dependency chain:

ManagedProxyServiceResolver (cluster-scoped CRD)
    ↓ references
ManagedClusterSet (v1beta2)
    ↓ selects via LabelSelector
ManagedCluster (v1)
    ↓ points to
Kubernetes Service (on managed cluster)

Any misconfiguration at any level in this chain results in silent failure, making troubleshooting extremely difficult.

Indirect Service Naming

Services are not accessed by intuitive names but through SHA256-hashed hostnames:

// Instead of: prometheus.monitoring.cluster1
// Users must use: cluster-proxy-a1b2c3d4e5f6... (max 63 chars)

// Generation logic:
content := sha256.Sum256([]byte(fmt.Sprintf("%s %s %s", cluster, namespace, service)))
hostname := fmt.Sprintf("cluster-proxy-%x", content)[:63]

Impact:

  • Users cannot guess or memorize service URLs
  • Must use client library or manually calculate hashes
  • Debugging connection issues requires understanding the hash algorithm
  • No human-readable service discovery

Validation Complexity

File: pkg/util/serviceresolver.go:7-23

func IsServiceResolverLegal(mpsr *ManagedProxyServiceResolver) bool {
    // Check managed cluster selector type
    if mpsr.Spec.ManagedClusterSelector.Type != ManagedClusterSelectorTypeClusterSet {
        return false
    }
    if mpsr.Spec.ManagedClusterSelector.ManagedClusterSet == nil {
        return false
    }
    // Check service selector type
    if mpsr.Spec.ServiceSelector.Type != ServiceSelectorTypeServiceRef {
        return false
    }
    if mpsr.Spec.ServiceSelector.ServiceRef == nil {
        return false
    }
    return true
}

Problems:

  • No admission webhook validation
  • Invalid resources are created but silently ignored
  • Status controller only reports errors, doesn't prevent creation
  • Users discover issues only after deployment

Maintenance Burden

Code Distribution

ManagedProxyServiceResolver touches 23+ files across the codebase:

Category Files Examples
CRD definitions 2 managedproxyserviceresolver_types.go, CRD manifests
Generated code 10+ clientset, informers, listers, deepcopy
Core logic 5 agent.go, serviceresolver.go, client.go
Controllers 1 service_resolver_controller.go
Tests 3 unit tests, integration tests, e2e tests
Documentation 3 access-exported-services.md, access-prometheus.md
Total 23+

Additional Runtime Components

ServiceResolverReconciler Controller:

// File: pkg/proxyserver/controllers/service_resolver_controller.go

// Watches:
// 1. ManagedProxyServiceResolver changes
// 2. ManagedClusterSet changes (triggers reconciliation)

// Responsibilities:
// - Validate MPSR spec
// - Check if referenced ClusterSet exists
// - Update status conditions

Impact:

  • Additional controller running in addon-manager
  • Increases memory and CPU usage
  • More code to test and maintain
  • Version compatibility concerns

Service Proxy Pattern

The service-proxy pattern provides human-readable, intuitive URLs for accessing services on managed clusters:

https://cluster-proxy-addon-user.open-cluster-management-addon.svc:9092/<cluster-name>/api/v1/namespaces/<namespace>/services/<protocol>:<service-name>:<port>/<path>

URL Pattern Breakdown:

https://cluster-proxy-addon-user.open-cluster-management-addon.svc:9092
      └─ Hub service endpoint

/cluster1
 └─ Managed cluster name (human-readable!)

/api/v1/namespaces/default/services
 └─ Standard Kubernetes API path

/http:hello-world:8000
 └─ protocol:service-name:port (clear and descriptive)

/proxy-service/index.html
 └─ Path to the actual resource

Compare

// Old (MPSR):
proxyHost, _ := clusterproxyclient.GetProxyHost(ctx, cfg, cluster, ns, svc)
url := fmt.Sprintf("http://%s:%d", proxyHost, port)  // cryptic hash

// New (Service-Proxy):
url := fmt.Sprintf(
    "https://cluster-proxy-addon-user.open-cluster-management-addon.svc:9092/%s/api/v1/namespaces/%s/services/http:%s:%d/proxy-service/",
    cluster, ns, svc, port,
)  // human-readable!

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    Status

    In Progress

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions