nfs: support custom NFS server port

When NFS runs with host networking, port 2049 may already be in use.
Add CephNFS spec.server.port (default 2049), wire it through Ganesha
config, the operator Service, and probes, and regenerate CRDs.

Signed-off-by: raaizik <raaizik@yahoo.com>
This commit is contained in:
raaizik authored and raaizik committed 2026-07-27 13:54:57 +03:00
1 parent 65af8e4f1b
commit 5e36fa4bc3
7 files changed
+57 -10

No files matched your search

+13
View File
@@ -8259,6 +8259,19 @@ bool
</tr>
<tr>
<td>
<code>port</code><br/>
<em>
int32
</em>
</td>
<td>
<em>(Optional)</em>
<p>The port the NFS server (NFS-Ganesha) will listen on for NFS clients. Defaults to 2049.
Useful when host networking is enabled and the default NFS port is already in use.</p>
</td>
</tr>
<tr>
<td>
<code>livenessProbe</code><br/>
<em>
<a href="#ceph.rook.io/v1.ProbeSpec">
@@ -11515,6 +11515,14 @@ spec:
type: array
type: object
x-kubernetes-preserve-unknown-fields: true
port:
description: |-
The port the NFS server (NFS-Ganesha) will listen on for NFS clients. Defaults to 2049.
Useful when host networking is enabled and the default NFS port is already in use.
format: int32
maximum: 65535
minimum: 1
type: integer
priorityClassName:
description: PriorityClassName sets the priority class on the pods
type: string
+8
View File
@@ -11508,6 +11508,14 @@ spec:
type: array
type: object
x-kubernetes-preserve-unknown-fields: true
port:
description: |-
The port the NFS server (NFS-Ganesha) will listen on for NFS clients. Defaults to 2049.
Useful when host networking is enabled and the default NFS port is already in use.
format: int32
maximum: 65535
minimum: 1
type: integer
priorityClassName:
description: PriorityClassName sets the priority class on the pods
type: string
+11
View File
@@ -49,6 +49,17 @@ func (n *CephNFS) IsHostNetwork(c *ClusterSpec) bool {
return c.Network.IsHost()
}
// DefaultNFSPort is the default port NFS-Ganesha listens on for NFS clients.
const DefaultNFSPort int32 = 2049
// GetPort returns the NFS listen port, or the default (2049) if unset.
func (n *CephNFS) GetPort() int32 {
if n.Spec.Server.Port != 0 {
return n.Spec.Server.Port
}
return DefaultNFSPort
}
func (sec *NFSSecuritySpec) Validate() error {
if sec == nil {
return nil
+7
View File
@@ -3070,6 +3070,13 @@ type GaneshaServerSpec struct {
// +optional
HostNetwork *bool `json:"hostNetwork,omitempty"`
// The port the NFS server (NFS-Ganesha) will listen on for NFS clients. Defaults to 2049.
// Useful when host networking is enabled and the default NFS port is already in use.
// +kubebuilder:validation:Minimum=1
// +kubebuilder:validation:Maximum=65535
// +optional
Port int32 `json:"port,omitempty"`
// A liveness-probe to verify that Ganesha server has valid run-time state.
// If LivenessProbe.Disabled is false and LivenessProbe.Probe is nil uses default probe.
// +optional
+2
View File
@@ -109,12 +109,14 @@ func getGaneshaConfig(n *cephv1.CephNFS, version cephver.CephVersion, name strin
nodeID := getNFSNodeID(n, name)
userID := getNFSUserID(nodeID)
url := getRadosURL(n)
port := n.GetPort()
return `
NFS_CORE_PARAM {
Enable_NLM = false;
Enable_RQUOTA = false;
Protocols = 4;
allow_set_io_flusher_fail = true;
NFS_Port = ` + fmt.Sprintf("%d", port) + `;
}
MDCACHE {
+8 -10
View File
@@ -30,7 +30,6 @@ import (
"github.com/rook/rook/pkg/util/log"
apps "k8s.io/api/apps/v1"
v1 "k8s.io/api/core/v1"
kerrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
@@ -41,13 +40,13 @@ const (
AppName = "rook-ceph-nfs"
ganeshaContainerName = "nfs-ganesha"
ganeshaConfigVolume = "ganesha-config"
nfsPort = 2049
ganeshaPid = "/var/run/ganesha/ganesha.pid"
nfsGaneshaMetricsPort = 9587
)
func (r *ReconcileCephNFS) generateCephNFSService(nfs *cephv1.CephNFS, cfg daemonConfig) *v1.Service {
labels := getLabels(nfs, cfg.ID, true)
nfsPort := nfs.GetPort()
svc := &v1.Service{
ObjectMeta: metav1.ObjectMeta{
@@ -92,16 +91,13 @@ func (r *ReconcileCephNFS) createCephNFSService(nfs *cephv1.CephNFS, cfg daemonC
return errors.Wrapf(err, "failed to set owner reference to ceph nfs %q", s)
}
svc, err := r.context.Clientset.CoreV1().Services(nfs.Namespace).Create(r.opManagerContext, s, metav1.CreateOptions{})
// Update the svc if it already exists so a changed spec.server.port takes effect.
svc, err := k8sutil.CreateOrUpdateService(r.opManagerContext, r.context.Clientset, nfs.Namespace, s)
if err != nil {
if !kerrors.IsAlreadyExists(err) {
return errors.Wrap(err, "failed to create ganesha service")
}
log.NamedInfo(nsName, logger, "ceph nfs service already created")
return nil
return errors.Wrap(err, "failed to create or update ganesha service")
}
log.NamedInfo(nsName, logger, "ceph nfs service running at %s:%d", svc.Spec.ClusterIP, nfsPort)
log.NamedInfo(nsName, logger, "ceph nfs service running at %s:%d", svc.Spec.ClusterIP, nfs.GetPort())
return nil
}
@@ -262,10 +258,12 @@ func (r *ReconcileCephNFS) daemonContainer(nfs *cephv1.CephNFS, cfg daemonConfig
func (r *ReconcileCephNFS) defaultGaneshaLivenessProbe(nfs *cephv1.CephNFS) *v1.Probe {
failureThreshold := int32(10)
nfsPort := nfs.GetPort()
cephVersionWithRpcinfo := version.CephVersion{Major: 18, Minor: 2, Extra: 1}
if r.clusterInfo.CephVersion.IsAtLeast(cephVersionWithRpcinfo) {
// liveness-probe using rpcinfo utility
return controller.GenerateLivenessProbeViaRpcinfo(nfsPort, failureThreshold)
//nolint:gosec // G115: port is CRD-validated to 1-65535
return controller.GenerateLivenessProbeViaRpcinfo(uint16(nfsPort), failureThreshold)
}
// liveness-probe using K8s builtin TCP-socket action
return controller.GenerateLivenessProbeTcpPort(nfsPort, failureThreshold)