Skip to content

Commit fc57be7

Browse files
feat(enrich): improve containerd image info enrich
Make the image info query in containerd enrichment more robust. Procedure now begins by first querying the containerd image service, and only then using the cri directly as a fallback. Additionally, fix a typo in the CRI query which appended the image name as its digest, even when found.
1 parent cb72aed commit fc57be7

File tree

1 file changed

+69
-18
lines changed

1 file changed

+69
-18
lines changed

pkg/containers/runtime/containerd.go

Lines changed: 69 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66

77
"github.com/containerd/containerd"
88
"github.com/containerd/containerd/containers"
9+
"github.com/containerd/containerd/images"
910
"github.com/containerd/containerd/namespaces"
1011
"google.golang.org/grpc"
1112
"google.golang.org/grpc/credentials/insecure"
@@ -17,12 +18,15 @@ import (
1718

1819
type containerdEnricher struct {
1920
containers containers.Store
20-
images cri.ImageServiceClient
21+
images images.Store
22+
images_cri cri.ImageServiceClient
2123
namespaces namespaces.Store
2224
}
2325

2426
func ContainerdEnricher(socket string) (ContainerEnricher, error) {
2527
enricher := containerdEnricher{}
28+
29+
// avoid duplicate unix:// prefix
2630
unixSocket := "unix://" + strings.TrimPrefix(socket, "unix://")
2731

2832
client, err := containerd.New(socket)
@@ -38,9 +42,10 @@ func ContainerdEnricher(socket string) (ContainerEnricher, error) {
3842
return nil, errfmt.WrapError(err)
3943
}
4044

41-
enricher.images = cri.NewImageServiceClient(conn)
45+
enricher.images_cri = cri.NewImageServiceClient(conn)
4246
enricher.containers = client.ContainerService()
4347
enricher.namespaces = client.NamespaceService()
48+
enricher.images = client.ImageService()
4449

4550
return &enricher, nil
4651
}
@@ -54,6 +59,7 @@ func (e *containerdEnricher) Get(ctx context.Context, containerId string) (Conta
5459
return metadata, errfmt.Errorf("failed to fetch namespaces %s", err.Error())
5560
}
5661
for _, namespace := range nsList {
62+
// always query with namespace applied
5763
nsCtx := namespaces.WithNamespace(ctx, namespace)
5864

5965
// if containers is not in current namespace, search the next one
@@ -62,27 +68,24 @@ func (e *containerdEnricher) Get(ctx context.Context, containerId string) (Conta
6268
continue
6369
}
6470

65-
imageName := container.Image
66-
imageDigest := container.Image
6771
image := container.Image
68-
// container may not have image name as id, if so fetch from the sha256 id
69-
if strings.HasPrefix(image, "sha256:") {
70-
imageInfo, err := e.images.ImageStatus(ctx, &cri.ImageStatusRequest{
71-
Image: &cri.ImageSpec{
72-
Image: strings.TrimPrefix(image, "sha256:"),
73-
},
74-
})
75-
if err != nil {
72+
var imageName, imageDigest string
73+
74+
i, d, err := e.getImageInfoStore(nsCtx, image)
75+
if err != nil {
76+
// try using cri directly
77+
i, d, err2 := e.getImageInfoCri(nsCtx, image)
78+
if err2 != nil {
79+
logger.Debugw("failed to extract image digest from containerd service and cri", "err", err, "err_cri", err2)
7680
imageName = image
7781
imageDigest = image
7882
} else {
79-
if len(imageInfo.Image.RepoTags) > 0 {
80-
imageName = imageInfo.Image.RepoTags[0]
81-
}
82-
if len(imageInfo.Image.RepoDigests) > 0 {
83-
imageDigest = imageInfo.Image.RepoTags[0]
84-
}
83+
imageName = i
84+
imageDigest = d
8585
}
86+
} else {
87+
imageName = i
88+
imageDigest = d
8689
}
8790

8891
// if in k8s we can extract pod info from labels
@@ -111,3 +114,51 @@ func (e *containerdEnricher) Get(ctx context.Context, containerId string) (Conta
111114
func (e *containerdEnricher) isSandbox(labels map[string]string) bool {
112115
return labels[ContainerTypeContainerdLabel] == "sandbox"
113116
}
117+
118+
func (e *containerdEnricher) getImageInfoStore(ctx context.Context, image string) (string, string, error) {
119+
r, err := e.images.Get(ctx, image)
120+
if err != nil {
121+
return "", "", err
122+
}
123+
124+
i := r.Name
125+
d := r.Target.Digest.String()
126+
return i, d, nil
127+
}
128+
129+
func (e *containerdEnricher) getImageInfoCri(ctx context.Context, image string) (string, string, error) {
130+
var imageName, imageDigest string
131+
var imageInfo *cri.ImageStatusResponse
132+
var err error
133+
134+
if strings.HasPrefix(image, "sha256:") {
135+
// container may not have image name as id, if so fetch from the sha256 id
136+
imageInfo, err = e.images_cri.ImageStatus(ctx, &cri.ImageStatusRequest{
137+
Image: &cri.ImageSpec{
138+
Image: strings.TrimPrefix(image, "sha256:"),
139+
},
140+
})
141+
} else {
142+
// else query directly
143+
imageInfo, err = e.images_cri.ImageStatus(ctx, &cri.ImageStatusRequest{
144+
Image: &cri.ImageSpec{
145+
UserSpecifiedImage: image,
146+
},
147+
})
148+
}
149+
if err != nil {
150+
return "", "", err
151+
} else if imageInfo.Image != nil {
152+
// if imag
153+
if len(imageInfo.Image.RepoTags) > 0 {
154+
imageName = imageInfo.Image.RepoTags[0]
155+
}
156+
if len(imageInfo.Image.RepoDigests) > 0 {
157+
imageDigest = imageInfo.Image.RepoDigests[0]
158+
}
159+
} else {
160+
// image was nil - no image found
161+
return "", "", errfmt.Errorf("no image info found in containerd cri (query: %s)", image)
162+
}
163+
return imageName, imageDigest, nil
164+
}

0 commit comments

Comments
 (0)