1
+ From 33ac7f6f513934a0ef59cc6739eee0efdac3631c Mon Sep 17 00:00:00 2001
2
+ From: Mitch Zhu <
[email protected] >
3
+ Date: Fri, 22 Nov 2024 20:41:27 +0000
4
+ Subject: [PATCH] Enhance snapshot handling and CRI runtime compatibility for
5
+ tardev-snapshotter
6
+
7
+ ---
8
+ client/image.go | 4 +-
9
+ internal/cri/server/container_status_test.go | 2 +-
10
+ internal/cri/server/images/image_pull.go | 37 +++++++++++--------
11
+ internal/cri/server/podsandbox/controller.go | 2 +-
12
+ internal/cri/server/podsandbox/sandbox_run.go | 30 ++++++++-------
13
+ internal/cri/server/service.go | 2 +-
14
+ internal/cri/store/image/image.go | 29 ++++++++++++---
15
+ 7 files changed, 68 insertions(+), 38 deletions(-)
16
+
17
+ diff --git a/client/image.go b/client/image.go
18
+ index 355bcba..791db88 100644
19
+ --- a/client/image.go
20
+ +++ b/client/image.go
21
+ @@ -31,6 +31,7 @@ import (
22
+ "github.com/containerd/containerd/v2/internal/kmutex"
23
+ "github.com/containerd/containerd/v2/pkg/labels"
24
+ "github.com/containerd/containerd/v2/pkg/rootfs"
25
+ + "github.com/containerd/containerd/v2/pkg/snapshotters"
26
+ "github.com/containerd/errdefs"
27
+ "github.com/containerd/platforms"
28
+ "github.com/opencontainers/go-digest"
29
+ @@ -333,7 +334,8 @@ func (i *image) Unpack(ctx context.Context, snapshotterName string, opts ...Unpa
30
+ }
31
+
32
+ for _, layer := range layers {
33
+ - unpacked, err = rootfs.ApplyLayerWithOpts(ctx, layer, chain, sn, a, config.SnapshotOpts, config.ApplyOpts)
34
+ + snOpts := append(config.SnapshotOpts, snapshots.WithLabels(map[string]string{snapshotters.TargetLayerDigestLabel: layer.Blob.Digest.String()}))
35
+ + unpacked, err = rootfs.ApplyLayerWithOpts(ctx, layer, chain, sn, a, snOpts, config.ApplyOpts)
36
+ if err != nil {
37
+ return fmt.Errorf("apply layer error for %q: %w", i.Name(), err)
38
+ }
39
+ diff --git a/internal/cri/server/container_status_test.go b/internal/cri/server/container_status_test.go
40
+ index 05b1650..71dcc10 100644
41
+ --- a/internal/cri/server/container_status_test.go
42
+ +++ b/internal/cri/server/container_status_test.go
43
+ @@ -302,7 +302,7 @@ func (s *fakeImageService) LocalResolve(refOrID string) (imagestore.Image, error
44
+
45
+ func (s *fakeImageService) ImageFSPaths() map[string]string { return make(map[string]string) }
46
+
47
+ - func (s *fakeImageService) PullImage(context.Context, string, func(string) (string, string, error), *runtime.PodSandboxConfig, string) (string, error) {
48
+ + func (s *fakeImageService) PullImage(context.Context, string, func(string) (string, string, error), *runtime.PodSandboxConfig, string, string) (string, error) {
49
+ return "", errors.New("not implemented")
50
+ }
51
+
52
+ diff --git a/internal/cri/server/images/image_pull.go b/internal/cri/server/images/image_pull.go
53
+ index e59b88b..f9c90b7 100644
54
+ --- a/internal/cri/server/images/image_pull.go
55
+ +++ b/internal/cri/server/images/image_pull.go
56
+ @@ -96,6 +96,15 @@ import (
57
+
58
+ // PullImage pulls an image with authentication config.
59
+ func (c *GRPCCRIImageService) PullImage(ctx context.Context, r *runtime.PullImageRequest) (_ *runtime.PullImageResponse, err error) {
60
+ + imageRef := r.GetImage().GetImage()
61
+ + snapshotter, err := c.snapshotterFromPodSandboxConfig(ctx, imageRef, r.SandboxConfig, r.GetImage().GetRuntimeHandler())
62
+ + if err != nil {
63
+ + return nil, err
64
+ + }
65
+ + return c.pullImage(ctx, r, snapshotter)
66
+ + }
67
+ +
68
+ + func (c *GRPCCRIImageService) pullImage(ctx context.Context, r *runtime.PullImageRequest, snapshotter string) (_ *runtime.PullImageResponse, err error) {
69
+
70
+ imageRef := r.GetImage().GetImage()
71
+
72
+ @@ -110,14 +119,14 @@ func (c *GRPCCRIImageService) PullImage(ctx context.Context, r *runtime.PullImag
73
+ return ParseAuth(hostauth, host)
74
+ }
75
+
76
+ - ref, err := c.CRIImageService.PullImage(ctx, imageRef, credentials, r.SandboxConfig, r.GetImage().GetRuntimeHandler())
77
+ + ref, err := c.CRIImageService.PullImage(ctx, imageRef, credentials, r.SandboxConfig, r.GetImage().GetRuntimeHandler(), snapshotter)
78
+ if err != nil {
79
+ return nil, err
80
+ }
81
+ return &runtime.PullImageResponse{ImageRef: ref}, nil
82
+ }
83
+
84
+ - func (c *CRIImageService) PullImage(ctx context.Context, name string, credentials func(string) (string, string, error), sandboxConfig *runtime.PodSandboxConfig, runtimeHandler string) (_ string, err error) {
85
+ + func (c *CRIImageService) PullImage(ctx context.Context, name string, credentials func(string) (string, string, error), sandboxConfig *runtime.PodSandboxConfig, runtimeHandler string, snapshotter string) (_ string, err error) {
86
+ span := tracing.SpanFromContext(ctx)
87
+ defer func() {
88
+ // TODO: add domain label for imagePulls metrics, and we may need to provide a mechanism
89
+ @@ -167,10 +176,6 @@ func (c *CRIImageService) PullImage(ctx context.Context, name string, credential
90
+ )
91
+
92
+ defer pcancel()
93
+ - snapshotter, err := c.snapshotterFromPodSandboxConfig(ctx, ref, sandboxConfig)
94
+ - if err != nil {
95
+ - return "", err
96
+ - }
97
+ log.G(ctx).Debugf("PullImage %q with snapshotter %s", ref, snapshotter)
98
+ span.SetAttributes(
99
+ tracing.Attribute("image.ref", ref),
100
+ @@ -761,17 +766,19 @@ func (rt *pullRequestReporterRoundTripper) RoundTrip(req *http.Request) (*http.R
101
+ // Once we know the runtime, try to override default snapshotter if it is set for this runtime.
102
+ // See https://github.com/containerd/containerd/issues/6657
103
+ func (c *CRIImageService) snapshotterFromPodSandboxConfig(ctx context.Context, imageRef string,
104
+ - s *runtime.PodSandboxConfig) (string, error) {
105
+ + s *runtime.PodSandboxConfig, runtimeHandler string) (string, error) {
106
+ snapshotter := c.config.Snapshotter
107
+ - if s == nil || s.Annotations == nil {
108
+ - return snapshotter, nil
109
+ - }
110
+
111
+ - // TODO(kiashok): honor the new CRI runtime handler field added to v0.29.0
112
+ - // for image pull per runtime class support.
113
+ - runtimeHandler, ok := s.Annotations[annotations.RuntimeHandler]
114
+ - if !ok {
115
+ - return snapshotter, nil
116
+ + if runtimeHandler == "" {
117
+ + if s == nil || s.Annotations == nil {
118
+ + return snapshotter, nil
119
+ + } else {
120
+ + ok := false
121
+ + runtimeHandler, ok = s.Annotations[annotations.RuntimeHandler]
122
+ + if !ok {
123
+ + return snapshotter, nil
124
+ + }
125
+ + }
126
+ }
127
+
128
+ // TODO: Ensure error is returned if runtime not found?
129
+ diff --git a/internal/cri/server/podsandbox/controller.go b/internal/cri/server/podsandbox/controller.go
130
+ index a185a4c..8fd032b 100644
131
+ --- a/internal/cri/server/podsandbox/controller.go
132
+ +++ b/internal/cri/server/podsandbox/controller.go
133
+ @@ -110,7 +110,7 @@ type RuntimeService interface {
134
+ type ImageService interface {
135
+ LocalResolve(refOrID string) (imagestore.Image, error)
136
+ GetImage(id string) (imagestore.Image, error)
137
+ - PullImage(ctx context.Context, name string, creds func(string) (string, string, error), sc *runtime.PodSandboxConfig, runtimeHandler string) (string, error)
138
+ + PullImage(ctx context.Context, name string, creds func(string) (string, string, error), sc *runtime.PodSandboxConfig, runtimeHandler string, snapshotter string) (string, error)
139
+ RuntimeSnapshotter(ctx context.Context, ociRuntime criconfig.Runtime) string
140
+ PinnedImage(string) string
141
+ }
142
+ diff --git a/internal/cri/server/podsandbox/sandbox_run.go b/internal/cri/server/podsandbox/sandbox_run.go
143
+ index 53d949f..b296061 100644
144
+ --- a/internal/cri/server/podsandbox/sandbox_run.go
145
+ +++ b/internal/cri/server/podsandbox/sandbox_run.go
146
+ @@ -77,23 +77,25 @@ func (c *Controller) Start(ctx context.Context, id string) (cin sandbox.Controll
147
+
148
+ sandboxImage := c.getSandboxImageName()
149
+ // Ensure sandbox container image snapshot.
150
+ - image, err := c.ensureImageExists(ctx, sandboxImage, config, metadata.RuntimeHandler)
151
+ + ociRuntime, err := c.config.GetSandboxRuntime(config, metadata.RuntimeHandler)
152
+ if err != nil {
153
+ - return cin, fmt.Errorf("failed to get sandbox image %q: %w", sandboxImage, err)
154
+ + return cin, fmt.Errorf("failed to get sandbox runtime: %w", err)
155
+ }
156
+ + log.G(ctx).WithField("podsandboxid", id).Debugf("use OCI runtime %+v", ociRuntime)
157
+
158
+ - containerdImage, err := c.toContainerdImage(ctx, *image)
159
+ + labels["oci_runtime_type"] = ociRuntime.Type
160
+ +
161
+ + snapshotter := c.imageService.RuntimeSnapshotter(ctx, ociRuntime)
162
+ +
163
+ + image, err := c.ensureImageExists(ctx, sandboxImage, config, metadata.RuntimeHandler, snapshotter)
164
+ if err != nil {
165
+ - return cin, fmt.Errorf("failed to get image from containerd %q: %w", image.ID, err)
166
+ + return cin, fmt.Errorf("failed to get sandbox image %q: %w", sandboxImage, err)
167
+ }
168
+
169
+ - ociRuntime, err := c.config.GetSandboxRuntime(config, metadata.RuntimeHandler)
170
+ + containerdImage, err := c.toContainerdImage(ctx, *image)
171
+ if err != nil {
172
+ - return cin, fmt.Errorf("failed to get sandbox runtime: %w", err)
173
+ + return cin, fmt.Errorf("failed to get image from containerd %q: %w", image.ID, err)
174
+ }
175
+ - log.G(ctx).WithField("podsandboxid", id).Debugf("use OCI runtime %+v", ociRuntime)
176
+ -
177
+ - labels["oci_runtime_type"] = ociRuntime.Type
178
+
179
+ // Create sandbox container root directories.
180
+ sandboxRootDir := c.getSandboxRootDir(id)
181
+ @@ -173,7 +175,7 @@ func (c *Controller) Start(ctx context.Context, id string) (cin sandbox.Controll
182
+ snapshotterOpt = append(snapshotterOpt, extraSOpts...)
183
+
184
+ opts := []containerd.NewContainerOpts{
185
+ - containerd.WithSnapshotter(c.imageService.RuntimeSnapshotter(ctx, ociRuntime)),
186
+ + containerd.WithSnapshotter(snapshotter),
187
+ customopts.WithNewSnapshot(id, containerdImage, snapshotterOpt...),
188
+ containerd.WithSpec(spec, specOpts...),
189
+ containerd.WithContainerLabels(sandboxLabels),
190
+ @@ -299,17 +301,19 @@ func (c *Controller) Create(_ctx context.Context, info sandbox.Sandbox, opts ...
191
+ return c.store.Save(podSandbox)
192
+ }
193
+
194
+ - func (c *Controller) ensureImageExists(ctx context.Context, ref string, config *runtime.PodSandboxConfig, runtimeHandler string) (*imagestore.Image, error) {
195
+ + func (c *Controller) ensureImageExists(ctx context.Context, ref string, config *runtime.PodSandboxConfig, runtimeHandler string, snapshotter string) (*imagestore.Image, error) {
196
+ image, err := c.imageService.LocalResolve(ref)
197
+ if err != nil && !errdefs.IsNotFound(err) {
198
+ return nil, fmt.Errorf("failed to get image %q: %w", ref, err)
199
+ }
200
+ if err == nil {
201
+ - return &image, nil
202
+ + if _, ok := image.Snapshotters[snapshotter]; ok {
203
+ + return &image, nil
204
+ + }
205
+ }
206
+ // Pull image to ensure the image exists
207
+ // TODO: Cleaner interface
208
+ - imageID, err := c.imageService.PullImage(ctx, ref, nil, config, runtimeHandler)
209
+ + imageID, err := c.imageService.PullImage(ctx, ref, nil, config, runtimeHandler, snapshotter)
210
+ if err != nil {
211
+ return nil, fmt.Errorf("failed to pull image %q: %w", ref, err)
212
+ }
213
+ diff --git a/internal/cri/server/service.go b/internal/cri/server/service.go
214
+ index 37d66f0..5d1546e 100644
215
+ --- a/internal/cri/server/service.go
216
+ +++ b/internal/cri/server/service.go
217
+ @@ -97,7 +97,7 @@ type RuntimeService interface {
218
+ type ImageService interface {
219
+ RuntimeSnapshotter(ctx context.Context, ociRuntime criconfig.Runtime) string
220
+
221
+ - PullImage(ctx context.Context, name string, credentials func(string) (string, string, error), sandboxConfig *runtime.PodSandboxConfig, runtimeHandler string) (string, error)
222
+ + PullImage(ctx context.Context, name string, credentials func(string) (string, string, error), sandboxConfig *runtime.PodSandboxConfig, runtimeHandler string, snapshotter string) (string, error)
223
+ UpdateImage(ctx context.Context, r string) error
224
+
225
+ CheckImages(ctx context.Context) error
226
+ diff --git a/internal/cri/store/image/image.go b/internal/cri/store/image/image.go
227
+ index 5887e75..43ecf0d 100644
228
+ --- a/internal/cri/store/image/image.go
229
+ +++ b/internal/cri/store/image/image.go
230
+ @@ -20,6 +20,7 @@ import (
231
+ "context"
232
+ "encoding/json"
233
+ "fmt"
234
+ + "strings"
235
+ "sync"
236
+
237
+ "github.com/containerd/containerd/v2/core/content"
238
+ @@ -53,6 +54,8 @@ type Image struct {
239
+ ImageSpec imagespec.Image
240
+ // Pinned image to prevent it from garbage collection
241
+ Pinned bool
242
+ + // Snapshotters is a map whose keys are snapshotters for which this image has a snapshot.
243
+ + Snapshotters map[string]struct{}
244
+ }
245
+
246
+ // Getter is used to get images but does not make changes
247
+ @@ -170,6 +173,19 @@ func (s *Store) getImage(ctx context.Context, i images.Image) (*Image, error) {
248
+ return nil, fmt.Errorf("read image config from content store: %w", err)
249
+ }
250
+
251
+ + info, err := s.provider.Info(ctx, desc.Digest)
252
+ + if err != nil {
253
+ + return nil, fmt.Errorf("get content store config info: %w", err)
254
+ + }
255
+ +
256
+ + snapshotters := make(map[string]struct{})
257
+ + for label := range info.Labels {
258
+ + const Prefix = "containerd.io/gc.ref.snapshot."
259
+ + if strings.HasPrefix(label, Prefix) {
260
+ + snapshotters[label[len(Prefix):]] = struct{}{}
261
+ + }
262
+ + }
263
+ +
264
+ var spec imagespec.Image
265
+ if err := json.Unmarshal(blob, &spec); err != nil {
266
+ return nil, fmt.Errorf("unmarshal image config %s: %w", blob, err)
267
+ @@ -178,12 +194,13 @@ func (s *Store) getImage(ctx context.Context, i images.Image) (*Image, error) {
268
+ pinned := i.Labels[labels.PinnedImageLabelKey] == labels.PinnedImageLabelValue
269
+
270
+ return &Image{
271
+ - ID: id,
272
+ - References: []string{i.Name},
273
+ - ChainID: chainID.String(),
274
+ - Size: size,
275
+ - ImageSpec: spec,
276
+ - Pinned: pinned,
277
+ + ID: id,
278
+ + References: []string{i.Name},
279
+ + ChainID: chainID.String(),
280
+ + Size: size,
281
+ + ImageSpec: spec,
282
+ + Pinned: pinned,
283
+ + Snapshotters: snapshotters,
284
+ }, nil
285
+
286
+ }
287
+ - -
288
+ 2.34.1
0 commit comments