diff --git a/src/apiserver/main.go b/src/apiserver/main.go index 5d3d2ca..2be3f8a 100644 --- a/src/apiserver/main.go +++ b/src/apiserver/main.go @@ -17,13 +17,43 @@ limitations under the License. package main import ( + "fmt" "os" + "syscall" "github.com/alibaba/higress/api-server/pkg/cmd/server" genericapiserver "k8s.io/apiserver/pkg/server" "k8s.io/component-base/cli" ) +func init() { + // Increase file descriptor limit early to avoid "too many open files" errors + var rLimit syscall.Rlimit + if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit); err != nil { + fmt.Fprintf(os.Stderr, "Warning: failed to get rlimit: %v\n", err) + return + } + + fmt.Printf("Current file descriptor limit: soft=%d hard=%d\n", rLimit.Cur, rLimit.Max) + + // Try to set soft limit to 65535 + targetLimit := uint64(65535) + if rLimit.Cur < targetLimit { + rLimit.Cur = targetLimit + // If hard limit is less than target, try to increase it (may require root) + if rLimit.Max < targetLimit { + rLimit.Max = targetLimit + } + + if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit); err != nil { + fmt.Fprintf(os.Stderr, "Warning: failed to set rlimit to %d: %v\n", targetLimit, err) + return + } + + fmt.Printf("Updated file descriptor limit: soft=%d hard=%d\n", rLimit.Cur, rLimit.Max) + } +} + func main() { stopCh := genericapiserver.SetupSignalHandler() options := server.NewHigressServerOptions(os.Stdout, os.Stderr) diff --git a/src/apiserver/pkg/apiserver/apiserver.go b/src/apiserver/pkg/apiserver/apiserver.go index 77b8e44..24557e8 100644 --- a/src/apiserver/pkg/apiserver/apiserver.go +++ b/src/apiserver/pkg/apiserver/apiserver.go @@ -19,7 +19,6 @@ package apiserver import ( "fmt" - "github.com/fsnotify/fsnotify" istiov1alpha3 "istio.io/client-go/pkg/apis/networking/v1alpha3" admregv1 "k8s.io/api/admissionregistration/v1" authzv1 "k8s.io/api/authorization/v1" @@ -170,15 +169,6 @@ func (c completedConfig) New() (*HigressServer, error) { } } - // Create shared watcher for file storage mode to avoid "too many open files" - var sharedWatcher *fsnotify.Watcher - if storageMode == options.Storage_File { - sharedWatcher, err = fsnotify.NewWatcher() - if err != nil { - return nil, fmt.Errorf("failed to create shared file watcher: %v", err) - } - } - storageCreateFunc := func( groupResource schema.GroupResource, runtimeCodec runtime.Codec, @@ -195,7 +185,7 @@ func (c completedConfig) New() (*HigressServer, error) { switch storageMode { case options.Storage_File: runtimeCodec = codec.NewFlatAwareCodec(groupResource, runtimeCodec) - return registry.NewFileREST(groupResource, runtimeCodec, storageOptions.FileOptions.RootDir, extension, isNamespaced, singularName, newFunc, newListFunc, attrFunc, sharedWatcher) + return registry.NewFileREST(groupResource, runtimeCodec, storageOptions.FileOptions.RootDir, extension, isNamespaced, singularName, newFunc, newListFunc, attrFunc) case options.Storage_Nacos: var encryptionKey []byte = nil if sensitive { diff --git a/src/apiserver/pkg/registry/file_rest.go b/src/apiserver/pkg/registry/file_rest.go index 35b1e23..b3cd81d 100644 --- a/src/apiserver/pkg/registry/file_rest.go +++ b/src/apiserver/pkg/registry/file_rest.go @@ -54,7 +54,6 @@ func NewFileREST( newFunc func() runtime.Object, newListFunc func() runtime.Object, attrFunc storage.AttrFunc, - sharedWatcher *fsnotify.Watcher, ) (REST, error) { if attrFunc == nil { if isNamespaced { @@ -63,6 +62,10 @@ func NewFileREST( attrFunc = storage.DefaultClusterScopedAttr } } + watcher, err := fsnotify.NewWatcher() + if err != nil { + return nil, fmt.Errorf("failed to create file watcher for %s: %v", groupResource.Resource, err) + } // file REST f := &fileREST{ TableConvertor: rest.NewDefaultTableConvertor(groupResource), @@ -75,7 +78,7 @@ func NewFileREST( newFunc: newFunc, newListFunc: newListFunc, attrFunc: attrFunc, - dirWatcher: sharedWatcher, + dirWatcher: watcher, fileWatchers: make(map[string]*fileWatch, 10), } if err := f.startDirWatcher(); err != nil { @@ -111,8 +114,9 @@ func (f *fileREST) GetSingularName() string { } func (f *fileREST) Destroy() { - // Don't close the watcher as it's shared across all fileREST instances - // The watcher will be closed when the server shuts down + if f.dirWatcher != nil { + _ = f.dirWatcher.Close() + } } func (f *fileREST) startDirWatcher() error {