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) <noreply@anthropic.com>
Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
This commit is contained in:
Akihiro Suda
2026-05-10 13:54:27 +09:00
parent 2976f38ccb
commit ef985f8628
2 changed files with 36 additions and 31 deletions

View File

@@ -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)
}

View File

@@ -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)
}