4bafaa00aa
The containerd client is very chatty at the best of times. Because the libcontained API is stateless and references containers and processes by string ID for every method call, the implementation is essentially forced to use the containerd client in a way which amplifies the number of redundant RPCs invoked to perform any operation. The libcontainerd remote implementation has to reload the containerd container, task and/or process metadata for nearly every operation. This in turn amplifies the number of context switches between dockerd and containerd to perform any container operation or handle a containerd event, increasing the load on the system which could otherwise be allocated to workloads. Overhaul the libcontainerd interface to reduce the impedance mismatch with the containerd client so that the containerd client can be used more efficiently. Split the API out into container, task and process interfaces which the consumer is expected to retain so that libcontainerd can retain state---especially the analogous containerd client objects---without having to manage any state-store inside the libcontainerd client. Signed-off-by: Cory Snider <csnider@mirantis.com>
123 lines
3.4 KiB
Go
123 lines
3.4 KiB
Go
package remote // import "github.com/docker/docker/libcontainerd/remote"
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/containerd/containerd"
|
|
"github.com/containerd/containerd/cio"
|
|
"github.com/containerd/containerd/containers"
|
|
libcontainerdtypes "github.com/docker/docker/libcontainerd/types"
|
|
"github.com/docker/docker/pkg/idtools"
|
|
specs "github.com/opencontainers/runtime-spec/specs-go"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
func summaryFromInterface(i interface{}) (*libcontainerdtypes.Summary, error) {
|
|
return &libcontainerdtypes.Summary{}, nil
|
|
}
|
|
|
|
func (t *task) UpdateResources(ctx context.Context, resources *libcontainerdtypes.Resources) error {
|
|
// go doesn't like the alias in 1.8, this means this need to be
|
|
// platform specific
|
|
return t.Update(ctx, containerd.WithResources((*specs.LinuxResources)(resources)))
|
|
}
|
|
|
|
func hostIDFromMap(id uint32, mp []specs.LinuxIDMapping) int {
|
|
for _, m := range mp {
|
|
if id >= m.ContainerID && id <= m.ContainerID+m.Size-1 {
|
|
return int(m.HostID + id - m.ContainerID)
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func getSpecUser(ociSpec *specs.Spec) (int, int) {
|
|
var (
|
|
uid int
|
|
gid int
|
|
)
|
|
|
|
for _, ns := range ociSpec.Linux.Namespaces {
|
|
if ns.Type == specs.UserNamespace {
|
|
uid = hostIDFromMap(0, ociSpec.Linux.UIDMappings)
|
|
gid = hostIDFromMap(0, ociSpec.Linux.GIDMappings)
|
|
break
|
|
}
|
|
}
|
|
|
|
return uid, gid
|
|
}
|
|
|
|
// WithBundle creates the bundle for the container
|
|
func WithBundle(bundleDir string, ociSpec *specs.Spec) containerd.NewContainerOpts {
|
|
return func(ctx context.Context, client *containerd.Client, c *containers.Container) error {
|
|
if c.Labels == nil {
|
|
c.Labels = make(map[string]string)
|
|
}
|
|
uid, gid := getSpecUser(ociSpec)
|
|
if uid == 0 && gid == 0 {
|
|
c.Labels[DockerContainerBundlePath] = bundleDir
|
|
return idtools.MkdirAllAndChownNew(bundleDir, 0755, idtools.Identity{UID: 0, GID: 0})
|
|
}
|
|
|
|
p := string(filepath.Separator)
|
|
components := strings.Split(bundleDir, string(filepath.Separator))
|
|
for _, d := range components[1:] {
|
|
p = filepath.Join(p, d)
|
|
fi, err := os.Stat(p)
|
|
if err != nil && !os.IsNotExist(err) {
|
|
return err
|
|
}
|
|
if os.IsNotExist(err) || fi.Mode()&1 == 0 {
|
|
p = fmt.Sprintf("%s.%d.%d", p, uid, gid)
|
|
if err := idtools.MkdirAndChown(p, 0700, idtools.Identity{UID: uid, GID: gid}); err != nil && !os.IsExist(err) {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
if c.Labels == nil {
|
|
c.Labels = make(map[string]string)
|
|
}
|
|
c.Labels[DockerContainerBundlePath] = p
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func withLogLevel(_ logrus.Level) containerd.NewTaskOpts {
|
|
panic("Not implemented")
|
|
}
|
|
|
|
func newFIFOSet(bundleDir, processID string, withStdin, withTerminal bool) *cio.FIFOSet {
|
|
config := cio.Config{
|
|
Terminal: withTerminal,
|
|
Stdout: filepath.Join(bundleDir, processID+"-stdout"),
|
|
}
|
|
paths := []string{config.Stdout}
|
|
|
|
if withStdin {
|
|
config.Stdin = filepath.Join(bundleDir, processID+"-stdin")
|
|
paths = append(paths, config.Stdin)
|
|
}
|
|
if !withTerminal {
|
|
config.Stderr = filepath.Join(bundleDir, processID+"-stderr")
|
|
paths = append(paths, config.Stderr)
|
|
}
|
|
closer := func() error {
|
|
for _, path := range paths {
|
|
if err := os.RemoveAll(path); err != nil {
|
|
logrus.Warnf("libcontainerd: failed to remove fifo %v: %v", path, err)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
return cio.NewFIFOSet(config, closer)
|
|
}
|
|
|
|
func (c *client) newDirectIO(ctx context.Context, fifos *cio.FIFOSet) (*cio.DirectIO, error) {
|
|
return cio.NewDirectIO(ctx, fifos)
|
|
}
|