summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbaude <bbaude@redhat.com>2018-10-17 13:43:36 -0500
committerbaude <bbaude@redhat.com>2018-10-25 06:34:23 -0500
commite2aef6341de2d371cec3e6085cb539dfadede8db (patch)
treed114122189efbd55001831ca9065dc8bb008e39f
parent57f778aed93efc0961b1335bcd07c3c82a11da0a (diff)
downloadpodman-e2aef6341de2d371cec3e6085cb539dfadede8db.tar.gz
podman-e2aef6341de2d371cec3e6085cb539dfadede8db.tar.bz2
podman-e2aef6341de2d371cec3e6085cb539dfadede8db.zip
run prepare in parallel
run prepare() -- which consists of creating a network namespace and mounting the container image is now run in parallel. This saves 25-40ms. Signed-off-by: baude <bbaude@redhat.com>
-rw-r--r--libpod/container_internal.go34
-rw-r--r--libpod/container_internal_linux.go66
-rw-r--r--libpod/networking_linux.go30
3 files changed, 79 insertions, 51 deletions
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index cb6b940fd..2af216358 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -750,30 +750,31 @@ func (c *Container) restartWithTimeout(ctx context.Context, timeout uint) (err e
// TODO: Add ability to override mount label so we can use this for Mount() too
// TODO: Can we use this for export? Copying SHM into the export might not be
// good
-func (c *Container) mountStorage() (err error) {
+func (c *Container) mountStorage() (string, error) {
+ var err error
// Container already mounted, nothing to do
if c.state.Mounted {
- return nil
+ return c.state.Mountpoint, nil
}
if !rootless.IsRootless() {
// TODO: generalize this mount code so it will mount every mount in ctr.config.Mounts
mounted, err := mount.Mounted(c.config.ShmDir)
if err != nil {
- return errors.Wrapf(err, "unable to determine if %q is mounted", c.config.ShmDir)
+ return "", errors.Wrapf(err, "unable to determine if %q is mounted", c.config.ShmDir)
}
if err := os.Chown(c.config.ShmDir, c.RootUID(), c.RootGID()); err != nil {
- return errors.Wrapf(err, "failed to chown %s", c.config.ShmDir)
+ return "", errors.Wrapf(err, "failed to chown %s", c.config.ShmDir)
}
if !mounted {
shmOptions := fmt.Sprintf("mode=1777,size=%d", c.config.ShmSize)
if err := c.mountSHM(shmOptions); err != nil {
- return err
+ return "", err
}
if err := os.Chown(c.config.ShmDir, c.RootUID(), c.RootGID()); err != nil {
- return errors.Wrapf(err, "failed to chown %s", c.config.ShmDir)
+ return "", errors.Wrapf(err, "failed to chown %s", c.config.ShmDir)
}
}
}
@@ -782,28 +783,11 @@ func (c *Container) mountStorage() (err error) {
if mountPoint == "" {
mountPoint, err = c.mount()
if err != nil {
- return err
+ return "", err
}
}
- c.state.Mounted = true
- c.state.Mountpoint = mountPoint
- if c.state.UserNSRoot == "" {
- c.state.RealMountpoint = c.state.Mountpoint
- } else {
- c.state.RealMountpoint = filepath.Join(c.state.UserNSRoot, "mountpoint")
- }
-
- logrus.Debugf("Created root filesystem for container %s at %s", c.ID(), c.state.Mountpoint)
-
- defer func() {
- if err != nil {
- if err2 := c.cleanupStorage(); err2 != nil {
- logrus.Errorf("Error unmounting storage for container %s: %v", c.ID(), err)
- }
- }
- }()
- return c.save()
+ return mountPoint, nil
}
// cleanupStorage unmounts and cleans up the container's root filesystem
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index b25645e5c..94704fc04 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -12,10 +12,12 @@ import (
"path"
"path/filepath"
"strings"
+ "sync"
"syscall"
"time"
cnitypes "github.com/containernetworking/cni/pkg/types/current"
+ "github.com/containernetworking/plugins/pkg/ns"
crioAnnotations "github.com/containers/libpod/pkg/annotations"
"github.com/containers/libpod/pkg/chrootuser"
"github.com/containers/libpod/pkg/criu"
@@ -49,24 +51,61 @@ func (c *Container) unmountSHM(mount string) error {
// prepare mounts the container and sets up other required resources like net
// namespaces
func (c *Container) prepare() (err error) {
+ var (
+ wg sync.WaitGroup
+ netNS ns.NetNS
+ networkStatus []*cnitypes.Result
+ createNetNSErr, mountStorageErr error
+ mountPoint string
+ saveNetworkStatus bool
+ )
+
+ wg.Add(2)
+
+ go func() {
+ defer wg.Done()
+ // Set up network namespace if not already set up
+ if c.config.CreateNetNS && c.state.NetNS == nil && !c.config.PostConfigureNetNS {
+ saveNetworkStatus = true
+ netNS, networkStatus, createNetNSErr = c.runtime.createNetNS(c)
+ }
+ }()
// Mount storage if not mounted
- if err := c.mountStorage(); err != nil {
- return err
- }
+ go func() {
+ defer wg.Done()
+ mountPoint, mountStorageErr = c.mountStorage()
+ }()
- // Set up network namespace if not already set up
- if c.config.CreateNetNS && c.state.NetNS == nil && !c.config.PostConfigureNetNS {
- if err := c.runtime.createNetNS(c); err != nil {
- // Tear down storage before exiting to make sure we
- // don't leak mounts
- if err2 := c.cleanupStorage(); err2 != nil {
- logrus.Errorf("Error cleaning up storage for container %s: %v", c.ID(), err2)
- }
- return err
+ wg.Wait()
+ if createNetNSErr != nil {
+ if mountStorageErr != nil {
+ logrus.Error(createNetNSErr)
+ return mountStorageErr
}
+ return createNetNSErr
+ }
+ if mountStorageErr != nil {
+ return mountStorageErr
}
- return nil
+ // Assign NetNS attributes to container
+ if saveNetworkStatus {
+ c.state.NetNS = netNS
+ c.state.NetworkStatus = networkStatus
+ }
+
+ // Finish up mountStorage
+ c.state.Mounted = true
+ c.state.Mountpoint = mountPoint
+ if c.state.UserNSRoot == "" {
+ c.state.RealMountpoint = c.state.Mountpoint
+ } else {
+ c.state.RealMountpoint = filepath.Join(c.state.UserNSRoot, "mountpoint")
+ }
+
+ logrus.Debugf("Created root filesystem for container %s at %s", c.ID(), c.state.Mountpoint)
+ // Save the container
+ return c.save()
}
// cleanupNetwork unmounts and cleans up the container's network
@@ -104,7 +143,6 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
g.AddOrReplaceLinuxNamespace(spec.NetworkNamespace, c.state.NetNS.Path())
}
}
-
// Check if the spec file mounts contain the label Relabel flags z or Z.
// If they do, relabel the source directory and then remove the option.
for _, m := range g.Mounts() {
diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go
index acb4e2a90..0d9ec2809 100644
--- a/libpod/networking_linux.go
+++ b/libpod/networking_linux.go
@@ -48,12 +48,12 @@ func (r *Runtime) getPodNetwork(id, name, nsPath string, networks []string, port
}
// Create and configure a new network namespace for a container
-func (r *Runtime) configureNetNS(ctr *Container, ctrNS ns.NetNS) (err error) {
+func (r *Runtime) configureNetNS(ctr *Container, ctrNS ns.NetNS) ([]*cnitypes.Result, error) {
podNetwork := r.getPodNetwork(ctr.ID(), ctr.Name(), ctrNS.Path(), ctr.config.Networks, ctr.config.PortMappings, ctr.config.StaticIP)
results, err := r.netPlugin.SetUpPod(podNetwork)
if err != nil {
- return errors.Wrapf(err, "error configuring network namespace for container %s", ctr.ID())
+ return nil, errors.Wrapf(err, "error configuring network namespace for container %s", ctr.ID())
}
defer func() {
if err != nil {
@@ -63,15 +63,14 @@ func (r *Runtime) configureNetNS(ctr *Container, ctrNS ns.NetNS) (err error) {
}
}()
- ctr.state.NetNS = ctrNS
- ctr.state.NetworkStatus = make([]*cnitypes.Result, 0)
+ networkStatus := make([]*cnitypes.Result, 1)
for idx, r := range results {
logrus.Debugf("[%d] CNI result: %v", idx, r.String())
resultCurrent, err := cnitypes.GetResult(r)
if err != nil {
- return errors.Wrapf(err, "error parsing CNI plugin result %q: %v", r.String(), err)
+ return nil, errors.Wrapf(err, "error parsing CNI plugin result %q: %v", r.String(), err)
}
- ctr.state.NetworkStatus = append(ctr.state.NetworkStatus, resultCurrent)
+ networkStatus = append(ctr.state.NetworkStatus, resultCurrent)
}
// Add firewall rules to ensure the container has network access.
@@ -82,18 +81,18 @@ func (r *Runtime) configureNetNS(ctr *Container, ctrNS ns.NetNS) (err error) {
PrevResult: netStatus,
}
if err := r.firewallBackend.Add(firewallConf); err != nil {
- return errors.Wrapf(err, "error adding firewall rules for container %s", ctr.ID())
+ return nil, errors.Wrapf(err, "error adding firewall rules for container %s", ctr.ID())
}
}
- return nil
+ return networkStatus, nil
}
// Create and configure a new network namespace for a container
-func (r *Runtime) createNetNS(ctr *Container) (err error) {
+func (r *Runtime) createNetNS(ctr *Container) (ns.NetNS, []*cnitypes.Result, error) {
ctrNS, err := netns.NewNS()
if err != nil {
- return errors.Wrapf(err, "error creating network namespace for container %s", ctr.ID())
+ return nil, nil, errors.Wrapf(err, "error creating network namespace for container %s", ctr.ID())
}
defer func() {
if err != nil {
@@ -104,7 +103,9 @@ func (r *Runtime) createNetNS(ctr *Container) (err error) {
}()
logrus.Debugf("Made network namespace at %s for container %s", ctrNS.Path(), ctr.ID())
- return r.configureNetNS(ctr, ctrNS)
+
+ networkStatus, err := r.configureNetNS(ctr, ctrNS)
+ return ctrNS, networkStatus, err
}
// Configure the network namespace for a rootless container
@@ -173,7 +174,12 @@ func (r *Runtime) setupNetNS(ctr *Container) (err error) {
if err != nil {
return err
}
- return r.configureNetNS(ctr, netNS)
+ networkStatus, err := r.configureNetNS(ctr, netNS)
+
+ // Assign NetNS attributes to container
+ ctr.state.NetNS = netNS
+ ctr.state.NetworkStatus = networkStatus
+ return err
}
// Join an existing network namespace