Merge pull request #4643 from dcantah/feedback-lcow-snapshotter

Optimize Windows and LCOW snapshotters to only create scratch layer on the final snapshot
This commit is contained in:
Michael Crosby 2020-12-01 10:38:02 -05:00 committed by GitHub
commit b9092fae15
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 82 additions and 56 deletions

View File

@ -123,7 +123,7 @@ func applyLayers(ctx context.Context, layers []Layer, chain []digest.Digest, sn
) )
for { for {
key = fmt.Sprintf("extract-%s %s", uniquePart(), chainID) key = fmt.Sprintf(snapshots.UnpackKeyFormat, uniquePart(), chainID)
// Prepare snapshot with from parent, label as root // Prepare snapshot with from parent, label as root
mounts, err = sn.Prepare(ctx, key, parent.String(), opts...) mounts, err = sn.Prepare(ctx, key, parent.String(), opts...)

View File

@ -330,37 +330,44 @@ func (s *snapshotter) createSnapshot(ctx context.Context, kind snapshots.Kind, k
for _, o := range opts { for _, o := range opts {
o(&snapshotInfo) o(&snapshotInfo)
} }
// IO/disk space optimization
var sizeGB int
if sizeGBstr, ok := snapshotInfo.Labels[rootfsSizeLabel]; ok {
i32, err := strconv.ParseInt(sizeGBstr, 10, 32)
if err != nil {
return nil, errors.Wrapf(err, "failed to parse annotation %q=%q", rootfsSizeLabel, sizeGBstr)
}
sizeGB = int(i32)
}
scratchSource, err := s.openOrCreateScratch(ctx, sizeGB)
if err != nil {
return nil, err
}
defer scratchSource.Close()
// TODO: JTERRY75 - This has to be called sandbox.vhdx for the time
// being but it really is the scratch.vhdx. Using this naming convention
// for now but this is not the kubernetes sandbox.
// //
// Create the sandbox.vhdx for this snapshot from the cache. // We only need one sandbox.vhd for the container. Skip making one for this
destPath := filepath.Join(snDir, "sandbox.vhdx") // snapshot if this isn't the snapshot that just houses the final sandbox.vhd
dest, err := os.OpenFile(destPath, os.O_RDWR|os.O_CREATE, 0700) // that will be mounted as the containers scratch. Currently the key for a snapshot
if err != nil { // where a layer.vhd will be extracted to it will have the string `extract-` in it.
return nil, errors.Wrap(err, "failed to create sandbox.vhdx in snapshot") // If this is changed this will also need to be changed.
} //
defer dest.Close() // We save about 17MB per layer (if the default scratch vhd size of 20GB is used) and of
if _, err := io.Copy(dest, scratchSource); err != nil { // course the time to copy the vhd per snapshot.
dest.Close() if !strings.Contains(key, snapshots.UnpackKeyPrefix) {
os.Remove(destPath) var sizeGB int
return nil, errors.Wrap(err, "failed to copy cached scratch.vhdx to sandbox.vhdx in snapshot") if sizeGBstr, ok := snapshotInfo.Labels[rootfsSizeLabel]; ok {
i32, err := strconv.ParseInt(sizeGBstr, 10, 32)
if err != nil {
return nil, errors.Wrapf(err, "failed to parse label %q=%q", rootfsSizeLabel, sizeGBstr)
}
sizeGB = int(i32)
}
scratchSource, err := s.openOrCreateScratch(ctx, sizeGB)
if err != nil {
return nil, err
}
defer scratchSource.Close()
// Create the sandbox.vhdx for this snapshot from the cache.
destPath := filepath.Join(snDir, "sandbox.vhdx")
dest, err := os.OpenFile(destPath, os.O_RDWR|os.O_CREATE, 0700)
if err != nil {
return nil, errors.Wrap(err, "failed to create sandbox.vhdx in snapshot")
}
defer dest.Close()
if _, err := io.Copy(dest, scratchSource); err != nil {
dest.Close()
os.Remove(destPath)
return nil, errors.Wrap(err, "failed to copy cached scratch.vhdx to sandbox.vhdx in snapshot")
}
} }
} }

View File

@ -26,6 +26,10 @@ import (
) )
const ( const (
// UnpackKeyPrefix is the beginning of the key format used for snapshots that will have
// image content unpacked into them.
UnpackKeyPrefix = "extract"
UnpackKeyFormat = UnpackKeyPrefix + "-%s %s"
inheritedLabelsPrefix = "containerd.io/snapshot/" inheritedLabelsPrefix = "containerd.io/snapshot/"
labelSnapshotRef = "containerd.io/snapshot.ref" labelSnapshotRef = "containerd.io/snapshot.ref"
) )

View File

@ -326,35 +326,50 @@ func (s *snapshotter) createSnapshot(ctx context.Context, kind snapshots.Kind, k
} }
if kind == snapshots.KindActive { if kind == snapshots.KindActive {
parentLayerPaths := s.parentIDsToParentPaths(newSnapshot.ParentIDs) log.G(ctx).Debug("createSnapshot active")
// Create the new snapshot dir
var parentPath string snDir := s.getSnapshotDir(newSnapshot.ID)
if len(parentLayerPaths) != 0 { if err := os.MkdirAll(snDir, 0700); err != nil {
parentPath = parentLayerPaths[0] return nil, err
} }
if err := hcsshim.CreateSandboxLayer(s.info, newSnapshot.ID, parentPath, parentLayerPaths); err != nil { // IO/disk space optimization
return nil, errors.Wrap(err, "failed to create sandbox layer") //
} // We only need one sandbox.vhdx for the container. Skip making one for this
// snapshot if this isn't the snapshot that just houses the final sandbox.vhd
// that will be mounted as the containers scratch. Currently the key for a snapshot
// where a layer will be extracted to will have the string `extract-` in it.
if !strings.Contains(key, snapshots.UnpackKeyPrefix) {
parentLayerPaths := s.parentIDsToParentPaths(newSnapshot.ParentIDs)
var snapshotInfo snapshots.Info var parentPath string
for _, o := range opts { if len(parentLayerPaths) != 0 {
o(&snapshotInfo) parentPath = parentLayerPaths[0]
}
var sizeGB int
if sizeGBstr, ok := snapshotInfo.Labels[rootfsSizeLabel]; ok {
i32, err := strconv.ParseInt(sizeGBstr, 10, 32)
if err != nil {
return nil, errors.Wrapf(err, "failed to parse annotation %q=%q", rootfsSizeLabel, sizeGBstr)
} }
sizeGB = int(i32)
}
if sizeGB > 0 { if err := hcsshim.CreateSandboxLayer(s.info, newSnapshot.ID, parentPath, parentLayerPaths); err != nil {
const gbToByte = 1024 * 1024 * 1024 return nil, errors.Wrap(err, "failed to create sandbox layer")
if err := hcsshim.ExpandSandboxSize(s.info, newSnapshot.ID, uint64(gbToByte*sizeGB)); err != nil { }
return nil, errors.Wrapf(err, "failed to expand scratch size to %d GB", sizeGB)
var snapshotInfo snapshots.Info
for _, o := range opts {
o(&snapshotInfo)
}
var sizeGB int
if sizeGBstr, ok := snapshotInfo.Labels[rootfsSizeLabel]; ok {
i32, err := strconv.ParseInt(sizeGBstr, 10, 32)
if err != nil {
return nil, errors.Wrapf(err, "failed to parse label %q=%q", rootfsSizeLabel, sizeGBstr)
}
sizeGB = int(i32)
}
if sizeGB > 0 {
const gbToByte = 1024 * 1024 * 1024
if err := hcsshim.ExpandSandboxSize(s.info, newSnapshot.ID, uint64(gbToByte*sizeGB)); err != nil {
return nil, errors.Wrapf(err, "failed to expand scratch size to %d GB", sizeGB)
}
} }
} }
} }

View File

@ -138,7 +138,7 @@ EachLayer:
for try := 1; try <= 3; try++ { for try := 1; try <= 3; try++ {
// Prepare snapshot with from parent, label as root // Prepare snapshot with from parent, label as root
key = fmt.Sprintf("extract-%s %s", uniquePart(), chainID) key = fmt.Sprintf(snapshots.UnpackKeyFormat, uniquePart(), chainID)
mounts, err = sn.Prepare(ctx, key, parent.String(), opts...) mounts, err = sn.Prepare(ctx, key, parent.String(), opts...)
if err != nil { if err != nil {
if errdefs.IsAlreadyExists(err) { if errdefs.IsAlreadyExists(err) {