IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> Docker基础之 ImageStore初始化 -> 正文阅读

[系统运维]Docker基础之 ImageStore初始化

ImageStore,根据所有layer来构建image,维护所有image的元数据。

ImageStore

  1. 创建一个type fs struct对象 ifs
  2. 根据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)
}
  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2021-11-27 10:18:21  更:2021-11-27 10:19:42 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/16 1:37:13-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码