ImageStore,根据所有layer来构建image,维护所有image的元数据。
ImageStore
- 创建一个type fs struct对象 ifs
- 根据StoreBackend ifs和 layerStore来创建一个imageStore
ifs, err := image.NewFSStoreBackend(filepath.Join(imageRoot, "imagedb"))
if err != nil {
return nil, err
}
d.imageStore, err = image.NewImageStore(ifs, d.layerStore)
if err != nil {
return nil, err
}
聚合两个子目录,一个存储目录,另一个存储元数据
const (
contentDirName = "content"
metadataDirName = "metadata"
)
二、文件系统(fs)函数结构
fs函数实现了type StoreBackend interface,提供方法供imageStore调用
type StoreBackend interface {
Walk(f DigestWalkFunc) error
Get(id digest.Digest) ([]byte, error)
Set(data []byte) (digest.Digest, error)
Delete(id digest.Digest) error
SetMetadata(id digest.Digest, key string, data []byte) error
GetMetadata(id digest.Digest, key string) ([]byte, error)
DeleteMetadata(id digest.Digest, key string) error
}
type fs struct {
sync.RWMutex
root string
}
1、创建fs对象 就是创建了3个目录,/var/lib/docker/image/${graphDriverName}/imagedb
func NewFSStoreBackend(root string) (StoreBackend, error) {
return newFSStore(root)
}
func newFSStore(root string) (*fs, error) {
s := &fs{
root: root,
}
if err := os.MkdirAll(filepath.Join(root, contentDirName, string(digest.Canonical)), 0700); err != nil {
return nil, err
}
if err := os.MkdirAll(filepath.Join(root, metadataDirName, string(digest.Canonical)), 0700); err != nil {
return nil, err
}
return s, nil
}
2、Walk函数 func (s *fs) Walk 会遍历下的目录/var/lib/docker/image/overlay/imagedb/content/sha256/ ,用入参提供的方法f DigestWalkFunc来对所有的目录ID进行计算。
func (s *fs) Walk(f DigestWalkFunc) error {
s.RLock()
dir, err := ioutil.ReadDir(filepath.Join(s.root, contentDirName, string(digest.Canonical)))
s.RUnlock()
if err != nil {
return err
}
for _, v := range dir {
dgst := digest.NewDigestFromHex(string(digest.Canonical), v.Name())
if err := dgst.Validate(); err != nil {
logrus.Debugf("Skipping invalid digest %s: %s", dgst, err)
continue
}
if err := f(dgst); err != nil {
return err
}
}
return nil
}
三、imageStore
首先查看相关定义
type imageMeta struct {
layer layer.Layer
children map[ID]struct{}
}
type store struct {
sync.Mutex
ls LayerGetReleaser
images map[ID]*imageMeta
fs StoreBackend
digestSet *digest.Set
}
1、创建imageStore对象 主要是调用restore()函数来根据/var/lib/docker/image/overlay/imagedb目录下的内容设置ImageStore的属性
func NewImageStore(fs StoreBackend, ls LayerGetReleaser) (Store, error) {
is := &store{
ls: ls,
images: make(map[ID]*imageMeta),
fs: fs,
digestSet: digest.NewSet(),
}
if err := is.restore(); err != nil {
return nil, err
}
return is, nil
}
2、 restore函数
func (is *store) restore() error {
err := is.fs.Walk(func(dgst digest.Digest) error {
img, err := is.Get(IDFromDigest(dgst))
if err != nil {
logrus.Errorf("invalid image %v, %v", dgst, err)
return nil
}
var l layer.Layer
if chainID := img.RootFS.ChainID(); chainID != "" {
l, err = is.ls.Get(chainID)
if err != nil {
return err
}
}
if err := is.digestSet.Add(dgst); err != nil {
return err
}
imageMeta := &imageMeta{
layer: l,
children: make(map[ID]struct{}),
}
is.images[IDFromDigest(dgst)] = imageMeta
return nil
})
if err != nil {
return err
}
for id := range is.images {
if parent, err := is.GetParent(id); err == nil {
if parentMeta := is.images[parent]; parentMeta != nil {
parentMeta.children[id] = struct{}{}
}
}
}
return nil
}
3、 根据diffID计算一个layer的chainID
func (r *RootFS) ChainID() layer.ChainID {
if runtime.GOOS == "windows" && r.Type == typeLayersWithBase {
logrus.Warnf("Layer type is unsupported on this platform. DiffIDs: '%v'", r.DiffIDs)
return ""
}
return layer.CreateChainID(r.DiffIDs)
}
func CreateChainID(dgsts []DiffID) ChainID {
return createChainIDFromParent("", dgsts...)
}
func createChainIDFromParent(parent ChainID, dgsts ...DiffID) ChainID {
if len(dgsts) == 0 {
return parent
}
if parent == "" {
return createChainIDFromParent(ChainID(dgsts[0]), dgsts[1:]...)
}
dgst := digest.FromBytes([]byte(string(parent) + " " + string(dgsts[0])))
return createChainIDFromParent(ChainID(dgst), dgsts[1:]...)
}
四、RootFS构造函数
type RootFS struct记录了一个镜像所有layer的diffID值,可以通过查看/var/lib/docker/image/overlay/imagedb/content/sha256/{id}文件来查看一个镜像的rootfs属性
type RootFS struct {
Type string `json:"type"`
DiffIDs []layer.DiffID `json:"diff_ids,omitempty"`
}
func NewRootFS() *RootFS {
return &RootFS{Type: TypeLayers}
}
func (r *RootFS) Append(id layer.DiffID) {
r.DiffIDs = append(r.DiffIDs, id)
}
|