ImageStore,根据所有layer来构建image,维护所有image的元数据。
ImageStore- 创建一个type fs struct对象 ifs
- 根据StoreBackend ifs和 layerStore来创建一个imageStore
// /var/lib/docker/image/${graphDriverName}/imagedb 这个目录是用来记录镜像元数据
ifs, err := image.NewFSStoreBackend(filepath.Join(imageRoot, "imagedb"))
if err != nil {
return nil, err
}
//imageStore:根据所有layer来构建image,维护所有image的元数据根据StoreBackend ifs和 layerStore来创建一个imageStore
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调用
// StoreBackend为image.Store的持久化提供接口
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
}
// fs在文件系统中继承了StoreBackend接口
type fs struct {
sync.RWMutex
root string
}
1、创建fs对象
就是创建了3个目录,/var/lib/docker/image/${graphDriverName}/imagedb
// NewFSStoreBackend为映像返回新的基于文件系统的后端。商店
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进行计算。
// Walk calls the supplied callback for each image ID in the storage backend.
func (s *fs) Walk(f DigestWalkFunc) error {
//目前仅支持sha256,用来计算digest值Canonical = SHA256
s.RLock()
//获取到 /var/lib/docker/image/overlay/imagedb/content/sha256/下的所有目录名字一个目录名字代表了一个image ID
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
}
//执行f(dgst)
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 //存放镜像ID对应的layer及子镜像
fs StoreBackend
digestSet *digest.Set //存放所有的镜像ID
}
1、创建imageStore对象
主要是调用restore()函数来根据/var/lib/docker/image/overlay/imagedb目录下的内容设置ImageStore的属性
// NewImageStore返回给定层存储的新存储对象
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 {
//根据image ID来生成type Image struct对象,记录了一个image的结构信息
img, err := is.Get(IDFromDigest(dgst))
if err != nil {
logrus.Errorf("invalid image %v, %v", dgst, err)
return nil
}
var l layer.Layer
//根据img.RootFS中记录的diffID计算出该image的最后一个chainID
if chainID := img.RootFS.ChainID(); chainID != "" {
l, err = is.ls.Get(chainID)
if err != nil {
return err
}
}
//在digestSet *digest.Set中记录下该image ID
if err := is.digestSet.Add(dgst); err != nil {
return err
}
//image元数据
imagemeta := &imagemeta{
layer: l,
children: make(map[ID]struct{}),
}
// image元数据和image ID的映射
is.images[IDFromDigest(dgst)] = imagemeta
return nil
})
if err != nil {
return err
}
for id := range is.images {
//设置ImageID中的父子关系,根据id读取/var/lib/docker/overlay/imagedb/metadata/sha256/{id}下的文件内容
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
//返回在RootFS中最顶层的那一个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)
}
// 计算一个镜像所有的 ChainID
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属性
// RootFS函数描述镜像在文件系统的根节点
type RootFS struct {
Type string `json:"type"`
DiffIDs []layer.DiffID `json:"diff_ids,omitempty"`
}
// NewRootFS返回空的RootFS结构
func NewRootFS() *RootFS {
return &RootFS{Type: TypeLayers}
}
// 将一个新的diffID附加到rootfs
func (r *RootFS) Append(id layer.DiffID) {
r.DiffIDs = append(r.DiffIDs, id)
}



