Skip to content
This repository was archived by the owner on Mar 9, 2022. It is now read-only.

Commit 18ecffc

Browse files
committed
Manage unmanaged images in k8s.io namespace
Signed-off-by: Lantao Liu <[email protected]>
1 parent e5b175d commit 18ecffc

6 files changed

Lines changed: 79 additions & 39 deletions

File tree

pkg/server/events.go

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ import (
3434
ctrdutil "github.com/containerd/cri/pkg/containerd/util"
3535
"github.com/containerd/cri/pkg/store"
3636
containerstore "github.com/containerd/cri/pkg/store/container"
37-
imagestore "github.com/containerd/cri/pkg/store/image"
3837
sandboxstore "github.com/containerd/cri/pkg/store/sandbox"
3938
)
4039

@@ -54,14 +53,12 @@ const (
5453
// eventMonitor monitors containerd event and updates internal state correspondingly.
5554
// TODO(random-liu): Handle event for each container in a separate goroutine.
5655
type eventMonitor struct {
57-
containerStore *containerstore.Store
58-
sandboxStore *sandboxstore.Store
59-
imageStore *imagestore.Store
60-
ch <-chan *events.Envelope
61-
errCh <-chan error
62-
ctx context.Context
63-
cancel context.CancelFunc
64-
backOff *backOff
56+
c *criService
57+
ch <-chan *events.Envelope
58+
errCh <-chan error
59+
ctx context.Context
60+
cancel context.CancelFunc
61+
backOff *backOff
6562
}
6663

6764
type backOff struct {
@@ -84,16 +81,14 @@ type backOffQueue struct {
8481

8582
// Create new event monitor. New event monitor will start subscribing containerd event. All events
8683
// happen after it should be monitored.
87-
func newEventMonitor(c *containerstore.Store, s *sandboxstore.Store, i *imagestore.Store) *eventMonitor {
84+
func newEventMonitor(c *criService) *eventMonitor {
8885
// event subscribe doesn't need namespace.
8986
ctx, cancel := context.WithCancel(context.Background())
9087
return &eventMonitor{
91-
containerStore: c,
92-
sandboxStore: s,
93-
imageStore: i,
94-
ctx: ctx,
95-
cancel: cancel,
96-
backOff: newBackOff(),
88+
c: c,
89+
ctx: ctx,
90+
cancel: cancel,
91+
backOff: newBackOff(),
9792
}
9893
}
9994

@@ -206,7 +201,7 @@ func (em *eventMonitor) handleEvent(any interface{}) error {
206201
case *eventtypes.TaskExit:
207202
e := any.(*eventtypes.TaskExit)
208203
logrus.Infof("TaskExit event %+v", e)
209-
cntr, err := em.containerStore.Get(e.ContainerID)
204+
cntr, err := em.c.containerStore.Get(e.ContainerID)
210205
if err == nil {
211206
if err := handleContainerExit(ctx, e, cntr); err != nil {
212207
return errors.Wrap(err, "failed to handle container TaskExit event")
@@ -216,7 +211,7 @@ func (em *eventMonitor) handleEvent(any interface{}) error {
216211
return errors.Wrap(err, "can't find container for TaskExit event")
217212
}
218213
// Use GetAll to include sandbox in unknown state.
219-
sb, err := em.sandboxStore.GetAll(e.ContainerID)
214+
sb, err := em.c.sandboxStore.GetAll(e.ContainerID)
220215
if err == nil {
221216
if err := handleSandboxExit(ctx, e, sb); err != nil {
222217
return errors.Wrap(err, "failed to handle sandbox TaskExit event")
@@ -229,12 +224,12 @@ func (em *eventMonitor) handleEvent(any interface{}) error {
229224
case *eventtypes.TaskOOM:
230225
e := any.(*eventtypes.TaskOOM)
231226
logrus.Infof("TaskOOM event %+v", e)
232-
cntr, err := em.containerStore.Get(e.ContainerID)
227+
cntr, err := em.c.containerStore.Get(e.ContainerID)
233228
if err != nil {
234229
if err != store.ErrNotExist {
235230
return errors.Wrap(err, "can't find container for TaskOOM event")
236231
}
237-
if _, err = em.sandboxStore.Get(e.ContainerID); err != nil {
232+
if _, err = em.c.sandboxStore.Get(e.ContainerID); err != nil {
238233
if err != store.ErrNotExist {
239234
return errors.Wrap(err, "can't find sandbox for TaskOOM event")
240235
}
@@ -252,15 +247,15 @@ func (em *eventMonitor) handleEvent(any interface{}) error {
252247
case *eventtypes.ImageCreate:
253248
e := any.(*eventtypes.ImageCreate)
254249
logrus.Infof("ImageCreate event %+v", e)
255-
return em.imageStore.Update(ctx, e.Name)
250+
return em.c.updateImage(ctx, e.Name)
256251
case *eventtypes.ImageUpdate:
257252
e := any.(*eventtypes.ImageUpdate)
258253
logrus.Infof("ImageUpdate event %+v", e)
259-
return em.imageStore.Update(ctx, e.Name)
254+
return em.c.updateImage(ctx, e.Name)
260255
case *eventtypes.ImageDelete:
261256
e := any.(*eventtypes.ImageDelete)
262257
logrus.Infof("ImageDelete event %+v", e)
263-
return em.imageStore.Update(ctx, e.Name)
258+
return em.c.updateImage(ctx, e.Name)
264259
}
265260

266261
return nil

pkg/server/helpers.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,10 @@ const (
105105
containerKindSandbox = "sandbox"
106106
// containerKindContainer is a label value indicating container is application container
107107
containerKindContainer = "container"
108+
// imageLabelKey is the label key indicating the image is managed by cri plugin.
109+
imageLabelKey = criContainerdPrefix + ".image"
110+
// imageLabelValue is the label value indicating the image is managed by cri plugin.
111+
imageLabelValue = "managed"
108112
// sandboxMetadataExtension is an extension name that identify metadata of sandbox in CreateContainerRequest
109113
sandboxMetadataExtension = criContainerdPrefix + ".sandbox.metadata"
110114
// containerMetadataExtension is an extension name that identify metadata of container in CreateContainerRequest

pkg/server/image_load.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,11 @@ func (c *criService) LoadImage(ctx context.Context, r *api.LoadImageRequest) (*a
4444
}
4545
for _, repoTag := range repoTags {
4646
// Update image store to reflect the newest state in containerd.
47-
if err := c.imageStore.Update(ctx, repoTag); err != nil {
48-
return nil, errors.Wrapf(err, "failed to update image store %q", repoTag)
47+
// Image imported by importer.Import is not treated as managed
48+
// by the cri plugin, call `updateImage` to make it managed.
49+
// TODO(random-liu): Replace this with the containerd library (issue #909).
50+
if err := c.updateImage(ctx, repoTag); err != nil {
51+
return nil, errors.Wrapf(err, "update image store %q", repoTag)
4952
}
5053
logrus.Debugf("Imported image %q", repoTag)
5154
}

pkg/server/image_pull.go

Lines changed: 47 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -114,14 +114,16 @@ func (c *criService) PullImage(ctx context.Context, r *runtime.PullImageRequest)
114114
imageID := configDesc.Digest.String()
115115

116116
repoDigest, repoTag := getRepoDigestAndTag(namedRef, image.Target().Digest, isSchema1)
117-
for _, r := range []string{repoTag, repoDigest} {
117+
for _, r := range []string{imageID, repoTag, repoDigest} {
118118
if r == "" {
119119
continue
120120
}
121121
if err := c.createImageReference(ctx, r, image.Target()); err != nil {
122-
return nil, errors.Wrapf(err, "failed to update image reference %q", r)
122+
return nil, errors.Wrapf(err, "failed to create image reference %q", r)
123123
}
124124
// Update image store to reflect the newest state in containerd.
125+
// No need to use `updateImage`, because the image reference must
126+
// have been managed by the cri plugin.
125127
if err := c.imageStore.Update(ctx, r); err != nil {
126128
return nil, errors.Wrapf(err, "failed to update image store %q", r)
127129
}
@@ -174,20 +176,57 @@ func (c *criService) createImageReference(ctx context.Context, name string, desc
174176
img := containerdimages.Image{
175177
Name: name,
176178
Target: desc,
179+
// Add a label to indicate that the image is managed by the cri plugin.
180+
Labels: map[string]string{imageLabelKey: imageLabelValue},
177181
}
178182
// TODO(random-liu): Figure out which is the more performant sequence create then update or
179183
// update then create.
180-
_, err := c.client.ImageService().Create(ctx, img)
181-
if err == nil {
182-
return nil
183-
}
184-
if !errdefs.IsAlreadyExists(err) {
184+
oldImg, err := c.client.ImageService().Create(ctx, img)
185+
if err == nil || !errdefs.IsAlreadyExists(err) {
185186
return err
186187
}
187-
_, err = c.client.ImageService().Update(ctx, img, "target")
188+
if oldImg.Target.Digest == img.Target.Digest && oldImg.Labels[imageLabelKey] == imageLabelValue {
189+
return nil
190+
}
191+
_, err = c.client.ImageService().Update(ctx, img, "target", "labels")
188192
return err
189193
}
190194

195+
// updateImage updates image store to reflect the newest state of an image reference
196+
// in containerd. If the reference is not managed by the cri plugin, the function also
197+
// generates necessary metadata for the image and make it managed.
198+
func (c *criService) updateImage(ctx context.Context, r string) error {
199+
img, err := c.client.GetImage(ctx, r)
200+
if err != nil && !errdefs.IsNotFound(err) {
201+
return errors.Wrap(err, "get image by reference")
202+
}
203+
if err == nil && img.Labels()[imageLabelKey] != imageLabelValue {
204+
// Make sure the image has the image id as its unique
205+
// identifier that references the image in its lifetime.
206+
configDesc, err := img.Config(ctx)
207+
if err != nil {
208+
return errors.Wrap(err, "get image id")
209+
}
210+
id := configDesc.Digest.String()
211+
if err := c.createImageReference(ctx, id, img.Target()); err != nil {
212+
return errors.Wrapf(err, "create image id reference %q", id)
213+
}
214+
if err := c.imageStore.Update(ctx, id); err != nil {
215+
return errors.Wrapf(err, "update image store for %q", id)
216+
}
217+
// The image id is ready, add the label to mark the image as managed.
218+
if err := c.createImageReference(ctx, r, img.Target()); err != nil {
219+
return errors.Wrap(err, "create managed label")
220+
}
221+
}
222+
// If the image is not found, we should continue updating the cache,
223+
// so that the image can be removed from the cache.
224+
if err := c.imageStore.Update(ctx, r); err != nil {
225+
return errors.Wrapf(err, "update image store for %q", r)
226+
}
227+
return nil
228+
}
229+
191230
// credentials returns a credential function for docker resolver to use.
192231
func (c *criService) credentials(auth *runtime.AuthConfig) func(string) (string, string, error) {
193232
return func(host string) (string, string, error) {

pkg/server/restart.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ import (
3636

3737
cio "github.com/containerd/cri/pkg/server/io"
3838
containerstore "github.com/containerd/cri/pkg/store/container"
39-
imagestore "github.com/containerd/cri/pkg/store/image"
4039
sandboxstore "github.com/containerd/cri/pkg/store/sandbox"
4140
)
4241

@@ -96,7 +95,7 @@ func (c *criService) recover(ctx context.Context) error {
9695
if err != nil {
9796
return errors.Wrap(err, "failed to list images")
9897
}
99-
loadImages(ctx, c.imageStore, cImages, c.config.ContainerdConfig.Snapshotter)
98+
c.loadImages(ctx, cImages)
10099

101100
// It's possible that containerd containers are deleted unexpectedly. In that case,
102101
// we can't even get metadata, we should cleanup orphaned sandbox/container directories
@@ -411,8 +410,8 @@ func loadSandbox(ctx context.Context, cntr containerd.Container) (sandboxstore.S
411410
}
412411

413412
// loadImages loads images from containerd.
414-
func loadImages(ctx context.Context, store *imagestore.Store, cImages []containerd.Image,
415-
snapshotter string) {
413+
func (c *criService) loadImages(ctx context.Context, cImages []containerd.Image) {
414+
snapshotter := c.config.ContainerdConfig.Snapshotter
416415
for _, i := range cImages {
417416
ok, _, _, _, err := containerdimages.Check(ctx, i.ContentStore(), i.Target(), platforms.Default())
418417
if err != nil {
@@ -433,7 +432,7 @@ func loadImages(ctx context.Context, store *imagestore.Store, cImages []containe
433432
logrus.Warnf("The image %s is not unpacked.", i.Name())
434433
// TODO(random-liu): Consider whether we should try unpack here.
435434
}
436-
if err := store.Update(ctx, i.Name()); err != nil {
435+
if err := c.updateImage(ctx, i.Name()); err != nil {
437436
logrus.WithError(err).Warnf("Failed to update reference for image %q", i.Name())
438437
continue
439438
}

pkg/server/service.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ func NewCRIService(config criconfig.Config, client *containerd.Client) (CRIServi
157157
return nil, errors.Wrap(err, "failed to create stream server")
158158
}
159159

160-
c.eventMonitor = newEventMonitor(c.containerStore, c.sandboxStore, c.imageStore)
160+
c.eventMonitor = newEventMonitor(c)
161161

162162
return c, nil
163163
}

0 commit comments

Comments
 (0)