faster image inspection

Vendor the latest HEAD in c/common to pull in changes for a faster
inspection of images.  Previously, only the size computation was
optional, now the one for the parent image is as well.

In many cases, the parent image is not needed but it takes around 10ms
on my local machine.  With this change, we cut off 10ms from many code
paths, most importantly, container creation.

[NO NEW TESTS NEEDED]

Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
This commit is contained in:
Valentin Rothberg
2021-10-08 14:45:19 +02:00
parent 14c0fcc6b7
commit fad14dafe1
13 changed files with 59 additions and 31 deletions

2
go.mod
View File

@ -12,7 +12,7 @@ require (
github.com/containernetworking/cni v1.0.1 github.com/containernetworking/cni v1.0.1
github.com/containernetworking/plugins v1.0.1 github.com/containernetworking/plugins v1.0.1
github.com/containers/buildah v1.23.1 github.com/containers/buildah v1.23.1
github.com/containers/common v0.46.1-0.20211001143714-161e078e4c7f github.com/containers/common v0.46.1-0.20211008123044-d846f5aaec0e
github.com/containers/conmon v2.0.20+incompatible github.com/containers/conmon v2.0.20+incompatible
github.com/containers/image/v5 v5.16.1 github.com/containers/image/v5 v5.16.1
github.com/containers/ocicrypt v1.1.2 github.com/containers/ocicrypt v1.1.2

6
go.sum
View File

@ -251,8 +251,8 @@ github.com/containernetworking/plugins v1.0.1/go.mod h1:QHCfGpaTwYTbbH+nZXKVTxNB
github.com/containers/buildah v1.23.1 h1:Tpc9DsRuU+0Oofewpxb6OJVNQjCu7yloN/obUqzfDTY= github.com/containers/buildah v1.23.1 h1:Tpc9DsRuU+0Oofewpxb6OJVNQjCu7yloN/obUqzfDTY=
github.com/containers/buildah v1.23.1/go.mod h1:4WnrN0yrA7ab0ppgunixu2WM1rlD2rG8QLJAKbEkZlQ= github.com/containers/buildah v1.23.1/go.mod h1:4WnrN0yrA7ab0ppgunixu2WM1rlD2rG8QLJAKbEkZlQ=
github.com/containers/common v0.44.2/go.mod h1:7sdP4vmI5Bm6FPFxb3lvAh1Iktb6tiO1MzjUzhxdoGo= github.com/containers/common v0.44.2/go.mod h1:7sdP4vmI5Bm6FPFxb3lvAh1Iktb6tiO1MzjUzhxdoGo=
github.com/containers/common v0.46.1-0.20211001143714-161e078e4c7f h1:vVmx51AzWvB4/ao2zyR6s053a1leLTOh+zsOPVWQRgA= github.com/containers/common v0.46.1-0.20211008123044-d846f5aaec0e h1:lYazDued7KBcMq5IJzRIbX47SSLRg/yYxvM/P9LaVhE=
github.com/containers/common v0.46.1-0.20211001143714-161e078e4c7f/go.mod h1:aml/OO4FmYfPbfT87rvWiCgkLzTdqO6PuZ/xXq6bPbk= github.com/containers/common v0.46.1-0.20211008123044-d846f5aaec0e/go.mod h1:ggZks97KCmjBcHvNTCyLc17SqdjSYoeexW7rnRt9H9Y=
github.com/containers/conmon v2.0.20+incompatible h1:YbCVSFSCqFjjVwHTPINGdMX1F6JXHGTUje2ZYobNrkg= github.com/containers/conmon v2.0.20+incompatible h1:YbCVSFSCqFjjVwHTPINGdMX1F6JXHGTUje2ZYobNrkg=
github.com/containers/conmon v2.0.20+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I= github.com/containers/conmon v2.0.20+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I=
github.com/containers/image/v5 v5.16.0/go.mod h1:XgTpfAPLRGOd1XYyCU5cISFr777bLmOerCSpt/v7+Q4= github.com/containers/image/v5 v5.16.0/go.mod h1:XgTpfAPLRGOd1XYyCU5cISFr777bLmOerCSpt/v7+Q4=
@ -921,7 +921,6 @@ github.com/vbatts/tar-split v0.11.2/go.mod h1:vV3ZuO2yWSVsz+pfFzDG/upWH1JhjOiEaW
github.com/vbauerster/mpb/v6 v6.0.4 h1:h6J5zM/2wimP5Hj00unQuV8qbo5EPcj6wbkCqgj7KcY= github.com/vbauerster/mpb/v6 v6.0.4 h1:h6J5zM/2wimP5Hj00unQuV8qbo5EPcj6wbkCqgj7KcY=
github.com/vbauerster/mpb/v6 v6.0.4/go.mod h1:a/+JT57gqh6Du0Ay5jSR+uBMfXGdlR7VQlGP52fJxLM= github.com/vbauerster/mpb/v6 v6.0.4/go.mod h1:a/+JT57gqh6Du0Ay5jSR+uBMfXGdlR7VQlGP52fJxLM=
github.com/vbauerster/mpb/v7 v7.1.3/go.mod h1:X5GlohZw2fIpypMXWaKart+HGSAjpz49skxkDk+ZL7c= github.com/vbauerster/mpb/v7 v7.1.3/go.mod h1:X5GlohZw2fIpypMXWaKart+HGSAjpz49skxkDk+ZL7c=
github.com/vbauerster/mpb/v7 v7.1.4/go.mod h1:4zulrZfvshMOnd2APiHgWS9Yrw08AzZVRr9G11tkpcQ=
github.com/vbauerster/mpb/v7 v7.1.5 h1:vtUEUfQHmNeJETyF4AcRCOV6RC4wqFwNORy52UMXPbQ= github.com/vbauerster/mpb/v7 v7.1.5 h1:vtUEUfQHmNeJETyF4AcRCOV6RC4wqFwNORy52UMXPbQ=
github.com/vbauerster/mpb/v7 v7.1.5/go.mod h1:4M8+qAoQqV60WDNktBM5k05i1iTrXE7rjKOHEVkVlec= github.com/vbauerster/mpb/v7 v7.1.5/go.mod h1:4M8+qAoQqV60WDNktBM5k05i1iTrXE7rjKOHEVkVlec=
github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
@ -1211,7 +1210,6 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210820121016-41cdb8703e55/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210820121016-41cdb8703e55/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210910150752-751e447fb3d0 h1:xrCZDmdtoloIiooiA9q0OQb9r8HejIHYoHGhGCe1pGg= golang.org/x/sys v0.0.0-20210910150752-751e447fb3d0 h1:xrCZDmdtoloIiooiA9q0OQb9r8HejIHYoHGhGCe1pGg=
golang.org/x/sys v0.0.0-20210910150752-751e447fb3d0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210910150752-751e447fb3d0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=

View File

@ -477,7 +477,7 @@ func containerToV1Container(ctx context.Context, c *Container) (v1.Container, []
if err != nil { if err != nil {
return kubeContainer, kubeVolumes, nil, annotations, err return kubeContainer, kubeVolumes, nil, annotations, err
} }
imgData, err := img.Inspect(ctx, false) imgData, err := img.Inspect(ctx, nil)
if err != nil { if err != nil {
return kubeContainer, kubeVolumes, nil, annotations, err return kubeContainer, kubeVolumes, nil, annotations, err
} }

View File

@ -11,6 +11,7 @@ import (
"strings" "strings"
"github.com/containers/buildah" "github.com/containers/buildah"
"github.com/containers/common/libimage"
"github.com/containers/common/pkg/filters" "github.com/containers/common/pkg/filters"
"github.com/containers/image/v5/manifest" "github.com/containers/image/v5/manifest"
"github.com/containers/image/v5/types" "github.com/containers/image/v5/types"
@ -93,7 +94,8 @@ func GetImage(w http.ResponseWriter, r *http.Request) {
utils.Error(w, "Something went wrong.", http.StatusNotFound, errors.Wrapf(err, "failed to find image %s", name)) utils.Error(w, "Something went wrong.", http.StatusNotFound, errors.Wrapf(err, "failed to find image %s", name))
return return
} }
inspect, err := newImage.Inspect(r.Context(), true) options := &libimage.InspectOptions{WithParent: true, WithSize: true}
inspect, err := newImage.Inspect(r.Context(), options)
if err != nil { if err != nil {
utils.Error(w, "Server error", http.StatusInternalServerError, errors.Wrapf(err, "failed in inspect image %s", inspect.ID)) utils.Error(w, "Server error", http.StatusInternalServerError, errors.Wrapf(err, "failed in inspect image %s", inspect.ID))
return return

View File

@ -166,7 +166,8 @@ type ExecStartConfig struct {
} }
func ImageToImageSummary(l *libimage.Image) (*entities.ImageSummary, error) { func ImageToImageSummary(l *libimage.Image) (*entities.ImageSummary, error) {
imageData, err := l.Inspect(context.TODO(), true) options := &libimage.InspectOptions{WithParent: true, WithSize: true}
imageData, err := l.Inspect(context.TODO(), options)
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "failed to obtain summary for image %s", l.ID()) return nil, errors.Wrapf(err, "failed to obtain summary for image %s", l.ID())
} }
@ -205,7 +206,8 @@ func ImageToImageSummary(l *libimage.Image) (*entities.ImageSummary, error) {
} }
func ImageDataToImageInspect(ctx context.Context, l *libimage.Image) (*ImageInspect, error) { func ImageDataToImageInspect(ctx context.Context, l *libimage.Image) (*ImageInspect, error) {
info, err := l.Inspect(context.Background(), true) options := &libimage.InspectOptions{WithParent: true, WithSize: true}
info, err := l.Inspect(context.Background(), options)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -252,6 +252,8 @@ func (ir *ImageEngine) Pull(ctx context.Context, rawImage string, options entiti
func (ir *ImageEngine) Inspect(ctx context.Context, namesOrIDs []string, opts entities.InspectOptions) ([]*entities.ImageInspectReport, []error, error) { func (ir *ImageEngine) Inspect(ctx context.Context, namesOrIDs []string, opts entities.InspectOptions) ([]*entities.ImageInspectReport, []error, error) {
reports := []*entities.ImageInspectReport{} reports := []*entities.ImageInspectReport{}
errs := []error{} errs := []error{}
inspectOptions := &libimage.InspectOptions{WithParent: true, WithSize: true}
for _, i := range namesOrIDs { for _, i := range namesOrIDs {
img, _, err := ir.Libpod.LibimageRuntime().LookupImage(i, nil) img, _, err := ir.Libpod.LibimageRuntime().LookupImage(i, nil)
if err != nil { if err != nil {
@ -259,7 +261,7 @@ func (ir *ImageEngine) Inspect(ctx context.Context, namesOrIDs []string, opts en
errs = append(errs, err) errs = append(errs, err)
continue continue
} }
result, err := img.Inspect(ctx, true) result, err := img.Inspect(ctx, inspectOptions)
if err != nil { if err != nil {
// This is more likely to be fatal. // This is more likely to be fatal.
return nil, nil, err return nil, nil, err

View File

@ -26,7 +26,7 @@ func getImageFromSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGen
// Image may already have been set in the generator. // Image may already have been set in the generator.
image, resolvedName := s.GetImage() image, resolvedName := s.GetImage()
if image != nil { if image != nil {
inspectData, err := image.Inspect(ctx, false) inspectData, err := image.Inspect(ctx, nil)
if err != nil { if err != nil {
return nil, "", nil, err return nil, "", nil, err
} }
@ -39,7 +39,7 @@ func getImageFromSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGen
return nil, "", nil, err return nil, "", nil, err
} }
s.SetImage(image, resolvedName) s.SetImage(image, resolvedName)
inspectData, err := image.Inspect(ctx, false) inspectData, err := image.Inspect(ctx, nil)
if err != nil { if err != nil {
return nil, "", nil, err return nil, "", nil, err
} }
@ -55,7 +55,7 @@ func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerat
return nil, err return nil, err
} }
if inspectData != nil { if inspectData != nil {
inspectData, err = newImage.Inspect(ctx, false) inspectData, err = newImage.Inspect(ctx, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -194,7 +194,7 @@ func ToSpecGen(ctx context.Context, opts *CtrSpecGenOptions) (*specgen.SpecGener
// TODO: We don't understand why specgen does not take of this, but // TODO: We don't understand why specgen does not take of this, but
// integration tests clearly pointed out that it was required. // integration tests clearly pointed out that it was required.
imageData, err := opts.Image.Inspect(ctx, false) imageData, err := opts.Image.Inspect(ctx, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -208,7 +208,7 @@ func getImageVolumes(ctx context.Context, img *libimage.Image, s *specgen.SpecGe
return mounts, volumes, nil return mounts, volumes, nil
} }
inspect, err := img.Inspect(ctx, false) inspect, err := img.Inspect(ctx, nil)
if err != nil { if err != nil {
return nil, nil, errors.Wrapf(err, "error inspecting image to get image volumes") return nil, nil, errors.Wrapf(err, "error inspecting image to get image volumes")
} }

View File

@ -50,19 +50,39 @@ type RootFS struct {
Layers []digest.Digest `json:"Layers"` Layers []digest.Digest `json:"Layers"`
} }
// Inspect inspects the image. Use `withSize` to also perform the // InspectOptions allow for customizing inspecting images.
// comparatively expensive size computation of the image. type InspectOptions struct {
func (i *Image) Inspect(ctx context.Context, withSize bool) (*ImageData, error) { // Compute the size of the image (expensive).
WithSize bool
// Compute the parent of the image (expensive).
WithParent bool
}
// Inspect inspects the image.
func (i *Image) Inspect(ctx context.Context, options *InspectOptions) (*ImageData, error) {
logrus.Debugf("Inspecting image %s", i.ID()) logrus.Debugf("Inspecting image %s", i.ID())
if options == nil {
options = &InspectOptions{}
}
if i.cached.completeInspectData != nil { if i.cached.completeInspectData != nil {
if withSize && i.cached.completeInspectData.Size == int64(-1) { if options.WithSize && i.cached.completeInspectData.Size == int64(-1) {
size, err := i.Size() size, err := i.Size()
if err != nil { if err != nil {
return nil, err return nil, err
} }
i.cached.completeInspectData.Size = size i.cached.completeInspectData.Size = size
} }
if options.WithParent && i.cached.completeInspectData.Parent == "" {
parentImage, err := i.Parent(ctx)
if err != nil {
return nil, err
}
if parentImage != nil {
i.cached.completeInspectData.Parent = parentImage.ID()
}
}
return i.cached.completeInspectData, nil return i.cached.completeInspectData, nil
} }
@ -75,10 +95,7 @@ func (i *Image) Inspect(ctx context.Context, withSize bool) (*ImageData, error)
if err != nil { if err != nil {
return nil, err return nil, err
} }
parentImage, err := i.Parent(ctx)
if err != nil {
return nil, err
}
repoTags, err := i.RepoTags() repoTags, err := i.RepoTags()
if err != nil { if err != nil {
return nil, err return nil, err
@ -93,7 +110,7 @@ func (i *Image) Inspect(ctx context.Context, withSize bool) (*ImageData, error)
} }
size := int64(-1) size := int64(-1)
if withSize { if options.WithSize {
size, err = i.Size() size, err = i.Size()
if err != nil { if err != nil {
return nil, err return nil, err
@ -124,9 +141,15 @@ func (i *Image) Inspect(ctx context.Context, withSize bool) (*ImageData, error)
NamesHistory: i.NamesHistory(), NamesHistory: i.NamesHistory(),
} }
if options.WithParent {
parentImage, err := i.Parent(ctx)
if err != nil {
return nil, err
}
if parentImage != nil { if parentImage != nil {
data.Parent = parentImage.ID() data.Parent = parentImage.ID()
} }
}
// Determine the format of the image. How we determine certain data // Determine the format of the image. How we determine certain data
// depends on the format (e.g., Docker v2s2, OCI v1). // depends on the format (e.g., Docker v2s2, OCI v1).

View File

@ -477,10 +477,10 @@ func (r *Runtime) copySingleImageFromRegistry(ctx context.Context, imageName str
if pullPolicy == config.PullPolicyNever { if pullPolicy == config.PullPolicyNever {
if localImage != nil { if localImage != nil {
logrus.Debugf("Pull policy %q but no local image has been found for %s", pullPolicy, imageName) logrus.Debugf("Pull policy %q and %s resolved to local image %s", pullPolicy, imageName, resolvedImageName)
return []string{resolvedImageName}, nil return []string{resolvedImageName}, nil
} }
logrus.Debugf("Pull policy %q and %s resolved to local image %s", pullPolicy, imageName, resolvedImageName) logrus.Debugf("Pull policy %q but no local image has been found for %s", pullPolicy, imageName)
return nil, errors.Wrap(storage.ErrImageUnknown, imageName) return nil, errors.Wrap(storage.ErrImageUnknown, imageName)
} }

View File

@ -286,6 +286,7 @@ func searchRepositoryTags(ctx context.Context, sys *types.SystemContext, registr
params := SearchResult{ params := SearchResult{
Name: imageRef.DockerReference().Name(), Name: imageRef.DockerReference().Name(),
Tag: tags[i], Tag: tags[i],
Index: registry,
} }
paramsArr = append(paramsArr, params) paramsArr = append(paramsArr, params)
} }

2
vendor/modules.txt vendored
View File

@ -95,7 +95,7 @@ github.com/containers/buildah/pkg/rusage
github.com/containers/buildah/pkg/sshagent github.com/containers/buildah/pkg/sshagent
github.com/containers/buildah/pkg/util github.com/containers/buildah/pkg/util
github.com/containers/buildah/util github.com/containers/buildah/util
# github.com/containers/common v0.46.1-0.20211001143714-161e078e4c7f # github.com/containers/common v0.46.1-0.20211008123044-d846f5aaec0e
github.com/containers/common/libimage github.com/containers/common/libimage
github.com/containers/common/libimage/manifests github.com/containers/common/libimage/manifests
github.com/containers/common/pkg/apparmor github.com/containers/common/pkg/apparmor