NRI: instantiate and start/stop NRI adaptation

Signed-off-by: Rob Murray <rob.murray@docker.com>
This commit is contained in:
Rob Murray
2025-12-02 17:26:12 +00:00
parent 4941b36883
commit 282868dabf
4 changed files with 151 additions and 1 deletions

View File

@@ -37,6 +37,7 @@ import (
networktypes "github.com/moby/moby/api/types/network" networktypes "github.com/moby/moby/api/types/network"
registrytypes "github.com/moby/moby/api/types/registry" registrytypes "github.com/moby/moby/api/types/registry"
"github.com/moby/moby/api/types/swarm" "github.com/moby/moby/api/types/swarm"
"github.com/moby/moby/v2/daemon/internal/nri"
"github.com/moby/sys/user" "github.com/moby/sys/user"
"github.com/moby/sys/userns" "github.com/moby/sys/userns"
"github.com/pkg/errors" "github.com/pkg/errors"
@@ -116,6 +117,7 @@ type Daemon struct {
shutdown bool shutdown bool
idMapping user.IdentityMapping idMapping user.IdentityMapping
PluginStore *plugin.Store // TODO: remove PluginStore *plugin.Store // TODO: remove
nri *nri.NRI
pluginManager *plugin.Manager pluginManager *plugin.Manager
linkIndex *linkIndex linkIndex *linkIndex
containerdClient *containerd.Client containerdClient *containerd.Client
@@ -1096,6 +1098,14 @@ func NewDaemon(ctx context.Context, config *config.Config, pluginStore *plugin.S
return nil, err return nil, err
} }
d.nri, err = nri.NewNRI(ctx, nri.Config{
DaemonConfig: config.NRIOpts,
ContainerLister: d.containers,
})
if err != nil {
return nil, err
}
driverName := getDriverOverride(ctx, cfgStore.GraphDriver, imgStoreChoice) driverName := getDriverOverride(ctx, cfgStore.GraphDriver, imgStoreChoice)
var migrationConfig migration.Config var migrationConfig migration.Config
@@ -1486,6 +1496,10 @@ func (daemon *Daemon) Shutdown(ctx context.Context) error {
// Shutdown plugins after containers and layerstore. Don't change the order. // Shutdown plugins after containers and layerstore. Don't change the order.
daemon.pluginShutdown() daemon.pluginShutdown()
if daemon.nri != nil {
daemon.nri.Shutdown(ctx)
}
// trigger libnetwork Stop only if it's initialized // trigger libnetwork Stop only if it's initialized
if daemon.netController != nil { if daemon.netController != nil {
daemon.netController.Stop() daemon.netController.Stop()

View File

@@ -1,7 +1,128 @@
package nri package nri
import ( import (
"context"
"errors"
"fmt"
"path/filepath"
"sync"
"github.com/containerd/log"
"github.com/containerd/nri/pkg/adaptation" "github.com/containerd/nri/pkg/adaptation"
"github.com/moby/moby/v2/daemon/container"
"github.com/moby/moby/v2/daemon/internal/rootless"
"github.com/moby/moby/v2/daemon/pkg/opts"
"github.com/moby/moby/v2/dockerversion"
"github.com/moby/moby/v2/pkg/homedir"
) )
var _ = *adaptation.Adaptation const (
// defaultPluginSubdir is the default location for NRI plugins under libexec,
// which is in a different location for rootful/rootless Docker.
defaultPluginSubdir = "docker/nri-plugins"
// defaultPluginConfigSubdir is the default location for NRI plugin config under etc,
// which is in a different location for rootful/rootless Docker.
defaultPluginConfigSubdir = "docker/nri/conf.d"
)
type NRI struct {
cfg Config
// mu protects nri - read lock for container operations, write lock for sync and shutdown.
mu sync.RWMutex
nri *adaptation.Adaptation
}
type ContainerLister interface {
List() []*container.Container
}
type Config struct {
DaemonConfig opts.NRIOpts
ContainerLister ContainerLister
}
func NewNRI(ctx context.Context, cfg Config) (*NRI, error) {
n := &NRI{cfg: cfg}
if !n.cfg.DaemonConfig.Enable {
log.G(ctx).Info("NRI is disabled")
return n, nil
}
if err := setDefaultPaths(&n.cfg.DaemonConfig); err != nil {
return nil, err
}
log.G(ctx).WithFields(log.Fields{
"pluginPath": n.cfg.DaemonConfig.PluginPath,
"pluginConfigPath": n.cfg.DaemonConfig.PluginConfigPath,
"socketPath": n.cfg.DaemonConfig.SocketPath,
}).Info("Starting NRI")
var err error
n.nri, err = adaptation.New("docker", dockerversion.Version, n.syncFn, n.updateFn, nriOptions(n.cfg.DaemonConfig)...)
if err != nil {
return nil, err
}
if err := n.nri.Start(); err != nil {
return nil, err
}
return n, nil
}
func (n *NRI) Shutdown(ctx context.Context) {
n.mu.Lock()
defer n.mu.Unlock()
if n.nri == nil {
return
}
log.G(ctx).Info("Shutting down NRI")
n.nri.Stop()
n.nri = nil
}
func (n *NRI) syncFn(ctx context.Context, syncCB adaptation.SyncCB) error {
return nil
}
func (n *NRI) updateFn(context.Context, []*adaptation.ContainerUpdate) ([]*adaptation.ContainerUpdate, error) {
return nil, errors.New("not implemented")
}
func setDefaultPaths(cfg *opts.NRIOpts) error {
if cfg.PluginPath != "" && cfg.PluginConfigPath != "" {
return nil
}
libexecDir := "/usr/libexec"
etcDir := "/etc"
if rootless.RunningWithRootlessKit() {
var err error
libexecDir, err = homedir.GetLibexecHome()
if err != nil {
return fmt.Errorf("configuring NRI: %w", err)
}
etcDir, err = homedir.GetConfigHome()
if err != nil {
return fmt.Errorf("configuring NRI: %w", err)
}
}
if cfg.PluginPath == "" {
cfg.PluginPath = filepath.Join(libexecDir, defaultPluginSubdir)
}
if cfg.PluginConfigPath == "" {
cfg.PluginConfigPath = filepath.Join(etcDir, defaultPluginConfigSubdir)
}
return nil
}
func nriOptions(cfg opts.NRIOpts) []adaptation.Option {
res := []adaptation.Option{
adaptation.WithPluginPath(cfg.PluginPath),
adaptation.WithPluginConfigPath(cfg.PluginConfigPath),
}
if cfg.SocketPath == "" {
res = append(res, adaptation.WithDisabledExternalConnections())
} else {
res = append(res, adaptation.WithSocketPath(cfg.SocketPath))
}
return res
}

View File

@@ -103,3 +103,13 @@ func GetLibHome() (string, error) {
} }
return filepath.Join(home, ".local/lib"), nil return filepath.Join(home, ".local/lib"), nil
} }
// GetLibexecHome returns $HOME/.local/libexec
// If HOME is not set, getpwent(3) is consulted to determine the users home directory.
func GetLibexecHome() (string, error) {
home := Get()
if home == "" {
return "", errors.New("could not get HOME")
}
return filepath.Join(home, ".local/libexec"), nil
}

View File

@@ -30,3 +30,8 @@ func GetConfigHome() (string, error) {
func GetLibHome() (string, error) { func GetLibHome() (string, error) {
return "", errors.New("homedir.GetLibHome() is not supported on this system") return "", errors.New("homedir.GetLibHome() is not supported on this system")
} }
// GetLibexecHome is unsupported on non-linux system.
func GetLibexecHome() (string, error) {
return "", errors.New("homedir.GetLibexecHome() is not supported on this system")
}