From ef985f8628344d803d511adf12e5af7cf4606aef Mon Sep 17 00:00:00 2001 From: Akihiro Suda Date: Sun, 10 May 2026 13:54:27 +0900 Subject: [PATCH] server: tolerate failed gRPC plugins when starting listeners The grpc, grpc-tcp, and ttrpc server plugins enumerated their services through ic.GetByType, which short-circuits on the first plugin whose Instance() returned an error. A single failed gRPC plugin (e.g. CRI under rootless, which cannot watch /etc/cni/net.d) therefore prevented the server plugins from initialising, leaving /run/containerd/containerd.sock uncreated. Iterate the plugin set directly and skip plugins that failed to initialise, restoring the pre-c15ec2485 behaviour where the listener is still created and only the failed services are missing. Fixes: c15ec2485 ("Add server plugins for grpc and ttrpc") Fixes: https://github.com/containerd/containerd/issues/13362 Co-Authored-By: Claude Opus 4.7 (1M context) Signed-off-by: Akihiro Suda --- plugins/server/grpc/plugin.go | 37 ++++++++++++++++++++++------------ plugins/server/ttrpc/plugin.go | 30 +++++++++++---------------- 2 files changed, 36 insertions(+), 31 deletions(-) diff --git a/plugins/server/grpc/plugin.go b/plugins/server/grpc/plugin.go index 1ef44badb3..6c5b1032e5 100644 --- a/plugins/server/grpc/plugin.go +++ b/plugins/server/grpc/plugin.go @@ -20,7 +20,6 @@ import ( "context" "crypto/tls" "crypto/x509" - "errors" "fmt" "net" "os" @@ -112,12 +111,19 @@ func init() { } s := grpc.NewServer(serverOpts...) - ps, err := ic.GetByType(plugins.GRPCPlugin) // ensure grpc plugin is initialized - if err != nil && !errors.Is(err, plugin.ErrPluginNotFound) { - return nil, err - } - for _, p := range ps { - if gs, ok := p.(grpcService); ok { + // Iterate plugins directly rather than using GetByType, which + // short-circuits on the first plugin that failed to initialize. + // Plugins that failed (e.g. CRI under rootless) have already been + // logged and should not prevent the GRPC server from starting. + for _, p := range ic.Plugins().GetAll() { + if p.Registration.Type != plugins.GRPCPlugin { + continue + } + instance, err := p.Instance() + if err != nil { + continue + } + if gs, ok := instance.(grpcService); ok { if err := gs.Register(s); err != nil { return nil, fmt.Errorf("failed to register grpc service: %w", err) } @@ -218,13 +224,18 @@ func init() { } s := grpc.NewServer(serverOpts...) - ps, err := ic.GetByType(plugins.GRPCPlugin) // ensure grpc plugin is initialized - if err != nil && !errors.Is(err, plugin.ErrPluginNotFound) { - return nil, err - } + // Iterate plugins directly rather than using GetByType, which + // short-circuits on the first plugin that failed to initialize. var hasService bool - for _, p := range ps { - if gs, ok := p.(tcpService); ok { + for _, p := range ic.Plugins().GetAll() { + if p.Registration.Type != plugins.GRPCPlugin { + continue + } + instance, err := p.Instance() + if err != nil { + continue + } + if gs, ok := instance.(tcpService); ok { if err := gs.RegisterTCP(s); err != nil { return nil, fmt.Errorf("failed to register grpc service: %w", err) } diff --git a/plugins/server/ttrpc/plugin.go b/plugins/server/ttrpc/plugin.go index fc5f5a44d9..921538bb19 100644 --- a/plugins/server/ttrpc/plugin.go +++ b/plugins/server/ttrpc/plugin.go @@ -18,7 +18,6 @@ package ttrpc import ( "context" - "errors" "fmt" "net" "os" @@ -75,25 +74,20 @@ func init() { type ttrpcService interface { RegisterTTRPC(*ttrpc.Server) error } + // Iterate plugins directly rather than using GetByType, which + // short-circuits on the first plugin that failed to initialize. + // Plugins that failed (e.g. CRI under rootless) have already been + // logged and should not prevent the TTRPC server from starting. var hasService bool - ps, err := ic.GetByType(plugins.TTRPCPlugin) // ensure grpc plugin is initialized - if err != nil && !errors.Is(err, plugin.ErrPluginNotFound) { - return nil, err - } - for _, p := range ps { - if gs, ok := p.(ttrpcService); ok { - if err := gs.RegisterTTRPC(s); err != nil { - return nil, fmt.Errorf("failed to register ttrpc service: %w", err) - } - hasService = true + for _, p := range ic.Plugins().GetAll() { + if p.Registration.Type != plugins.TTRPCPlugin && p.Registration.Type != plugins.GRPCPlugin { + continue } - } - ps, err = ic.GetByType(plugins.GRPCPlugin) // ensure grpc plugin is initialized - if err != nil && !errors.Is(err, plugin.ErrPluginNotFound) { - return nil, err - } - for _, p := range ps { - if gs, ok := p.(ttrpcService); ok { + instance, err := p.Instance() + if err != nil { + continue + } + if gs, ok := instance.(ttrpcService); ok { if err := gs.RegisterTTRPC(s); err != nil { return nil, fmt.Errorf("failed to register ttrpc service: %w", err) }