Merge pull request #9124 from dmcgowan/cri-image-store-no-client

Update CRI image store to not use containerd client
This commit is contained in:
Akihiro Suda 2023-09-21 19:17:21 +09:00 committed by GitHub
commit 3ebe5d1c56
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 59 additions and 23 deletions

View File

@ -27,6 +27,7 @@ import (
imagestore "github.com/containerd/containerd/pkg/cri/store/image" imagestore "github.com/containerd/containerd/pkg/cri/store/image"
snapshotstore "github.com/containerd/containerd/pkg/cri/store/snapshot" snapshotstore "github.com/containerd/containerd/pkg/cri/store/snapshot"
"github.com/containerd/containerd/pkg/kmutex" "github.com/containerd/containerd/pkg/kmutex"
"github.com/containerd/containerd/platforms"
docker "github.com/distribution/reference" docker "github.com/distribution/reference"
imagedigest "github.com/opencontainers/go-digest" imagedigest "github.com/opencontainers/go-digest"
) )
@ -52,7 +53,7 @@ func NewService(config criconfig.Config, imageFSPath string, client *containerd.
svc := CRIImageService{ svc := CRIImageService{
config: config, config: config,
client: client, client: client,
imageStore: imagestore.NewStore(client), imageStore: imagestore.NewStore(client.ImageService(), client.ContentStore(), platforms.Default()),
imageFSPath: imageFSPath, imageFSPath: imageFSPath,
snapshotStore: snapshotstore.NewStore(), snapshotStore: snapshotstore.NewStore(),
unpackDuplicationSuppressor: kmutex.New(), unpackDuplicationSuppressor: kmutex.New(),

View File

@ -24,6 +24,7 @@ import (
criconfig "github.com/containerd/containerd/pkg/cri/config" criconfig "github.com/containerd/containerd/pkg/cri/config"
imagestore "github.com/containerd/containerd/pkg/cri/store/image" imagestore "github.com/containerd/containerd/pkg/cri/store/image"
snapshotstore "github.com/containerd/containerd/pkg/cri/store/snapshot" snapshotstore "github.com/containerd/containerd/pkg/cri/store/snapshot"
"github.com/containerd/containerd/platforms"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -42,7 +43,7 @@ func newTestCRIService() *CRIImageService {
return &CRIImageService{ return &CRIImageService{
config: testConfig, config: testConfig,
imageFSPath: testImageFSPath, imageFSPath: testImageFSPath,
imageStore: imagestore.NewStore(nil), imageStore: imagestore.NewStore(nil, nil, platforms.Default()),
snapshotStore: snapshotstore.NewStore(), snapshotStore: snapshotstore.NewStore(),
} }
} }

View File

@ -34,6 +34,7 @@ import (
"github.com/containerd/containerd/pkg/cri/nri" "github.com/containerd/containerd/pkg/cri/nri"
"github.com/containerd/containerd/pkg/cri/streaming" "github.com/containerd/containerd/pkg/cri/streaming"
"github.com/containerd/containerd/pkg/kmutex" "github.com/containerd/containerd/pkg/kmutex"
"github.com/containerd/containerd/platforms"
"github.com/containerd/containerd/plugin" "github.com/containerd/containerd/plugin"
cni "github.com/containerd/go-cni" cni "github.com/containerd/go-cni"
"google.golang.org/grpc" "google.golang.org/grpc"
@ -128,7 +129,7 @@ func NewCRIService(config criconfig.Config, client *containerd.Client, nri *nri.
os: osinterface.RealOS{}, os: osinterface.RealOS{},
sandboxStore: sandboxstore.NewStore(labels), sandboxStore: sandboxstore.NewStore(labels),
containerStore: containerstore.NewStore(labels), containerStore: containerstore.NewStore(labels),
imageStore: imagestore.NewStore(client), imageStore: imagestore.NewStore(client.ImageService(), client.ContentStore(), platforms.Default()),
snapshotStore: snapshotstore.NewStore(), snapshotStore: snapshotstore.NewStore(),
sandboxNameIndex: registrar.NewRegistrar(), sandboxNameIndex: registrar.NewRegistrar(),
containerNameIndex: registrar.NewRegistrar(), containerNameIndex: registrar.NewRegistrar(),

View File

@ -22,6 +22,7 @@ import (
"testing" "testing"
"github.com/containerd/containerd/oci" "github.com/containerd/containerd/oci"
"github.com/containerd/containerd/platforms"
"github.com/containerd/go-cni" "github.com/containerd/go-cni"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@ -45,7 +46,7 @@ func newTestCRIService() *criService {
imageFSPath: testImageFSPath, imageFSPath: testImageFSPath,
os: ostesting.NewFakeOS(), os: ostesting.NewFakeOS(),
sandboxStore: sandboxstore.NewStore(labels), sandboxStore: sandboxstore.NewStore(labels),
imageStore: imagestore.NewStore(nil), imageStore: imagestore.NewStore(nil, nil, platforms.Default()),
snapshotStore: snapshotstore.NewStore(), snapshotStore: snapshotstore.NewStore(),
sandboxNameIndex: registrar.NewRegistrar(), sandboxNameIndex: registrar.NewRegistrar(),
containerStore: containerstore.NewStore(labels), containerStore: containerstore.NewStore(labels),

View File

@ -16,12 +16,16 @@
package image package image
import "fmt" import (
"fmt"
"github.com/containerd/containerd/platforms"
)
// NewFakeStore returns an image store with predefined images. // NewFakeStore returns an image store with predefined images.
// Update is not allowed for this fake store. // Update is not allowed for this fake store.
func NewFakeStore(images []Image) (*Store, error) { func NewFakeStore(images []Image) (*Store, error) {
s := NewStore(nil) s := NewStore(nil, nil, platforms.Default())
for _, i := range images { for _, i := range images {
for _, ref := range i.References { for _, ref := range i.References {
s.refCache[ref] = i.ID s.refCache[ref] = i.ID

View File

@ -18,15 +18,20 @@ package image
import ( import (
"context" "context"
"encoding/json"
"fmt" "fmt"
"sync" "sync"
"github.com/containerd/containerd" "github.com/containerd/containerd/content"
"github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/images"
"github.com/containerd/containerd/images/usage"
"github.com/containerd/containerd/pkg/cri/labels" "github.com/containerd/containerd/pkg/cri/labels"
"github.com/containerd/containerd/pkg/cri/util" "github.com/containerd/containerd/pkg/cri/util"
"github.com/containerd/containerd/platforms"
docker "github.com/distribution/reference" docker "github.com/distribution/reference"
"github.com/opencontainers/go-digest"
imagedigest "github.com/opencontainers/go-digest" imagedigest "github.com/opencontainers/go-digest"
"github.com/opencontainers/go-digest/digestset" "github.com/opencontainers/go-digest/digestset"
imageidentity "github.com/opencontainers/image-spec/identity" imageidentity "github.com/opencontainers/image-spec/identity"
@ -50,22 +55,39 @@ type Image struct {
Pinned bool Pinned bool
} }
// InfoProvider provides both content and info about content
type InfoProvider interface {
content.Provider
Info(ctx context.Context, dgst digest.Digest) (content.Info, error)
}
// Store stores all images. // Store stores all images.
type Store struct { type Store struct {
lock sync.RWMutex lock sync.RWMutex
// refCache is a containerd image reference to image id cache. // refCache is a containerd image reference to image id cache.
refCache map[string]string refCache map[string]string
// client is the containerd client.
client *containerd.Client // images is the local image store
images images.Store
// content provider
provider InfoProvider
// platform represents the currently supported platform for images
// TODO: Make this store multi-platform
platform platforms.MatchComparer
// store is the internal image store indexed by image id. // store is the internal image store indexed by image id.
store *store store *store
} }
// NewStore creates an image store. // NewStore creates an image store.
func NewStore(client *containerd.Client) *Store { func NewStore(img images.Store, provider InfoProvider, platform platforms.MatchComparer) *Store {
return &Store{ return &Store{
refCache: make(map[string]string), refCache: make(map[string]string),
client: client, images: img,
provider: provider,
platform: platform,
store: &store{ store: &store{
images: make(map[string]Image), images: make(map[string]Image),
digestSet: digestset.NewSet(), digestSet: digestset.NewSet(),
@ -77,13 +99,15 @@ func NewStore(client *containerd.Client) *Store {
func (s *Store) Update(ctx context.Context, ref string) error { func (s *Store) Update(ctx context.Context, ref string) error {
s.lock.Lock() s.lock.Lock()
defer s.lock.Unlock() defer s.lock.Unlock()
i, err := s.client.GetImage(ctx, ref)
i, err := s.images.Get(ctx, ref)
if err != nil && !errdefs.IsNotFound(err) { if err != nil && !errdefs.IsNotFound(err) {
return fmt.Errorf("get image from containerd: %w", err) return fmt.Errorf("get image from containerd: %w", err)
} }
var img *Image var img *Image
if err == nil { if err == nil {
img, err = getImage(ctx, i) img, err = s.getImage(ctx, i)
if err != nil { if err != nil {
return fmt.Errorf("get image info from containerd: %w", err) return fmt.Errorf("get image info from containerd: %w", err)
} }
@ -116,36 +140,40 @@ func (s *Store) update(ref string, img *Image) error {
return s.store.add(*img) return s.store.add(*img)
} }
// getImage gets image information from containerd. // getImage gets image information from containerd for current platform.
func getImage(ctx context.Context, i containerd.Image) (*Image, error) { func (s *Store) getImage(ctx context.Context, i images.Image) (*Image, error) {
// Get image information. diffIDs, err := i.RootFS(ctx, s.provider, s.platform)
diffIDs, err := i.RootFS(ctx)
if err != nil { if err != nil {
return nil, fmt.Errorf("get image diffIDs: %w", err) return nil, fmt.Errorf("get image diffIDs: %w", err)
} }
chainID := imageidentity.ChainID(diffIDs) chainID := imageidentity.ChainID(diffIDs)
size, err := i.Size(ctx) size, err := usage.CalculateImageUsage(ctx, i, s.provider, usage.WithManifestLimit(s.platform, 1), usage.WithManifestUsage())
if err != nil { if err != nil {
return nil, fmt.Errorf("get image compressed resource size: %w", err) return nil, fmt.Errorf("get image compressed resource size: %w", err)
} }
desc, err := i.Config(ctx) desc, err := i.Config(ctx, s.provider, s.platform)
if err != nil { if err != nil {
return nil, fmt.Errorf("get image config descriptor: %w", err) return nil, fmt.Errorf("get image config descriptor: %w", err)
} }
id := desc.Digest.String() id := desc.Digest.String()
spec, err := i.Spec(ctx) blob, err := content.ReadBlob(ctx, s.provider, desc)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to get OCI image spec: %w", err) return nil, fmt.Errorf("read image config from content store: %w", err)
} }
pinned := i.Labels()[labels.PinnedImageLabelKey] == labels.PinnedImageLabelValue var spec imagespec.Image
if err := json.Unmarshal(blob, &spec); err != nil {
return nil, fmt.Errorf("unmarshal image config %s: %w", blob, err)
}
pinned := i.Labels[labels.PinnedImageLabelKey] == labels.PinnedImageLabelValue
return &Image{ return &Image{
ID: id, ID: id,
References: []string{i.Name()}, References: []string{i.Name},
ChainID: chainID.String(), ChainID: chainID.String(),
Size: size, Size: size,
ImageSpec: spec, ImageSpec: spec,