diff options
author | baude <bbaude@redhat.com> | 2018-10-17 13:43:36 -0500 |
---|---|---|
committer | baude <bbaude@redhat.com> | 2018-10-25 06:34:23 -0500 |
commit | e2aef6341de2d371cec3e6085cb539dfadede8db (patch) | |
tree | d114122189efbd55001831ca9065dc8bb008e39f | |
parent | 57f778aed93efc0961b1335bcd07c3c82a11da0a (diff) | |
download | podman-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.go | 34 | ||||
-rw-r--r-- | libpod/container_internal_linux.go | 66 | ||||
-rw-r--r-- | libpod/networking_linux.go | 30 |
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 |