Run two containers

This change will allow the gVisor sandbox to run multiple containers.
- Added new functions to validate the SentryMultiContainerSpec and the
container mounts.
- Changes to set the target path in container mounts for eg: root target will
be "/container0" and the submounts target will be "/container0/dev".. etc in
multi-container mode.
- Added new fields in the protos: container name in ContainerSpec and
MultiContainerConfig in SentryConfig.
- Updated the sentry to create the mount namespaces for all the containers
during the sentry start as we have all the container mount configs. These
mount namespaces are passed to the control server in a map with the container
name as the key.
- Updated changes in StartContainer():
    - Use ContainerSpec instead of SandboxRunSpec.
    - No longer create the mount namespaces here and use the ones created by
      the sentry.
- Added test to run two containers in multi-container mode using the
SentryMultiContainerSpec.

PiperOrigin-RevId: 454649646
This commit is contained in:
Nayana Bidari
2022-06-13 10:59:24 -07:00
committed by gVisor bot
parent 0301bb07ef
commit 2610918ed4
+32 -10
View File
@@ -26,6 +26,7 @@ import (
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
"gvisor.dev/gvisor/pkg/sentry/limits"
"gvisor.dev/gvisor/pkg/sentry/vfs"
"gvisor.dev/gvisor/pkg/sync"
"gvisor.dev/gvisor/pkg/urpc"
)
@@ -34,13 +35,19 @@ type Lifecycle struct {
// Kernel is the kernel where the tasks belong to.
Kernel *kernel.Kernel
// Sends a message to the sentry that the task has been started.
// StartedCh is the channel used to send a message to the sentry that
// all the containers in the sandbox have been started.
StartedCh chan struct{}
// TODO(b/202052732): Root mount namespace. When running multiple
// containers, create the mount namespace using the mount spec in
// the StartContainerArgs.
MountNamespaceVFS2 *vfs.MountNamespace
// mu protects the fields below.
mu sync.RWMutex
// containersStarted is the number of containers started in the sandbox.
containersStarted int32
// MountNamespacesMap is a map of container id/names and the mount
// namespaces.
MountNamespacesMap map[string]*vfs.MountNamespace
}
// StartContainerArgs is the set of arguments to start a container.
@@ -127,12 +134,22 @@ func (l *Lifecycle) StartContainer(args *StartContainerArgs, _ *uint32) error {
AbstractSocketNamespace: l.Kernel.RootAbstractSocketNamespace(),
ContainerID: args.ContainerID,
PIDNamespace: l.Kernel.RootPIDNamespace(),
MountNamespaceVFS2: l.MountNamespaceVFS2,
}
ctx := initArgs.NewContext(l.Kernel)
defer fdTable.DecRef(ctx)
// VFS2 is supported in multi-container mode by default.
l.mu.RLock()
mntns, ok := l.MountNamespacesMap[initArgs.ContainerID]
if !ok {
l.mu.RUnlock()
return fmt.Errorf("mount namespace is nil for %s", initArgs.ContainerID)
}
initArgs.MountNamespaceVFS2 = mntns
l.mu.RUnlock()
initArgs.MountNamespaceVFS2.IncRef()
resolved, err := user.ResolveExecutablePath(ctx, &initArgs)
if err != nil {
return err
@@ -154,12 +171,17 @@ func (l *Lifecycle) StartContainer(args *StartContainerArgs, _ *uint32) error {
return err
}
l.mu.Lock()
numContainers := int32(len(l.MountNamespacesMap))
// Start the newly created process.
l.Kernel.StartProcess(tg)
log.Infof("Started the new container")
l.StartedCh <- struct{}{}
log.Infof("Started the new container %v ", l.containersStarted)
l.containersStarted++
if numContainers == l.containersStarted {
l.StartedCh <- struct{}{}
}
l.mu.Unlock()
return nil
}