c8d: Compute container's layer size
Co-authored-by: Sebastiaan van Stijn <github@gone.nl> Signed-off-by: Laura Brehm <laurabrehm@hey.com>
This commit is contained in:
parent
6f719c74a9
commit
45ee4d7c78
13 changed files with 96 additions and 23 deletions
|
@ -49,7 +49,7 @@ type stateBackend interface {
|
|||
// monitorBackend includes functions to implement to provide containers monitoring functionality.
|
||||
type monitorBackend interface {
|
||||
ContainerChanges(name string) ([]archive.Change, error)
|
||||
ContainerInspect(name string, size bool, version string) (interface{}, error)
|
||||
ContainerInspect(ctx context.Context, name string, size bool, version string) (interface{}, error)
|
||||
ContainerLogs(ctx context.Context, name string, config *types.ContainerLogsOptions) (msgs <-chan *backend.LogMessage, tty bool, err error)
|
||||
ContainerStats(ctx context.Context, name string, config *backend.ContainerStatsConfig) error
|
||||
ContainerTop(name string, psArgs string) (*container.ContainerTopOKBody, error)
|
||||
|
|
|
@ -12,7 +12,7 @@ func (s *containerRouter) getContainersByName(ctx context.Context, w http.Respon
|
|||
displaySize := httputils.BoolValue(r, "size")
|
||||
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
json, err := s.backend.ContainerInspect(vars["name"], displaySize, version)
|
||||
json, err := s.backend.ContainerInspect(ctx, vars["name"], displaySize, version)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ type Backend interface {
|
|||
ActivateContainerServiceBinding(containerName string) error
|
||||
DeactivateContainerServiceBinding(containerName string) error
|
||||
UpdateContainerServiceConfig(containerName string, serviceConfig *clustertypes.ServiceConfig) error
|
||||
ContainerInspectCurrent(name string, size bool) (*types.ContainerJSON, error)
|
||||
ContainerInspectCurrent(ctx context.Context, name string, size bool) (*types.ContainerJSON, error)
|
||||
ContainerWait(ctx context.Context, name string, condition containerpkg.WaitCondition) (<-chan containerpkg.StateStatus, error)
|
||||
ContainerRm(name string, config *types.ContainerRmConfig) error
|
||||
ContainerKill(name string, sig string) error
|
||||
|
|
|
@ -361,7 +361,7 @@ func (c *containerAdapter) start(ctx context.Context) error {
|
|||
}
|
||||
|
||||
func (c *containerAdapter) inspect(ctx context.Context) (types.ContainerJSON, error) {
|
||||
cs, err := c.backend.ContainerInspectCurrent(c.container.name(), false)
|
||||
cs, err := c.backend.ContainerInspectCurrent(ctx, c.container.name(), false)
|
||||
if ctx.Err() != nil {
|
||||
return types.ContainerJSON{}, ctx.Err()
|
||||
}
|
||||
|
|
|
@ -2,8 +2,10 @@ package containerd
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/plugin"
|
||||
"github.com/containerd/containerd/remotes/docker"
|
||||
"github.com/containerd/containerd/snapshots"
|
||||
|
@ -13,6 +15,9 @@ import (
|
|||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/layer"
|
||||
"github.com/docker/docker/registry"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"github.com/opencontainers/image-spec/identity"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
|
@ -139,6 +144,56 @@ func (i *ImageService) GetLayerFolders(img *image.Image, rwLayer layer.RWLayer)
|
|||
}
|
||||
|
||||
// GetContainerLayerSize returns the real size & virtual size of the container.
|
||||
func (i *ImageService) GetContainerLayerSize(containerID string) (int64, int64) {
|
||||
panic("not implemented")
|
||||
func (i *ImageService) GetContainerLayerSize(ctx context.Context, containerID string) (int64, int64, error) {
|
||||
ctr := i.containers.Get(containerID)
|
||||
if ctr == nil {
|
||||
return 0, 0, nil
|
||||
}
|
||||
cs := i.client.ContentStore()
|
||||
|
||||
imageManifestBytes, err := content.ReadBlob(ctx, cs, *ctr.ImageManifest)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
var manifest ocispec.Manifest
|
||||
if err := json.Unmarshal(imageManifestBytes, &manifest); err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
imageConfigBytes, err := content.ReadBlob(ctx, cs, manifest.Config)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
var img ocispec.Image
|
||||
if err := json.Unmarshal(imageConfigBytes, &img); err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
snapshotter := i.client.SnapshotService(i.snapshotter)
|
||||
usage, err := snapshotter.Usage(ctx, containerID)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
sizeCache := make(map[digest.Digest]int64)
|
||||
snapshotSizeFn := func(d digest.Digest) (int64, error) {
|
||||
if s, ok := sizeCache[d]; ok {
|
||||
return s, nil
|
||||
}
|
||||
u, err := snapshotter.Usage(ctx, d.String())
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
sizeCache[d] = u.Size
|
||||
return u.Size, nil
|
||||
}
|
||||
|
||||
chainIDs := identity.ChainIDs(img.RootFS.DiffIDs)
|
||||
virtualSize, err := computeVirtualSize(chainIDs, snapshotSizeFn)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
return usage.Size, usage.Size + virtualSize, nil
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ type ImageService interface {
|
|||
GetLayerMountID(cid string) (string, error)
|
||||
ReleaseLayer(rwlayer layer.RWLayer) error
|
||||
LayerDiskUsage(ctx context.Context) (int64, error)
|
||||
GetContainerLayerSize(containerID string) (int64, int64)
|
||||
GetContainerLayerSize(ctx context.Context, containerID string) (int64, int64, error)
|
||||
Mount(ctx context.Context, container *container.Container) error
|
||||
Unmount(ctx context.Context, container *container.Container) error
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
package images // import "github.com/docker/docker/daemon/images"
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/layer"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
@ -16,7 +18,7 @@ func (i *ImageService) GetLayerFolders(img *image.Image, rwLayer layer.RWLayer)
|
|||
}
|
||||
|
||||
// GetContainerLayerSize returns the real size & virtual size of the container.
|
||||
func (i *ImageService) GetContainerLayerSize(containerID string) (int64, int64) {
|
||||
func (i *ImageService) GetContainerLayerSize(ctx context.Context, containerID string) (int64, int64, error) {
|
||||
var (
|
||||
sizeRw, sizeRootfs int64
|
||||
err error
|
||||
|
@ -27,7 +29,7 @@ func (i *ImageService) GetContainerLayerSize(containerID string) (int64, int64)
|
|||
rwlayer, err := i.layerStore.GetRWLayer(containerID)
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to compute size of container rootfs %v: %v", containerID, err)
|
||||
return sizeRw, sizeRootfs
|
||||
return sizeRw, sizeRootfs, nil
|
||||
}
|
||||
defer i.layerStore.ReleaseRWLayer(rwlayer)
|
||||
|
||||
|
@ -46,5 +48,5 @@ func (i *ImageService) GetContainerLayerSize(containerID string) (int64, int64)
|
|||
sizeRootfs += sizeRw
|
||||
}
|
||||
}
|
||||
return sizeRw, sizeRootfs
|
||||
return sizeRw, sizeRootfs, nil
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package images
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/layer"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
|
@ -8,9 +10,9 @@ import (
|
|||
)
|
||||
|
||||
// GetContainerLayerSize returns real size & virtual size
|
||||
func (i *ImageService) GetContainerLayerSize(containerID string) (int64, int64) {
|
||||
func (i *ImageService) GetContainerLayerSize(ctx context.Context, containerID string) (int64, int64, error) {
|
||||
// TODO Windows
|
||||
return 0, 0
|
||||
return 0, 0, nil
|
||||
}
|
||||
|
||||
// GetLayerFolders returns the layer folders from an image RootFS
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package daemon // import "github.com/docker/docker/daemon"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
@ -19,19 +20,19 @@ import (
|
|||
// ContainerInspect returns low-level information about a
|
||||
// container. Returns an error if the container cannot be found, or if
|
||||
// there is an error getting the data.
|
||||
func (daemon *Daemon) ContainerInspect(name string, size bool, version string) (interface{}, error) {
|
||||
func (daemon *Daemon) ContainerInspect(ctx context.Context, name string, size bool, version string) (interface{}, error) {
|
||||
switch {
|
||||
case versions.LessThan(version, "1.20"):
|
||||
return daemon.containerInspectPre120(name)
|
||||
return daemon.containerInspectPre120(ctx, name)
|
||||
case versions.Equal(version, "1.20"):
|
||||
return daemon.containerInspect120(name)
|
||||
}
|
||||
return daemon.ContainerInspectCurrent(name, size)
|
||||
return daemon.ContainerInspectCurrent(ctx, name, size)
|
||||
}
|
||||
|
||||
// ContainerInspectCurrent returns low-level information about a
|
||||
// container in a most recent api version.
|
||||
func (daemon *Daemon) ContainerInspectCurrent(name string, size bool) (*types.ContainerJSON, error) {
|
||||
func (daemon *Daemon) ContainerInspectCurrent(ctx context.Context, name string, size bool) (*types.ContainerJSON, error) {
|
||||
ctr, err := daemon.GetContainer(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -78,7 +79,10 @@ func (daemon *Daemon) ContainerInspectCurrent(name string, size bool) (*types.Co
|
|||
ctr.Unlock()
|
||||
|
||||
if size {
|
||||
sizeRw, sizeRootFs := daemon.imageService.GetContainerLayerSize(base.ID)
|
||||
sizeRw, sizeRootFs, err := daemon.imageService.GetContainerLayerSize(ctx, base.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
base.SizeRw = &sizeRw
|
||||
base.SizeRootFs = &sizeRootFs
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package daemon // import "github.com/docker/docker/daemon"
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/docker/api/types/versions/v1p19"
|
||||
|
@ -18,7 +20,7 @@ func setPlatformSpecificContainerFields(container *container.Container, contJSON
|
|||
}
|
||||
|
||||
// containerInspectPre120 gets containers for pre 1.20 APIs.
|
||||
func (daemon *Daemon) containerInspectPre120(name string) (*v1p19.ContainerJSON, error) {
|
||||
func (daemon *Daemon) containerInspectPre120(ctx context.Context, name string) (*v1p19.ContainerJSON, error) {
|
||||
ctr, err := daemon.GetContainer(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package daemon // import "github.com/docker/docker/daemon"
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/docker/container"
|
||||
|
@ -12,8 +14,8 @@ func setPlatformSpecificContainerFields(container *container.Container, contJSON
|
|||
}
|
||||
|
||||
// containerInspectPre120 get containers for pre 1.20 APIs.
|
||||
func (daemon *Daemon) containerInspectPre120(name string) (*types.ContainerJSON, error) {
|
||||
return daemon.ContainerInspectCurrent(name, false)
|
||||
func (daemon *Daemon) containerInspectPre120(ctx context.Context, name string) (*types.ContainerJSON, error) {
|
||||
return daemon.ContainerInspectCurrent(ctx, name, false)
|
||||
}
|
||||
|
||||
func inspectExecProcessConfig(e *container.ExecConfig) *backend.ExecProcessConfig {
|
||||
|
|
|
@ -238,7 +238,10 @@ func (daemon *Daemon) reducePsContainer(ctx context.Context, container *containe
|
|||
|
||||
// release lock because size calculation is slow
|
||||
if filter.Size {
|
||||
sizeRw, sizeRootFs := daemon.imageService.GetContainerLayerSize(newC.ID)
|
||||
sizeRw, sizeRootFs, err := daemon.imageService.GetContainerLayerSize(ctx, newC.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
newC.SizeRw = sizeRw
|
||||
newC.SizeRootFs = sizeRootFs
|
||||
}
|
||||
|
|
|
@ -73,9 +73,12 @@ func (daemon *Daemon) ContainersPrune(ctx context.Context, pruneFilters filters.
|
|||
if !matchLabels(pruneFilters, c.Config.Labels) {
|
||||
continue
|
||||
}
|
||||
cSize, _ := daemon.imageService.GetContainerLayerSize(c.ID)
|
||||
cSize, _, err := daemon.imageService.GetContainerLayerSize(ctx, c.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// TODO: sets RmLink to true?
|
||||
err := daemon.ContainerRm(c.ID, &types.ContainerRmConfig{})
|
||||
err = daemon.ContainerRm(c.ID, &types.ContainerRmConfig{})
|
||||
if err != nil {
|
||||
logrus.Warnf("failed to prune container %s: %v", c.ID, err)
|
||||
continue
|
||||
|
|
Loading…
Reference in a new issue