From b5fdf90aee3aafb1dc852a37702c6432c1c1c2d5 Mon Sep 17 00:00:00 2001 From: Cory Snider Date: Wed, 2 Nov 2022 18:53:23 -0400 Subject: [PATCH] containerdexecutor: add network namespace callback In order to support identity mapping and user namespaces, the Moby project needs to defer the creation of a container's network namespace to the runtime and hook into the container lifecycle to configure the network namespace before the user binary is started. The standard way to do so is by configuring a `createRuntime` OCI lifecycle hook, in which the OCI runtime executes a specified process in the runtime environment after the container has been created and before it is started. In the case of Moby the network namespace needs to be configured from the daemon process, which necessitates that the hook process communicate with the daemon process. This is complicated and slow. All the hook process does is inform the daemon of the container's PID and wait until the daemon has finished applying the network namespace configuration. There is an alternative to the `createRuntime` OCI hook which containerd clients can take advantage of. The `container.NewTask` method is directly analogous to the OCI create operation, and the `task.Start` method is directly analogous to the OCI start operation. Any operations performed between the `NewTask` and `Start` calls are therefore directly analogous to `createRuntime` OCI hooks, without needing to execute any external processes! Provide a mechanism for network.Namespace instances to register a callback function which can be used to configure a container's network namespace instead of, or in addition to, `createRuntime` OCI hooks. Signed-off-by: Cory Snider --- executor/containerdexecutor/executor.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/executor/containerdexecutor/executor.go b/executor/containerdexecutor/executor.go index 714daa421..fd752732f 100644 --- a/executor/containerdexecutor/executor.go +++ b/executor/containerdexecutor/executor.go @@ -45,6 +45,19 @@ type containerdExecutor struct { rootless bool } +// OnCreateRuntimer provides an alternative to OCI hooks for applying network +// configuration to a container. If the [network.Provider] returns a +// [network.Namespace] which also implements this interface, the containerd +// executor will run the callback at the appropriate point in the container +// lifecycle. +type OnCreateRuntimer interface { + // OnCreateRuntime is analogous to the createRuntime OCI hook. The + // function is called after the container is created, before the user + // process has been executed. The argument is the container PID in the + // runtime namespace. + OnCreateRuntime(pid uint32) error +} + // New creates a new executor backed by connection to containerd API func New(client *containerd.Client, root, cgroup string, networkProviders map[pb.NetMode]network.Provider, dnsConfig *oci.DNSConfig, apparmorProfile string, selinux bool, traceSocket string, rootless bool) executor.Executor { // clean up old hosts/resolv.conf file. ignore errors @@ -210,6 +223,12 @@ func (w *containerdExecutor) Run(ctx context.Context, id string, root executor.M } }() + if nn, ok := namespace.(OnCreateRuntimer); ok { + if err := nn.OnCreateRuntime(task.Pid()); err != nil { + return err + } + } + trace.SpanFromContext(ctx).AddEvent("Container created") err = w.runProcess(ctx, task, process.Resize, process.Signal, func() { startedOnce.Do(func() {