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

Commit 98bc3ed

Browse files
authored
Merge pull request #48 from Random-Liu/apply-sandbox-image-config
Apply sandbox image config
2 parents a49f66e + 6eb1ddb commit 98bc3ed

File tree

11 files changed

+218
-91
lines changed

11 files changed

+218
-91
lines changed

pkg/server/events.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ func (c *criContainerdService) startEventMonitor() error {
4949
func (c *criContainerdService) handleEventStream(events execution.ContainerService_EventsClient) {
5050
// TODO(random-liu): [P1] Should backoff on this error, or else this will
5151
// cause a busy loop.
52+
// TODO(random-liu): Handle io.EOF.
5253
e, err := events.Recv()
5354
if err != nil {
5455
glog.Errorf("Failed to receive event: %v", err)

pkg/server/helpers.go

Lines changed: 54 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ const (
5555
)
5656

5757
const (
58+
// defaultSandboxImage is the image used by sandbox container.
59+
// TODO(random-liu): [P1] Build schema 2 pause image and use it here.
60+
defaultSandboxImage = "gcr.io/google.com/noogler-kubernetes/pause-amd64:3.0"
5861
// relativeRootfsPath is the rootfs path relative to bundle path.
5962
relativeRootfsPath = "rootfs"
6063
// defaultRuntime is the runtime to use in containerd. We may support
@@ -305,31 +308,39 @@ func getRepoDigestAndTag(namedRef reference.Named, digest imagedigest.Digest) (s
305308
return repoDigest, repoTag
306309
}
307310

308-
// localResolve resolves image reference to image id locally. It returns empty string
309-
// without error if the reference doesn't exist.
310-
func (c *criContainerdService) localResolve(ctx context.Context, ref string) (string, error) {
311+
// localResolve resolves image reference locally and returns corresponding image metadata. It returns
312+
// nil without error if the reference doesn't exist.
313+
func (c *criContainerdService) localResolve(ctx context.Context, ref string) (*metadata.ImageMetadata, error) {
311314
_, err := imagedigest.Parse(ref)
312-
if err == nil {
313-
return ref, nil
314-
}
315-
// ref is not image id, try to resolve it locally.
316-
normalized, err := normalizeImageRef(ref)
317315
if err != nil {
318-
return "", fmt.Errorf("invalid image reference %q: %v", ref, err)
319-
}
320-
image, err := c.imageStoreService.Get(ctx, normalized.String())
321-
if err != nil {
322-
if images.IsNotFound(err) {
323-
return "", nil
316+
// ref is not image id, try to resolve it locally.
317+
normalized, err := normalizeImageRef(ref)
318+
if err != nil {
319+
return nil, fmt.Errorf("invalid image reference %q: %v", ref, err)
320+
}
321+
image, err := c.imageStoreService.Get(ctx, normalized.String())
322+
if err != nil {
323+
if images.IsNotFound(err) {
324+
return nil, nil
325+
}
326+
return nil, fmt.Errorf("an error occurred when getting image %q from containerd image store: %v",
327+
normalized.String(), err)
328+
}
329+
desc, err := image.Config(ctx, c.contentStoreService)
330+
if err != nil {
331+
return nil, fmt.Errorf("failed to get image config descriptor: %v", err)
324332
}
325-
return "", fmt.Errorf("an error occurred when getting image %q from containerd image store: %v",
326-
normalized.String(), err)
333+
ref = desc.Digest.String()
327334
}
328-
desc, err := image.Config(ctx, c.contentStoreService)
335+
imageID := ref
336+
meta, err := c.imageMetadataStore.Get(imageID)
329337
if err != nil {
330-
return "", fmt.Errorf("failed to get image config descriptor: %v", err)
338+
if metadata.IsNotExistError(err) {
339+
return nil, nil
340+
}
341+
return nil, fmt.Errorf("failed to get image %q metadata: %v", imageID, err)
331342
}
332-
return desc.Digest.String(), nil
343+
return meta, nil
333344
}
334345

335346
// getUserFromImage gets uid or user name of the image user.
@@ -350,3 +361,27 @@ func getUserFromImage(user string) (*int64, string) {
350361
// If user is a numeric uid.
351362
return &uid, ""
352363
}
364+
365+
// ensureImageExists returns corresponding metadata of the image reference, if image is not
366+
// pulled yet, the function will pull the image.
367+
func (c *criContainerdService) ensureImageExists(ctx context.Context, ref string) (*metadata.ImageMetadata, error) {
368+
meta, err := c.localResolve(ctx, ref)
369+
if err != nil {
370+
return nil, fmt.Errorf("failed to resolve image %q: %v", ref, err)
371+
}
372+
if meta != nil {
373+
return meta, nil
374+
}
375+
// Pull image to ensure the image exists
376+
resp, err := c.PullImage(ctx, &runtime.PullImageRequest{Image: &runtime.ImageSpec{Image: ref}})
377+
if err != nil {
378+
return nil, fmt.Errorf("failed to pull image %q: %v", ref, err)
379+
}
380+
imageID := resp.GetImageRef()
381+
meta, err = c.imageMetadataStore.Get(imageID)
382+
if err != nil {
383+
// It's still possible that someone removed the image right after it is pulled.
384+
return nil, fmt.Errorf("failed to get image %q metadata after pulling: %v", imageID, err)
385+
}
386+
return meta, nil
387+
}

pkg/server/image_remove.go

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -41,21 +41,14 @@ func (c *criContainerdService) RemoveImage(ctx context.Context, r *runtime.Remov
4141
glog.V(2).Infof("RemoveImage %q returns successfully", r.GetImage().GetImage())
4242
}
4343
}()
44-
imageID, err := c.localResolve(ctx, r.GetImage().GetImage())
44+
meta, err := c.localResolve(ctx, r.GetImage().GetImage())
4545
if err != nil {
4646
return nil, fmt.Errorf("can not resolve %q locally: %v", r.GetImage().GetImage(), err)
4747
}
48-
if imageID == "" {
48+
if meta == nil {
4949
// return empty without error when image not found.
5050
return &runtime.RemoveImageResponse{}, nil
5151
}
52-
meta, err := c.imageMetadataStore.Get(imageID)
53-
if err != nil {
54-
if metadata.IsNotExistError(err) {
55-
return &runtime.RemoveImageResponse{}, nil
56-
}
57-
return nil, fmt.Errorf("an error occurred when get image %q metadata: %v", imageID, err)
58-
}
5952
// Also include repo digest, because if user pull image with digest,
6053
// there will also be a corresponding repo digest reference.
6154
for _, ref := range append(meta.RepoTags, meta.RepoDigests...) {
@@ -65,14 +58,14 @@ func (c *criContainerdService) RemoveImage(ctx context.Context, r *runtime.Remov
6558
if err == nil || images.IsNotFound(err) {
6659
continue
6760
}
68-
return nil, fmt.Errorf("failed to delete image reference %q for image %q: %v", ref, imageID, err)
61+
return nil, fmt.Errorf("failed to delete image reference %q for image %q: %v", ref, meta.ID, err)
6962
}
70-
err = c.imageMetadataStore.Delete(imageID)
63+
err = c.imageMetadataStore.Delete(meta.ID)
7164
if err != nil {
7265
if metadata.IsNotExistError(err) {
7366
return &runtime.RemoveImageResponse{}, nil
7467
}
75-
return nil, fmt.Errorf("an error occurred when delete image %q matadata: %v", imageID, err)
68+
return nil, fmt.Errorf("an error occurred when delete image %q matadata: %v", meta.ID, err)
7669
}
7770
return &runtime.RemoveImageResponse{}, nil
7871
}

pkg/server/image_status.go

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@ import (
2222
"github.com/golang/glog"
2323
"golang.org/x/net/context"
2424
runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1"
25-
26-
"github.com/kubernetes-incubator/cri-containerd/pkg/metadata"
2725
)
2826

2927
// ImageStatus returns the status of the image, returns nil if the image isn't present.
@@ -37,23 +35,14 @@ func (c *criContainerdService) ImageStatus(ctx context.Context, r *runtime.Image
3735
r.GetImage().GetImage(), retRes.GetImage())
3836
}
3937
}()
40-
imageID, err := c.localResolve(ctx, r.GetImage().GetImage())
38+
meta, err := c.localResolve(ctx, r.GetImage().GetImage())
4139
if err != nil {
4240
return nil, fmt.Errorf("can not resolve %q locally: %v", r.GetImage().GetImage(), err)
4341
}
44-
if imageID == "" {
42+
if meta == nil {
4543
// return empty without error when image not found.
4644
return &runtime.ImageStatusResponse{}, nil
4745
}
48-
49-
meta, err := c.imageMetadataStore.Get(imageID)
50-
if err != nil {
51-
if metadata.IsNotExistError(err) {
52-
return &runtime.ImageStatusResponse{}, nil
53-
}
54-
return nil, fmt.Errorf("an error occurred during get image %q metadata: %v",
55-
imageID, err)
56-
}
5746
// TODO(random-liu): [P0] Make sure corresponding snapshot exists. What if snapshot
5847
// doesn't exist?
5948
runtimeImage := &runtime.Image{

pkg/server/sandbox_remove.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ func (c *criContainerdService) RemovePodSandbox(ctx context.Context, r *runtime.
3535
glog.V(2).Infof("RemovePodSandbox for sandbox %q", r.GetPodSandboxId())
3636
defer func() {
3737
if retErr == nil {
38-
glog.V(2).Info("RemovePodSandbox %q returns successfully", r.GetPodSandboxId())
38+
glog.V(2).Infof("RemovePodSandbox %q returns successfully", r.GetPodSandboxId())
3939
}
4040
}()
4141

@@ -65,6 +65,7 @@ func (c *criContainerdService) RemovePodSandbox(ctx context.Context, r *runtime.
6565
return nil, fmt.Errorf("sandbox container %q is not fully stopped", id)
6666
}
6767

68+
// TODO(random-liu): [P0] Cleanup snapshot after switching to new snapshot api.
6869
// TODO(random-liu): [P0] Cleanup shm created in RunPodSandbox.
6970
// TODO(random-liu): [P1] Remove permanent namespace once used.
7071

pkg/server/sandbox_run.go

Lines changed: 49 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,18 @@ import (
2121
"fmt"
2222
"io"
2323
"io/ioutil"
24+
"strings"
2425
"time"
2526

27+
"github.com/containerd/containerd/api/services/execution"
28+
rootfsapi "github.com/containerd/containerd/api/services/rootfs"
2629
prototypes "github.com/gogo/protobuf/types"
2730
"github.com/golang/glog"
31+
imagedigest "github.com/opencontainers/go-digest"
32+
imagespec "github.com/opencontainers/image-spec/specs-go/v1"
2833
runtimespec "github.com/opencontainers/runtime-spec/specs-go"
2934
"github.com/opencontainers/runtime-tools/generate"
3035
"golang.org/x/net/context"
31-
32-
"github.com/containerd/containerd/api/services/execution"
33-
"github.com/containerd/containerd/api/types/mount"
34-
3536
runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1"
3637

3738
"github.com/kubernetes-incubator/cri-containerd/pkg/metadata"
@@ -81,10 +82,22 @@ func (c *criContainerdService) RunPodSandbox(ctx context.Context, r *runtime.Run
8182
Config: config,
8283
}
8384

84-
// TODO(random-liu): [P0] Ensure pause image snapshot, apply default image config
85-
// and get snapshot mounts.
86-
// Use fixed rootfs path and sleep command.
87-
const rootPath = "/"
85+
// Ensure sandbox container image snapshot.
86+
imageMeta, err := c.ensureImageExists(ctx, c.sandboxImage)
87+
if err != nil {
88+
return nil, fmt.Errorf("failed to get sandbox image %q: %v", defaultSandboxImage, err)
89+
}
90+
prepareResp, err := c.rootfsService.Prepare(ctx, &rootfsapi.PrepareRequest{
91+
Name: id,
92+
// We are sure that ChainID must be a digest.
93+
ChainID: imagedigest.Digest(imageMeta.ChainID),
94+
Readonly: true,
95+
})
96+
if err != nil {
97+
return nil, fmt.Errorf("failed to prepare sandbox rootfs %q: %v", imageMeta.ChainID, err)
98+
}
99+
// TODO(random-liu): [P0] Cleanup snapshot on failure after switching to new rootfs api.
100+
rootfsMounts := prepareResp.Mounts
88101

89102
// Create sandbox container root directory.
90103
// Prepare streaming named pipe.
@@ -124,7 +137,10 @@ func (c *criContainerdService) RunPodSandbox(ctx context.Context, r *runtime.Run
124137
}
125138

126139
// Start sandbox container.
127-
spec := c.generateSandboxContainerSpec(id, config)
140+
spec, err := c.generateSandboxContainerSpec(id, config, imageMeta.Config)
141+
if err != nil {
142+
return nil, fmt.Errorf("failed to generate sandbox container spec: %v", err)
143+
}
128144
rawSpec, err := json.Marshal(spec)
129145
if err != nil {
130146
return nil, fmt.Errorf("failed to marshal oci spec %+v: %v", spec, err)
@@ -137,16 +153,7 @@ func (c *criContainerdService) RunPodSandbox(ctx context.Context, r *runtime.Run
137153
Value: rawSpec,
138154
},
139155
// TODO(random-liu): [P0] Get rootfs mount from containerd.
140-
Rootfs: []*mount.Mount{
141-
{
142-
Type: "bind",
143-
Source: rootPath,
144-
Options: []string{
145-
"rw",
146-
"rbind",
147-
},
148-
},
149-
},
156+
Rootfs: rootfsMounts,
150157
Runtime: defaultRuntime,
151158
// No stdin for sandbox container.
152159
Stdout: stdout,
@@ -205,19 +212,34 @@ func (c *criContainerdService) RunPodSandbox(ctx context.Context, r *runtime.Run
205212
return &runtime.RunPodSandboxResponse{PodSandboxId: id}, nil
206213
}
207214

208-
func (c *criContainerdService) generateSandboxContainerSpec(id string, config *runtime.PodSandboxConfig) *runtimespec.Spec {
209-
// TODO(random-liu): [P0] Get command from image config.
210-
pauseCommand := []string{"sh", "-c", "while true; do sleep 1000000000; done"}
211-
215+
func (c *criContainerdService) generateSandboxContainerSpec(id string, config *runtime.PodSandboxConfig,
216+
imageConfig *imagespec.ImageConfig) (*runtimespec.Spec, error) {
212217
// Creates a spec Generator with the default spec.
213218
// TODO(random-liu): [P1] Compare the default settings with docker and containerd default.
214219
g := generate.New()
215220

216-
// Set relative root path.
217-
g.SetRootPath(relativeRootfsPath)
221+
// Apply default config from image config.
222+
for _, e := range imageConfig.Env {
223+
kv := strings.Split(e, "=")
224+
if len(kv) != 2 {
225+
return nil, fmt.Errorf("invalid environment variable in image config %+v", imageConfig)
226+
}
227+
g.AddProcessEnv(kv[0], kv[1])
228+
}
218229

230+
if imageConfig.WorkingDir != "" {
231+
g.SetProcessCwd(imageConfig.WorkingDir)
232+
}
233+
234+
if len(imageConfig.Entrypoint) == 0 {
235+
// Pause image must have entrypoint.
236+
return nil, fmt.Errorf("invalid empty entrypoint in image config %+v", imageConfig)
237+
}
219238
// Set process commands.
220-
g.SetProcessArgs(pauseCommand)
239+
g.SetProcessArgs(append(imageConfig.Entrypoint, imageConfig.Cmd...))
240+
241+
// Set relative root path.
242+
g.SetRootPath(relativeRootfsPath)
221243

222244
// Make root of sandbox container read-only.
223245
g.SetRootReadonly(true)
@@ -276,5 +298,5 @@ func (c *criContainerdService) generateSandboxContainerSpec(id string, config *r
276298

277299
// TODO(random-liu): [P1] Set default sandbox container resource limit.
278300

279-
return g.Spec()
301+
return g.Spec(), nil
280302
}

0 commit comments

Comments
 (0)