mirror of https://github.com/containers/podman.git
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>
This commit is contained in:
parent
57f778aed9
commit
e2aef6341d
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
// Mount storage if not mounted
|
||||
if err := c.mountStorage(); err != nil {
|
||||
return err
|
||||
}
|
||||
var (
|
||||
wg sync.WaitGroup
|
||||
netNS ns.NetNS
|
||||
networkStatus []*cnitypes.Result
|
||||
createNetNSErr, mountStorageErr error
|
||||
mountPoint string
|
||||
saveNetworkStatus bool
|
||||
)
|
||||
|
||||
// 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.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
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
mountPoint, mountStorageErr = c.mountStorage()
|
||||
}()
|
||||
|
||||
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() {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue