Skip to content

[FEATURE] Spawn Client pods via DaemonSet/Deployment for HA round-robin via loadBalancer.group #12

Description

@WarrDoge

Is your feature request related to a problem? Please describe.

The Client controller currently builds a single bare corev1.Pod per Client CR (pkg/client/builder/pod_builder.go). For multi-worker Kubernetes clusters that want one frpc per node — so frps can round-robin incoming connections across multiple registered members of a loadBalancer.group — this forces either:

  1. Creating N Client CRs with manual node-pinning (drifts as the worker count changes, ugly to template), or
  2. Running a single Client and losing the HA + load-spreading benefit of loadBalancer.group.

A bare Pod also has no rolling update story and is not rescheduled on NodeLost: the reconciler's Get returns the stuck pod (not NotFound), so the recreate branch never fires. This is worse than the equivalent hand-rolled DaemonSet today.

Describe the solution you'd like

Add a workload-kind selector to Client.spec.podTemplate (or a sibling Client.spec.workload) supporting:

  • Pod (current behavior, default)
  • Deployment with replicas
  • DaemonSet (one pod per matching node)

When combined with Upstream.spec.tcp.loadBalancer.group + groupKey, each replica registers itself as a member of the same group and frps spreads traffic across them — which is exactly the production HA story loadBalancer.group was designed for, but it's currently unreachable through this operator.

Suggested CRD shape (additive, non-breaking):

apiVersion: frp.zufardhiyaulhaq.com/v1alpha1
kind: Client
metadata:
  name: edge
spec:
  server: { ... }
  workload:
    kind: DaemonSet           # Pod | Deployment | DaemonSet
    # for Deployment only:
    replicas: 3
    # nodeSelector / affinity / tolerations remain on podTemplate
  podTemplate:
    nodeSelector:
      node-role.kubernetes.io/worker: ""

Describe alternatives you've considered

  • Generating N Client CRs externally (Helm/Kustomize/Flux templating). Works but defeats the operator abstraction and complicates pod identity for loadBalancer.group membership.
  • Wrapping the operator-managed Pod in an external DaemonSet that shares the same ConfigMap. Bypasses the operator entirely.
  • Switching to a different frp operator. Aureum-Cloud/frp-Operator is TCP-only with no loadBalancer.group, so it's not a viable alternative for HA workloads.

Additional context

loadBalancer.group + groupKey are already supported in UpstreamSpec_TCP.LoadBalancer (api/v1alpha1/upstream_types.go), so the proxy side is ready — only the client workload model needs to scale out. Happy to send a PR if the API shape is agreed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions