Merge pull request #14599 from feiskyer/kubelet/client-server/image-refator

Refactor image manager for client/server container runtime
This commit is contained in:
Dawn Chen 2015-09-29 09:33:59 -07:00
commit ca3ae476fc
3 changed files with 131 additions and 100 deletions

View File

@ -22,12 +22,11 @@ import (
"sync" "sync"
"time" "time"
docker "github.com/fsouza/go-dockerclient"
"github.com/golang/glog" "github.com/golang/glog"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/client/record" "k8s.io/kubernetes/pkg/client/record"
"k8s.io/kubernetes/pkg/kubelet/cadvisor" "k8s.io/kubernetes/pkg/kubelet/cadvisor"
"k8s.io/kubernetes/pkg/kubelet/dockertools" "k8s.io/kubernetes/pkg/kubelet/container"
"k8s.io/kubernetes/pkg/util" "k8s.io/kubernetes/pkg/util"
"k8s.io/kubernetes/pkg/util/sets" "k8s.io/kubernetes/pkg/util/sets"
) )
@ -59,8 +58,8 @@ type ImageGCPolicy struct {
} }
type realImageManager struct { type realImageManager struct {
// Connection to the Docker daemon. // Container runtime
dockerClient dockertools.DockerInterface runtime container.Runtime
// Records of images and their use. // Records of images and their use.
imageRecords map[string]*imageRecord imageRecords map[string]*imageRecord
@ -91,7 +90,7 @@ type imageRecord struct {
size int64 size int64
} }
func newImageManager(dockerClient dockertools.DockerInterface, cadvisorInterface cadvisor.Interface, recorder record.EventRecorder, nodeRef *api.ObjectReference, policy ImageGCPolicy) (imageManager, error) { func newImageManager(runtime container.Runtime, cadvisorInterface cadvisor.Interface, recorder record.EventRecorder, nodeRef *api.ObjectReference, policy ImageGCPolicy) (imageManager, error) {
// Validate policy. // Validate policy.
if policy.HighThresholdPercent < 0 || policy.HighThresholdPercent > 100 { if policy.HighThresholdPercent < 0 || policy.HighThresholdPercent > 100 {
return nil, fmt.Errorf("invalid HighThresholdPercent %d, must be in range [0-100]", policy.HighThresholdPercent) return nil, fmt.Errorf("invalid HighThresholdPercent %d, must be in range [0-100]", policy.HighThresholdPercent)
@ -100,7 +99,7 @@ func newImageManager(dockerClient dockertools.DockerInterface, cadvisorInterface
return nil, fmt.Errorf("invalid LowThresholdPercent %d, must be in range [0-100]", policy.LowThresholdPercent) return nil, fmt.Errorf("invalid LowThresholdPercent %d, must be in range [0-100]", policy.LowThresholdPercent)
} }
im := &realImageManager{ im := &realImageManager{
dockerClient: dockerClient, runtime: runtime,
policy: policy, policy: policy,
imageRecords: make(map[string]*imageRecord), imageRecords: make(map[string]*imageRecord),
cadvisor: cadvisorInterface, cadvisor: cadvisorInterface,
@ -130,22 +129,22 @@ func (im *realImageManager) Start() error {
} }
func (im *realImageManager) detectImages(detected time.Time) error { func (im *realImageManager) detectImages(detected time.Time) error {
images, err := im.dockerClient.ListImages(docker.ListImagesOptions{}) images, err := im.runtime.ListImages()
if err != nil { if err != nil {
return err return err
} }
containers, err := im.dockerClient.ListContainers(docker.ListContainersOptions{ pods, err := im.runtime.GetPods(true)
All: true,
})
if err != nil { if err != nil {
return err return err
} }
// Make a set of images in use by containers. // Make a set of images in use by containers.
imagesInUse := sets.NewString() imagesInUse := sets.NewString()
for _, container := range containers { for _, pod := range pods {
for _, container := range pod.Containers {
imagesInUse.Insert(container.Image) imagesInUse.Insert(container.Image)
} }
}
// Add new images and record those being used. // Add new images and record those being used.
now := time.Now() now := time.Now()
@ -163,11 +162,11 @@ func (im *realImageManager) detectImages(detected time.Time) error {
} }
// Set last used time to now if the image is being used. // Set last used time to now if the image is being used.
if isImageUsed(&image, imagesInUse) { if isImageUsed(image, imagesInUse) {
im.imageRecords[image.ID].lastUsed = now im.imageRecords[image.ID].lastUsed = now
} }
im.imageRecords[image.ID].size = image.VirtualSize im.imageRecords[image.ID].size = image.Size
} }
// Remove old images from our records. // Remove old images from our records.
@ -253,7 +252,7 @@ func (im *realImageManager) freeSpace(bytesToFree int64) (int64, error) {
// Remove image. Continue despite errors. // Remove image. Continue despite errors.
glog.Infof("[ImageManager]: Removing image %q to free %d bytes", image.id, image.size) glog.Infof("[ImageManager]: Removing image %q to free %d bytes", image.id, image.size)
err := im.dockerClient.RemoveImage(image.id) err := im.runtime.RemoveImage(container.ImageSpec{Image: image.id})
if err != nil { if err != nil {
lastErr = err lastErr = err
continue continue
@ -287,12 +286,12 @@ func (ev byLastUsedAndDetected) Less(i, j int) bool {
} }
} }
func isImageUsed(image *docker.APIImages, imagesInUse sets.String) bool { func isImageUsed(image container.Image, imagesInUse sets.String) bool {
// Check the image ID and all the RepoTags. // Check the image ID and all the RepoTags.
if _, ok := imagesInUse[image.ID]; ok { if _, ok := imagesInUse[image.ID]; ok {
return true return true
} }
for _, tag := range image.RepoTags { for _, tag := range image.Tags {
if _, ok := imagesInUse[tag]; ok { if _, ok := imagesInUse[tag]; ok {
return true return true
} }

View File

@ -21,30 +21,27 @@ import (
"testing" "testing"
"time" "time"
docker "github.com/fsouza/go-dockerclient"
cadvisorApiV2 "github.com/google/cadvisor/info/v2" cadvisorApiV2 "github.com/google/cadvisor/info/v2"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"k8s.io/kubernetes/pkg/client/record" "k8s.io/kubernetes/pkg/client/record"
"k8s.io/kubernetes/pkg/kubelet/cadvisor" "k8s.io/kubernetes/pkg/kubelet/cadvisor"
"k8s.io/kubernetes/pkg/kubelet/dockertools" "k8s.io/kubernetes/pkg/kubelet/container"
"k8s.io/kubernetes/pkg/util/sets" "k8s.io/kubernetes/pkg/types"
) )
var zero time.Time var zero time.Time
func newRealImageManager(policy ImageGCPolicy) (*realImageManager, *dockertools.FakeDockerClient, *cadvisor.Mock) { func newRealImageManager(policy ImageGCPolicy) (*realImageManager, *container.FakeRuntime, *cadvisor.Mock) {
fakeDocker := &dockertools.FakeDockerClient{ fakeRuntime := &container.FakeRuntime{}
RemovedImages: sets.NewString(),
}
mockCadvisor := new(cadvisor.Mock) mockCadvisor := new(cadvisor.Mock)
return &realImageManager{ return &realImageManager{
dockerClient: fakeDocker, runtime: fakeRuntime,
policy: policy, policy: policy,
imageRecords: make(map[string]*imageRecord), imageRecords: make(map[string]*imageRecord),
cadvisor: mockCadvisor, cadvisor: mockCadvisor,
recorder: &record.FakeRecorder{}, recorder: &record.FakeRecorder{},
}, fakeDocker, mockCadvisor }, fakeRuntime, mockCadvisor
} }
// Accessors used for thread-safe testing. // Accessors used for thread-safe testing.
@ -67,29 +64,33 @@ func imageName(id int) string {
} }
// Make an image with the specified ID. // Make an image with the specified ID.
func makeImage(id int, size int64) docker.APIImages { func makeImage(id int, size int64) container.Image {
return docker.APIImages{ return container.Image{
ID: imageName(id), ID: imageName(id),
VirtualSize: size, Size: size,
} }
} }
// Make a container with the specified ID. It will use the image with the same ID. // Make a container with the specified ID. It will use the image with the same ID.
func makeContainer(id int) docker.APIContainers { func makeContainer(id int) *container.Container {
return docker.APIContainers{ return &container.Container{
ID: fmt.Sprintf("container-%d", id), ID: types.UID(fmt.Sprintf("container-%d", id)),
Image: imageName(id), Image: imageName(id),
} }
} }
func TestDetectImagesInitialDetect(t *testing.T) { func TestDetectImagesInitialDetect(t *testing.T) {
manager, fakeDocker, _ := newRealImageManager(ImageGCPolicy{}) manager, fakeRuntime, _ := newRealImageManager(ImageGCPolicy{})
fakeDocker.Images = []docker.APIImages{ fakeRuntime.ImageList = []container.Image{
makeImage(0, 1024), makeImage(0, 1024),
makeImage(1, 2048), makeImage(1, 2048),
} }
fakeDocker.ContainerList = []docker.APIContainers{ fakeRuntime.PodList = []*container.Pod{
{
Containers: []*container.Container{
makeContainer(1), makeContainer(1),
},
},
} }
startTime := time.Now().Add(-time.Millisecond) startTime := time.Now().Add(-time.Millisecond)
@ -109,13 +110,17 @@ func TestDetectImagesInitialDetect(t *testing.T) {
func TestDetectImagesWithNewImage(t *testing.T) { func TestDetectImagesWithNewImage(t *testing.T) {
// Just one image initially. // Just one image initially.
manager, fakeDocker, _ := newRealImageManager(ImageGCPolicy{}) manager, fakeRuntime, _ := newRealImageManager(ImageGCPolicy{})
fakeDocker.Images = []docker.APIImages{ fakeRuntime.ImageList = []container.Image{
makeImage(0, 1024), makeImage(0, 1024),
makeImage(1, 2048), makeImage(1, 2048),
} }
fakeDocker.ContainerList = []docker.APIContainers{ fakeRuntime.PodList = []*container.Pod{
{
Containers: []*container.Container{
makeContainer(1), makeContainer(1),
},
},
} }
err := manager.detectImages(zero) err := manager.detectImages(zero)
@ -124,7 +129,7 @@ func TestDetectImagesWithNewImage(t *testing.T) {
assert.Equal(manager.imageRecordsLen(), 2) assert.Equal(manager.imageRecordsLen(), 2)
// Add a new image. // Add a new image.
fakeDocker.Images = []docker.APIImages{ fakeRuntime.ImageList = []container.Image{
makeImage(0, 1024), makeImage(0, 1024),
makeImage(1, 1024), makeImage(1, 1024),
makeImage(2, 1024), makeImage(2, 1024),
@ -150,13 +155,17 @@ func TestDetectImagesWithNewImage(t *testing.T) {
} }
func TestDetectImagesContainerStopped(t *testing.T) { func TestDetectImagesContainerStopped(t *testing.T) {
manager, fakeDocker, _ := newRealImageManager(ImageGCPolicy{}) manager, fakeRuntime, _ := newRealImageManager(ImageGCPolicy{})
fakeDocker.Images = []docker.APIImages{ fakeRuntime.ImageList = []container.Image{
makeImage(0, 1024), makeImage(0, 1024),
makeImage(1, 2048), makeImage(1, 2048),
} }
fakeDocker.ContainerList = []docker.APIContainers{ fakeRuntime.PodList = []*container.Pod{
{
Containers: []*container.Container{
makeContainer(1), makeContainer(1),
},
},
} }
err := manager.detectImages(zero) err := manager.detectImages(zero)
@ -167,7 +176,7 @@ func TestDetectImagesContainerStopped(t *testing.T) {
require.True(t, ok) require.True(t, ok)
// Simulate container being stopped. // Simulate container being stopped.
fakeDocker.ContainerList = []docker.APIContainers{} fakeRuntime.PodList = []*container.Pod{}
err = manager.detectImages(time.Now()) err = manager.detectImages(time.Now())
require.NoError(t, err) require.NoError(t, err)
assert.Equal(manager.imageRecordsLen(), 2) assert.Equal(manager.imageRecordsLen(), 2)
@ -182,13 +191,17 @@ func TestDetectImagesContainerStopped(t *testing.T) {
} }
func TestDetectImagesWithRemovedImages(t *testing.T) { func TestDetectImagesWithRemovedImages(t *testing.T) {
manager, fakeDocker, _ := newRealImageManager(ImageGCPolicy{}) manager, fakeRuntime, _ := newRealImageManager(ImageGCPolicy{})
fakeDocker.Images = []docker.APIImages{ fakeRuntime.ImageList = []container.Image{
makeImage(0, 1024), makeImage(0, 1024),
makeImage(1, 2048), makeImage(1, 2048),
} }
fakeDocker.ContainerList = []docker.APIContainers{ fakeRuntime.PodList = []*container.Pod{
{
Containers: []*container.Container{
makeContainer(1), makeContainer(1),
},
},
} }
err := manager.detectImages(zero) err := manager.detectImages(zero)
@ -197,48 +210,63 @@ func TestDetectImagesWithRemovedImages(t *testing.T) {
assert.Equal(manager.imageRecordsLen(), 2) assert.Equal(manager.imageRecordsLen(), 2)
// Simulate both images being removed. // Simulate both images being removed.
fakeDocker.Images = []docker.APIImages{} fakeRuntime.ImageList = []container.Image{}
err = manager.detectImages(time.Now()) err = manager.detectImages(time.Now())
require.NoError(t, err) require.NoError(t, err)
assert.Equal(manager.imageRecordsLen(), 0) assert.Equal(manager.imageRecordsLen(), 0)
} }
func TestFreeSpaceImagesInUseContainersAreIgnored(t *testing.T) { func TestFreeSpaceImagesInUseContainersAreIgnored(t *testing.T) {
manager, fakeDocker, _ := newRealImageManager(ImageGCPolicy{}) manager, fakeRuntime, _ := newRealImageManager(ImageGCPolicy{})
fakeDocker.Images = []docker.APIImages{ fakeRuntime.ImageList = []container.Image{
makeImage(0, 1024), makeImage(0, 1024),
makeImage(1, 2048), makeImage(1, 2048),
} }
fakeDocker.ContainerList = []docker.APIContainers{ fakeRuntime.PodList = []*container.Pod{
{
Containers: []*container.Container{
makeContainer(1), makeContainer(1),
},
},
} }
spaceFreed, err := manager.freeSpace(2048) spaceFreed, err := manager.freeSpace(2048)
assert := assert.New(t) assert := assert.New(t)
require.NoError(t, err) require.NoError(t, err)
assert.EqualValues(1024, spaceFreed) assert.EqualValues(1024, spaceFreed)
assert.Len(fakeDocker.RemovedImages, 1) assert.Len(fakeRuntime.ImageList, 1)
assert.True(fakeDocker.RemovedImages.Has(imageName(0)))
} }
func TestFreeSpaceRemoveByLeastRecentlyUsed(t *testing.T) { func TestFreeSpaceRemoveByLeastRecentlyUsed(t *testing.T) {
manager, fakeDocker, _ := newRealImageManager(ImageGCPolicy{}) manager, fakeRuntime, _ := newRealImageManager(ImageGCPolicy{})
fakeDocker.Images = []docker.APIImages{ fakeRuntime.ImageList = []container.Image{
makeImage(0, 1024), makeImage(0, 1024),
makeImage(1, 2048), makeImage(1, 2048),
} }
fakeDocker.ContainerList = []docker.APIContainers{ fakeRuntime.PodList = []*container.Pod{
{
Containers: []*container.Container{
makeContainer(0), makeContainer(0),
makeContainer(1), makeContainer(1),
},
},
} }
// Make 1 be more recently used than 0. // Make 1 be more recently used than 0.
require.NoError(t, manager.detectImages(zero)) require.NoError(t, manager.detectImages(zero))
fakeDocker.ContainerList = []docker.APIContainers{ fakeRuntime.PodList = []*container.Pod{
{
Containers: []*container.Container{
makeContainer(1), makeContainer(1),
},
},
} }
require.NoError(t, manager.detectImages(time.Now())) require.NoError(t, manager.detectImages(time.Now()))
fakeDocker.ContainerList = []docker.APIContainers{} fakeRuntime.PodList = []*container.Pod{
{
Containers: []*container.Container{},
},
}
require.NoError(t, manager.detectImages(time.Now())) require.NoError(t, manager.detectImages(time.Now()))
require.Equal(t, manager.imageRecordsLen(), 2) require.Equal(t, manager.imageRecordsLen(), 2)
@ -246,65 +274,66 @@ func TestFreeSpaceRemoveByLeastRecentlyUsed(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
require.NoError(t, err) require.NoError(t, err)
assert.EqualValues(1024, spaceFreed) assert.EqualValues(1024, spaceFreed)
assert.Len(fakeDocker.RemovedImages, 1) assert.Len(fakeRuntime.ImageList, 1)
assert.True(fakeDocker.RemovedImages.Has(imageName(0)))
} }
func TestFreeSpaceTiesBrokenByDetectedTime(t *testing.T) { func TestFreeSpaceTiesBrokenByDetectedTime(t *testing.T) {
manager, fakeDocker, _ := newRealImageManager(ImageGCPolicy{}) manager, fakeRuntime, _ := newRealImageManager(ImageGCPolicy{})
fakeDocker.Images = []docker.APIImages{ fakeRuntime.ImageList = []container.Image{
makeImage(0, 1024), makeImage(0, 1024),
} }
fakeDocker.ContainerList = []docker.APIContainers{ fakeRuntime.PodList = []*container.Pod{
{
Containers: []*container.Container{
makeContainer(0), makeContainer(0),
},
},
} }
// Make 1 more recently detected but used at the same time as 0. // Make 1 more recently detected but used at the same time as 0.
require.NoError(t, manager.detectImages(zero)) require.NoError(t, manager.detectImages(zero))
fakeDocker.Images = []docker.APIImages{ fakeRuntime.ImageList = []container.Image{
makeImage(0, 1024), makeImage(0, 1024),
makeImage(1, 2048), makeImage(1, 2048),
} }
fakeDocker.ContainerList = []docker.APIContainers{
makeContainer(0),
makeContainer(1),
}
require.NoError(t, manager.detectImages(time.Now())) require.NoError(t, manager.detectImages(time.Now()))
fakeDocker.ContainerList = []docker.APIContainers{} fakeRuntime.PodList = []*container.Pod{}
require.NoError(t, manager.detectImages(time.Now())) require.NoError(t, manager.detectImages(time.Now()))
require.Equal(t, manager.imageRecordsLen(), 2) require.Equal(t, manager.imageRecordsLen(), 2)
spaceFreed, err := manager.freeSpace(1024) spaceFreed, err := manager.freeSpace(1024)
assert := assert.New(t) assert := assert.New(t)
require.NoError(t, err) require.NoError(t, err)
assert.EqualValues(1024, spaceFreed) assert.EqualValues(2048, spaceFreed)
assert.Len(fakeDocker.RemovedImages, 1) assert.Len(fakeRuntime.ImageList, 1)
assert.True(fakeDocker.RemovedImages.Has(imageName(0)))
} }
func TestFreeSpaceImagesAlsoDoesLookupByRepoTags(t *testing.T) { func TestFreeSpaceImagesAlsoDoesLookupByRepoTags(t *testing.T) {
manager, fakeDocker, _ := newRealImageManager(ImageGCPolicy{}) manager, fakeRuntime, _ := newRealImageManager(ImageGCPolicy{})
fakeDocker.Images = []docker.APIImages{ fakeRuntime.ImageList = []container.Image{
makeImage(0, 1024), makeImage(0, 1024),
{ {
ID: "5678", ID: "5678",
RepoTags: []string{"potato", "salad"}, Tags: []string{"potato", "salad"},
VirtualSize: 2048, Size: 2048,
}, },
} }
fakeDocker.ContainerList = []docker.APIContainers{ fakeRuntime.PodList = []*container.Pod{
{
Containers: []*container.Container{
{ {
ID: "c5678", ID: "c5678",
Image: "salad", Image: "salad",
}, },
},
},
} }
spaceFreed, err := manager.freeSpace(1024) spaceFreed, err := manager.freeSpace(1024)
assert := assert.New(t) assert := assert.New(t)
require.NoError(t, err) require.NoError(t, err)
assert.EqualValues(1024, spaceFreed) assert.EqualValues(1024, spaceFreed)
assert.Len(fakeDocker.RemovedImages, 1) assert.Len(fakeRuntime.ImageList, 1)
assert.True(fakeDocker.RemovedImages.Has(imageName(0)))
} }
func TestGarbageCollectBelowLowThreshold(t *testing.T) { func TestGarbageCollectBelowLowThreshold(t *testing.T) {
@ -339,14 +368,14 @@ func TestGarbageCollectBelowSuccess(t *testing.T) {
HighThresholdPercent: 90, HighThresholdPercent: 90,
LowThresholdPercent: 80, LowThresholdPercent: 80,
} }
manager, fakeDocker, mockCadvisor := newRealImageManager(policy) manager, fakeRuntime, mockCadvisor := newRealImageManager(policy)
// Expect 95% usage and most of it gets freed. // Expect 95% usage and most of it gets freed.
mockCadvisor.On("DockerImagesFsInfo").Return(cadvisorApiV2.FsInfo{ mockCadvisor.On("DockerImagesFsInfo").Return(cadvisorApiV2.FsInfo{
Usage: 950, Usage: 950,
Capacity: 1000, Capacity: 1000,
}, nil) }, nil)
fakeDocker.Images = []docker.APIImages{ fakeRuntime.ImageList = []container.Image{
makeImage(0, 450), makeImage(0, 450),
} }
@ -358,14 +387,14 @@ func TestGarbageCollectNotEnoughFreed(t *testing.T) {
HighThresholdPercent: 90, HighThresholdPercent: 90,
LowThresholdPercent: 80, LowThresholdPercent: 80,
} }
manager, fakeDocker, mockCadvisor := newRealImageManager(policy) manager, fakeRuntime, mockCadvisor := newRealImageManager(policy)
// Expect 95% usage and little of it gets freed. // Expect 95% usage and little of it gets freed.
mockCadvisor.On("DockerImagesFsInfo").Return(cadvisorApiV2.FsInfo{ mockCadvisor.On("DockerImagesFsInfo").Return(cadvisorApiV2.FsInfo{
Usage: 950, Usage: 950,
Capacity: 1000, Capacity: 1000,
}, nil) }, nil)
fakeDocker.Images = []docker.APIImages{ fakeRuntime.ImageList = []container.Image{
makeImage(0, 50), makeImage(0, 50),
} }

View File

@ -237,10 +237,7 @@ func NewMainKubelet(
if err != nil { if err != nil {
return nil, err return nil, err
} }
imageManager, err := newImageManager(dockerClient, cadvisorInterface, recorder, nodeRef, imageGCPolicy)
if err != nil {
return nil, fmt.Errorf("failed to initialize image manager: %v", err)
}
diskSpaceManager, err := newDiskSpaceManager(cadvisorInterface, diskSpacePolicy) diskSpaceManager, err := newDiskSpaceManager(cadvisorInterface, diskSpacePolicy)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to initialize disk manager: %v", err) return nil, fmt.Errorf("failed to initialize disk manager: %v", err)
@ -278,7 +275,6 @@ func NewMainKubelet(
recorder: recorder, recorder: recorder,
cadvisor: cadvisorInterface, cadvisor: cadvisorInterface,
containerGC: containerGC, containerGC: containerGC,
imageManager: imageManager,
diskSpaceManager: diskSpaceManager, diskSpaceManager: diskSpaceManager,
statusManager: statusManager, statusManager: statusManager,
volumeManager: volumeManager, volumeManager: volumeManager,
@ -360,6 +356,13 @@ func NewMainKubelet(
return nil, fmt.Errorf("unsupported container runtime %q specified", containerRuntime) return nil, fmt.Errorf("unsupported container runtime %q specified", containerRuntime)
} }
// setup imageManager
imageManager, err := newImageManager(klet.containerRuntime, cadvisorInterface, recorder, nodeRef, imageGCPolicy)
if err != nil {
return nil, fmt.Errorf("failed to initialize image manager: %v", err)
}
klet.imageManager = imageManager
// Setup container manager, can fail if the devices hierarchy is not mounted // Setup container manager, can fail if the devices hierarchy is not mounted
// (it is required by Docker however). // (it is required by Docker however).
containerManager, err := newContainerManager(mounter, cadvisorInterface, dockerDaemonContainer, systemContainer, resourceContainer) containerManager, err := newContainerManager(mounter, cadvisorInterface, dockerDaemonContainer, systemContainer, resourceContainer)