layStore负责Docker的layer的管理,具体有镜像层的管理,容器init层的管理,容器读写层的管理。layerStore的管理目录为/var/lib/docker/image/aufs/layerdb,主要有以下目录:
- mounts: 存储容器挂载信息,有init-id, mount-id, parent文件。
 
- sha256: 存储镜像层的信息,有cache-id(aufs的存储位置), diff, size和tar-split.json.gz。
 
本次分析将介绍layStore是如何管理这些文件目录的。
首先,要先介绍直接与文件打交道的filestore。
filestore相关
先来介绍fileMetadataStore,fileMetadataStore用来读取layerdb目录下的文件,定义在/layer/filestore.go中:
1 2 3 4 
  | type fileMetadataStore struct { 	root string } 
  | 
NewFSMetadataStore()可以创建layerdb的根目录,并生成一个新的fileMetadataStore。
1 2 3 4 5 6 7 8 9 10 11 
  | func NewFSMetadataStore(root string) (MetadataStore, error) { 	if err := os.MkdirAll(root, 0700); err != nil { 		return nil, err 	} 	return &fileMetadataStore{ 		root: root, 	}, nil } 
  | 
getLayerDirectory()
getLayerDirectory()返回/var/lib/docker/image/aufs/layerdb/sha256/xxxxxxxxxxxxxxxx目录。
1 2 3 4 5 
  | func (fms *fileMetadataStore) getLayerDirectory(layer ChainID) string { 	dgst := digest.Digest(layer) 	return filepath.Join(fms.root, string(dgst.Algorithm()), dgst.Hex()) } 
  | 
getLayerFilename()
getLayerFilename()用来获取sha256目录具体层目录下的具体文件。
1 2 3 4 
  | func (fms *fileMetadataStore) getLayerFilename(layer ChainID, filename string) string { 	return filepath.Join(fms.getLayerDirectory(layer), filename) } 
  | 
getMountDirectory()
getMountDirectory()返回/var/lib/docker/image/aufs/layerdb/mounts/xxxxxxxxxx目录。
1 2 3 4 
  | func (fms *fileMetadataStore) getMountDirectory(mount string) string { 	return filepath.Join(fms.root, "mounts", mount) } 
  | 
getMountFilename()
1 2 3 4 
  | func (fms *fileMetadataStore) getMountFilename(mount, filename string) string { 	return filepath.Join(fms.getMountDirectory(mount), filename) } 
  | 
 
StartTransaction()
设置临时目录。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 
  | func (fms *fileMetadataStore) StartTransaction() (MetadataTransaction, error) { 	tmpDir := filepath.Join(fms.root, "tmp") 	if err := os.MkdirAll(tmpDir, 0755); err != nil { 		return nil, err 	} 	td, err := ioutil.TempDir(tmpDir, "layer-") 	if err != nil { 		return nil, err 	} 	 	return &fileMetadataTransaction{ 		store: fms, 		root:  td, 	}, nil } 
  | 
GetSize()
GetSize()用于获取size文件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 
  | func (fms *fileMetadataStore) GetSize(layer ChainID) (int64, error) { 	content, err := ioutil.ReadFile(fms.getLayerFilename(layer, "size")) 	if err != nil { 		return 0, err 	} 	size, err := strconv.ParseInt(string(content), 10, 64) 	if err != nil { 		return 0, err 	} 	return size, nil } 
  | 
GetParent()
GetParent()用于获取parent文件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 
  | func (fms *fileMetadataStore) GetParent(layer ChainID) (ChainID, error) { 	content, err := ioutil.ReadFile(fms.getLayerFilename(layer, "parent")) 	if err != nil { 		if os.IsNotExist(err) { 			return "", nil 		} 		return "", err 	} 	dgst, err := digest.ParseDigest(strings.TrimSpace(string(content))) 	if err != nil { 		return "", err 	} 	return ChainID(dgst), nil } 
  | 
GetDiffID()
GetDiffID()用于获取diff文件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 
  | func (fms *fileMetadataStore) GetDiffID(layer ChainID) (DiffID, error) { 	content, err := ioutil.ReadFile(fms.getLayerFilename(layer, "diff")) 	if err != nil { 		return "", err 	} 	dgst, err := digest.ParseDigest(strings.TrimSpace(string(content))) 	if err != nil { 		return "", err 	} 	return DiffID(dgst), nil } 
  | 
GetCacheID()
GetCacheID()用于获取cache-id
1 2 3 4 5 6 7 8 9 10 11 12 13 14 
  | func (fms *fileMetadataStore) GetCacheID(layer ChainID) (string, error) { 	contentBytes, err := ioutil.ReadFile(fms.getLayerFilename(layer, "cache-id")) 	if err != nil { 		return "", err 	} 	content := strings.TrimSpace(string(contentBytes)) 	if !stringIDRegexp.MatchString(content) { 		return "", errors.New("invalid cache id value") 	} 	return content, nil } 
  | 
GetDescriptor()
??????不知道什么用途
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 
  | func (fms *fileMetadataStore) GetDescriptor(layer ChainID) (distribution.Descriptor, error) { 	content, err := ioutil.ReadFile(fms.getLayerFilename(layer, "descriptor.json")) 	if err != nil { 		if os.IsNotExist(err) { 			 			return distribution.Descriptor{}, nil 		} 		return distribution.Descriptor{}, err 	} 	var ref distribution.Descriptor 	err = json.Unmarshal(content, &ref) 	if err != nil { 		return distribution.Descriptor{}, err 	} 	return ref, err } 
  | 
TarSplitReader()
TarSplitReader()可以读取tar-split.json.gz,但tar-split.json.gz的作用目录还不清楚。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 
  | func (fms *fileMetadataStore) TarSplitReader(layer ChainID) (io.ReadCloser, error) { 	fz, err := os.Open(fms.getLayerFilename(layer, "tar-split.json.gz")) 	if err != nil { 		return nil, err 	} 	f, err := gzip.NewReader(fz) 	if err != nil { 		return nil, err 	} 	return ioutils.NewReadCloserWrapper(f, func() error { 		f.Close() 		return fz.Close() 	}), nil } 
  | 
SetMountID()
SetMountID()可以在mounts目录下设置mount-id文件。
1 2 3 4 5 6 7 
  | func (fms *fileMetadataStore) SetMountID(mount string, mountID string) error { 	if err := os.MkdirAll(fms.getMountDirectory(mount), 0755); err != nil { 		return err 	} 	return ioutil.WriteFile(fms.getMountFilename(mount, "mount-id"), []byte(mountID), 0644) } 
  | 
SetInitID()
SetInitID()可以在mounts目录下设置init-id文件。
1 2 3 4 5 6 7 
  | func (fms *fileMetadataStore) SetInitID(mount string, init string) error { 	if err := os.MkdirAll(fms.getMountDirectory(mount), 0755); err != nil { 		return err 	} 	return ioutil.WriteFile(fms.getMountFilename(mount, "init-id"), []byte(init), 0644) } 
  | 
SetMountParent()
SetMountParent()可以在mounts目录下设置parent文件。
1 2 3 4 5 6 7 
  | func (fms *fileMetadataStore) SetMountParent(mount string, parent ChainID) error { 	if err := os.MkdirAll(fms.getMountDirectory(mount), 0755); err != nil { 		return err 	} 	return ioutil.WriteFile(fms.getMountFilename(mount, "parent"), []byte(digest.Digest(parent).String()), 0644) } 
  | 
GetMountID()
GetMountID()用于获取mounts目录下的mount-id文件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 
  | func (fms *fileMetadataStore) GetMountID(mount string) (string, error) { 	contentBytes, err := ioutil.ReadFile(fms.getMountFilename(mount, "mount-id")) 	if err != nil { 		return "", err 	} 	content := strings.TrimSpace(string(contentBytes)) 	if !stringIDRegexp.MatchString(content) { 		return "", errors.New("invalid mount id value") 	} 	return content, nil } 
  | 
GetInitID()
GetInitID()用于获取mounts目录下的init-id文件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 
  | func (fms *fileMetadataStore) GetInitID(mount string) (string, error) { 	contentBytes, err := ioutil.ReadFile(fms.getMountFilename(mount, "init-id")) 	if err != nil { 		if os.IsNotExist(err) { 			return "", nil 		} 		return "", err 	} 	content := strings.TrimSpace(string(contentBytes)) 	if !stringIDRegexp.MatchString(content) { 		return "", errors.New("invalid init id value") 	} 	return content, nil } 
  | 
GetMountParent()
GetMountParent()用于获取mounts目录下的parent文件。。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 
  | func (fms *fileMetadataStore) GetMountParent(mount string) (ChainID, error) { 	content, err := ioutil.ReadFile(fms.getMountFilename(mount, "parent")) 	if err != nil { 		if os.IsNotExist(err) { 			return "", nil 		} 		return "", err 	} 	dgst, err := digest.ParseDigest(strings.TrimSpace(string(content))) 	if err != nil { 		return "", err 	} 	return ChainID(dgst), nil } 
  | 
List()
用于获取ids和mounts。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 
  | func (fms *fileMetadataStore) List() ([]ChainID, []string, error) { 	var ids []ChainID 	for _, algorithm := range supportedAlgorithms { 		fileInfos, err := ioutil.ReadDir(filepath.Join(fms.root, string(algorithm))) 		if err != nil { 			if os.IsNotExist(err) { 				continue 			} 			return nil, nil, err 		} 		for _, fi := range fileInfos { 			if fi.IsDir() && fi.Name() != "mounts" { 				dgst := digest.NewDigestFromHex(string(algorithm), fi.Name()) 				if err := dgst.Validate(); err != nil { 					logrus.Debugf("Ignoring invalid digest %s:%s", algorithm, fi.Name()) 				} else { 					ids = append(ids, ChainID(dgst)) 				} 			} 		} 	} 	fileInfos, err := ioutil.ReadDir(filepath.Join(fms.root, "mounts")) 	if err != nil { 		if os.IsNotExist(err) { 			return ids, []string{}, nil 		} 		return nil, nil, err 	} 	var mounts []string 	for _, fi := range fileInfos { 		if fi.IsDir() { 			mounts = append(mounts, fi.Name()) 		} 	} 	return ids, mounts, nil } 
  | 
Remove()
Remove()移除layerdb中的镜像层
1 2 3 4 
  | func (fms *fileMetadataStore) Remove(layer ChainID) error { 	return os.RemoveAll(fms.getLayerDirectory(layer)) } 
  | 
RemoveMount()
RemoveMount()移除layerdb中mounts目录下的内容。
1 2 3 4 
  | func (fms *fileMetadataStore) RemoveMount(mount string) error { 	return os.RemoveAll(fms.getMountDirectory(mount)) } 
  | 
再来介绍fileMetadataTransaction。fileMetadataTransaction用来创建一个临时文件夹,再全部的操作完成后,再把临时文件夹重命名成正式文件夹。
fileMetadataTransaction定义在/layer/filiestore.go中:
1 2 3 4 5 
  | type fileMetadataTransaction struct { 	store *fileMetadataStore 	root  string } 
  | 
fileMetaDataStore的StartTransaction()方法可以生成一个新的fileMetadataTransaction。
SetSize()
往临时文件夹中写入size。
1 2 3 4 5 
  | func (fm *fileMetadataTransaction) SetSize(size int64) error { 	content := fmt.Sprintf("%d", size) 	return ioutil.WriteFile(filepath.Join(fm.root, "size"), []byte(content), 0644) } 
  | 
SetParent()
往临时文件夹中写入parent。
1 2 3 4 
  | func (fm *fileMetadataTransaction) SetParent(parent ChainID) error { 	return ioutil.WriteFile(filepath.Join(fm.root, "parent"), []byte(digest.Digest(parent).String()), 0644) } 
  | 
SetDiffID()
往临时文件夹中写入diff。
1 2 3 4 
  | func (fm *fileMetadataTransaction) SetDiffID(diff DiffID) error { 	return ioutil.WriteFile(filepath.Join(fm.root, "diff"), []byte(digest.Digest(diff).String()), 0644) } 
  | 
SetCacheID()
往临时文件夹中写入cache-id。
1 2 3 4 
  | func (fm *fileMetadataTransaction) SetCacheID(cacheID string) error { 	return ioutil.WriteFile(filepath.Join(fm.root, "cache-id"), []byte(cacheID), 0644) } 
  | 
SetDescriptor()
往临时文件夹中写入descriptor.json。
1 2 3 4 5 6 7 
  | func (fm *fileMetadataTransaction) SetDescriptor(ref distribution.Descriptor) error { 	jsonRef, err := json.Marshal(ref) 	if err != nil { 		return err 	} 	return ioutil.WriteFile(filepath.Join(fm.root, "descriptor.json"), jsonRef, 0644) } 
  | 
TarSplitWriter()
往临时文件夹中写入tar-split.json.gz。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 
  | func (fm *fileMetadataTransaction) TarSplitWriter(compressInput bool) (io.WriteCloser, error) { 	f, err := os.OpenFile(filepath.Join(fm.root, "tar-split.json.gz"), os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0644) 	if err != nil { 		return nil, err 	} 	var wc io.WriteCloser 	if compressInput { 		wc = gzip.NewWriter(f) 	} else { 		wc = f 	} 	return ioutils.NewWriteCloserWrapper(wc, func() error { 		wc.Close() 		return f.Close() 	}), nil } 
  | 
Commit()
把临时目录重命名成正式目录。
1 2 3 4 5 6 7 8 
  | func (fm *fileMetadataTransaction) Commit(layer ChainID) error { 	finalDir := fm.store.getLayerDirectory(layer) 	if err := os.MkdirAll(filepath.Dir(finalDir), 0755); err != nil { 		return err 	} 	return os.Rename(fm.root, finalDir) } 
  | 
Cancel()
Cancel()用来删除临时文件夹。
1 2 3 4 
  | func (fm *fileMetadataTransaction) Cancel() error { 	return os.RemoveAll(fm.root) } 
  | 
layerStore
再来看layerStore。layerStore定义了layerdb真正意义上的操作,定义在/layer/layer_store.go中:
1 2 3 4 5 6 7 8 9 10 11 12 13 
  | type layerStore struct { 	 	store  MetadataStore 	driver graphdriver.Driver 	 	layerMap map[ChainID]*roLayer 	layerL   sync.Mutex 	 	mounts map[string]*mountedLayer 	mountL sync.Mutex } 
  | 
可以看出,layerStore中有一个store,即fileMetadataStore;一个driver,默认为aufs driver;一个layerMap用来缓存layer;一个mounts用来缓存mountedLayer。
NewStoreFromGraphDriver()
NewStoreFromGraphDriver()可以创建一个layerStore。流程如下:
- 使用store.List()获取ids和mounts;
 
- 通过loadLayer()方法导入所有layer信息;
 
- 通过loadMount()方法导入所有mount信息。
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 
  | func NewStoreFromGraphDriver(store MetadataStore, driver graphdriver.Driver) (Store, error) { 	ls := &layerStore{ 		store:    store, 		driver:   driver, 		layerMap: map[ChainID]*roLayer{}, 		mounts:   map[string]*mountedLayer{}, 	} 	ids, mounts, err := store.List() 	if err != nil { 		return nil, err 	} 	for _, id := range ids { 		l, err := ls.loadLayer(id) 		if err != nil { 			logrus.Debugf("Failed to load layer %s: %s", id, err) 			continue 		} 		if l.parent != nil { 			l.parent.referenceCount++ 		} 	} 	for _, mount := range mounts { 		if err := ls.loadMount(mount); err != nil { 			logrus.Debugf("Failed to load mount %s: %s", mount, err) 		} 	} 	return ls, nil } 
  | 
 
loadLayer()
loadLayer()用于导入一个layer。主要流程如下:
- 如果layer在layerMap已缓存,则直接返回;
 
- 获取layer目录下的diff文件;
 
- 获取layer目录下的size文件;
 
- 获取layer目录下的cache-id文件;
 
- 获取layer目录下的parent文件;
 
- 获取layer目录下的descriptor文件;
 
- 构造roLayer表示只读层;
 
- 把roLayer缓存到layerMap中;
 
- 返回roLayer。
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 
  | func (ls *layerStore) loadLayer(layer ChainID) (*roLayer, error) { 	cl, ok := ls.layerMap[layer] 	if ok { 		return cl, nil 	} 	 	diff, err := ls.store.GetDiffID(layer) 	if err != nil { 		return nil, fmt.Errorf("failed to get diff id for %s: %s", layer, err) 	} 	 	size, err := ls.store.GetSize(layer) 	if err != nil { 		return nil, fmt.Errorf("failed to get size for %s: %s", layer, err) 	} 	 	cacheID, err := ls.store.GetCacheID(layer) 	if err != nil { 		return nil, fmt.Errorf("failed to get cache id for %s: %s", layer, err) 	} 	 	parent, err := ls.store.GetParent(layer) 	if err != nil { 		return nil, fmt.Errorf("failed to get parent for %s: %s", layer, err) 	} 	 	descriptor, err := ls.store.GetDescriptor(layer) 	if err != nil { 		return nil, fmt.Errorf("failed to get descriptor for %s: %s", layer, err) 	} 	 	cl = &roLayer{ 		chainID:    layer, 		diffID:     diff, 		size:       size, 		cacheID:    cacheID, 		layerStore: ls, 		references: map[Layer]struct{}{}, 		descriptor: descriptor, 	} 	if parent != "" { 		p, err := ls.loadLayer(parent) 		if err != nil { 			return nil, err 		} 		cl.parent = p 	} 	 	ls.layerMap[cl.chainID] = cl 	return cl, nil } 
  | 
 
loadMount()
loadMount()用于导入一个mount。主要流程如下:
- 如果mouns中已有缓存,则直接返回;
 
- 获取mount目录下的mount-id文件;
 
- 获取mount目录下的init-id文件;
 
- 获取mount目录下的parent文件;
 
- 构造mountLayer;
 
- 把mountLayer缓存到mounts中。
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 
  | func (ls *layerStore) loadMount(mount string) error { 	if _, ok := ls.mounts[mount]; ok { 		return nil 	} 	 	mountID, err := ls.store.GetMountID(mount) 	if err != nil { 		return err 	} 	 	initID, err := ls.store.GetInitID(mount) 	if err != nil { 		return err 	} 	 	parent, err := ls.store.GetMountParent(mount) 	if err != nil { 		return err 	} 	 	ml := &mountedLayer{ 		name:       mount, 		mountID:    mountID, 		initID:     initID, 		layerStore: ls, 		references: map[RWLayer]*referencedRWLayer{}, 	} 	if parent != "" { 		p, err := ls.loadLayer(parent) 		if err != nil { 			return err 		} 		ml.parent = p 		p.referenceCount++ 	} 	 	ls.mounts[ml.name] = ml 	return nil } 
  | 
 
applyTar()
applyTar()通过调用driver的ApplyDiff()把镜像层的tar包解压到指定位置。具体解压过程见driver的分析过程。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 
  | func (ls *layerStore) applyTar(tx MetadataTransaction, ts io.Reader, parent string, layer *roLayer) error { 	digester := digest.Canonical.New() 	 	tr := io.TeeReader(ts, digester.Hash()) 	tsw, err := tx.TarSplitWriter(true) 	if err != nil { 		return err 	} 	metaPacker := storage.NewJSONPacker(tsw) 	defer tsw.Close() 	 	 	rdr, err := asm.NewInputTarStream(tr, metaPacker, nil) 	if err != nil { 		return err 	} 	 	 	applySize, err := ls.driver.ApplyDiff(layer.cacheID, parent, archive.Reader(rdr)) 	if err != nil { 		return err 	} 	 	io.Copy(ioutil.Discard, rdr)  	 	layer.size = applySize 	 	layer.diffID = DiffID(digester.Digest()) 	logrus.Debugf("Applied tar %s to %s, size: %d", layer.diffID, layer.cacheID, applySize) 	return nil } 
  | 
Register()
Register()是入口。
Register()调用了registerWithDescriptor()方法。registerWithDescriptor()主要流程如下:
- 调用driver.Create()在driver中创建对应目录;
 
- 调用store.StartTransaction()创建临时目录;
 
- applyTar()把镜像层的tar包解压到driver指定目录中;
 
- 调用createChainIDFromParent()计算chainID,即layerID,具体分析见Docker镜像存储分析;
 
- 调用storeLayer()把所生成的layer持久化;
 
- 调用tx.Commit()提交变更。
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 
  | func (ls *layerStore) Register(ts io.Reader, parent ChainID) (Layer, error) { 	return ls.registerWithDescriptor(ts, parent, distribution.Descriptor{}) } func (ls *layerStore) registerWithDescriptor(ts io.Reader, parent ChainID, descriptor distribution.Descriptor) (Layer, error) { 	 	 	 	var err error 	var pid string 	var p *roLayer 	if string(parent) != "" { 		p = ls.get(parent) 		if p == nil { 			return nil, ErrLayerDoesNotExist 		} 		pid = p.cacheID 		 		defer func() { 			if err != nil { 				ls.layerL.Lock() 				ls.releaseLayer(p) 				ls.layerL.Unlock() 			} 		}() 		if p.depth() >= maxLayerDepth { 			err = ErrMaxDepthExceeded 			return nil, err 		} 	} 	 	layer := &roLayer{ 		parent:         p, 		cacheID:        stringid.GenerateRandomID(), 		referenceCount: 1, 		layerStore:     ls, 		references:     map[Layer]struct{}{}, 		descriptor:     descriptor, 	} 	 	if err = ls.driver.Create(layer.cacheID, pid, "", nil); err != nil { 		return nil, err 	} 	tx, err := ls.store.StartTransaction() 	if err != nil { 		return nil, err 	} 	defer func() { 		if err != nil { 			logrus.Debugf("Cleaning up layer %s: %v", layer.cacheID, err) 			if err := ls.driver.Remove(layer.cacheID); err != nil { 				logrus.Errorf("Error cleaning up cache layer %s: %v", layer.cacheID, err) 			} 			if err := tx.Cancel(); err != nil { 				logrus.Errorf("Error canceling metadata transaction %q: %s", tx.String(), err) 			} 		} 	}() 	 	 	if err = ls.applyTar(tx, ts, pid, layer); err != nil { 		return nil, err 	} 	if layer.parent == nil { 		layer.chainID = ChainID(layer.diffID) 	} else { 		 		 		layer.chainID = createChainIDFromParent(layer.parent.chainID, layer.diffID) 	} 	 	if err = storeLayer(tx, layer); err != nil { 		return nil, err 	} 	ls.layerL.Lock() 	defer ls.layerL.Unlock() 	if existingLayer := ls.getWithoutLock(layer.chainID); existingLayer != nil { 		 		err = errors.New("layer already exists") 		return existingLayer.getReference(), nil 	} 	 	if err = tx.Commit(layer.chainID); err != nil { 		return nil, err 	} 	ls.layerMap[layer.chainID] = layer 	return layer.getReference(), nil } 
  | 
 
Get()
Get()可以从layerMap中获取一个layer,并在该layer的referenceCount上+1。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 
  | func (ls *layerStore) getWithoutLock(layer ChainID) *roLayer { 	l, ok := ls.layerMap[layer] 	if !ok { 		return nil 	} 	l.referenceCount++ 	return l } func (ls *layerStore) get(l ChainID) *roLayer { 	ls.layerL.Lock() 	defer ls.layerL.Unlock() 	return ls.getWithoutLock(l) } func (ls *layerStore) Get(l ChainID) (Layer, error) { 	ls.layerL.Lock() 	defer ls.layerL.Unlock() 	layer := ls.getWithoutLock(l) 	if layer == nil { 		return nil, ErrLayerDoesNotExist 	} 	return layer.getReference(), nil } 
  | 
deleteLayer()
在driver中删除layer相关信息;在filestore中删除layer相关信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 
  | func (ls *layerStore) deleteLayer(layer *roLayer, metadata *Metadata) error { 	 	err := ls.driver.Remove(layer.cacheID) 	if err != nil { 		return err 	} 	 	err = ls.store.Remove(layer.chainID) 	if err != nil { 		return err 	} 	metadata.DiffID = layer.diffID 	metadata.ChainID = layer.chainID 	metadata.Size, err = layer.Size() 	if err != nil { 		return err 	} 	metadata.DiffSize = layer.size 	return nil } 
  | 
Release()
Release()可以层层删除没有被引用的层。由于Docker镜像是树状结构的,Release()相当于删除一条枝代表的laysers。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 
  | func (ls *layerStore) Release(l Layer) ([]Metadata, error) { 	ls.layerL.Lock() 	defer ls.layerL.Unlock() 	layer, ok := ls.layerMap[l.ChainID()] 	if !ok { 		return []Metadata{}, nil 	} 	if !layer.hasReference(l) { 		return nil, ErrLayerNotRetained 	} 	layer.deleteReference(l) 	return ls.releaseLayer(layer) } func (ls *layerStore) releaseLayer(l *roLayer) ([]Metadata, error) { 	depth := 0 	removed := []Metadata{} 	 	for { 		if l.referenceCount == 0 { 			panic("layer not retained") 		} 		l.referenceCount-- 		 		 		if l.referenceCount != 0 { 			return removed, nil 		} 		if len(removed) == 0 && depth > 0 { 			panic("cannot remove layer with child") 		} 		if l.hasReferences() { 			panic("cannot delete referenced layer") 		} 		var metadata Metadata 		 		if err := ls.deleteLayer(l, &metadata); err != nil { 			return nil, err 		} 		 		delete(ls.layerMap, l.chainID) 		 		removed = append(removed, metadata) 		if l.parent == nil { 			return removed, nil 		} 		depth++ 		l = l.parent 	} } 
  | 
CreateRWLayer()
CreateRWLayer()先在layerdb中创建一个layer,然后调用driver.CreateReadWrite()在driver中创建读写目录。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 
  | func (ls *layerStore) CreateRWLayer(name string, parent ChainID, mountLabel string, initFunc MountInit, storageOpt map[string]string) (RWLayer, error) { 	ls.mountL.Lock() 	defer ls.mountL.Unlock() 	m, ok := ls.mounts[name] 	if ok { 		return nil, ErrMountNameConflict 	} 	var err error 	var pid string 	var p *roLayer 	if string(parent) != "" { 		p = ls.get(parent) 		if p == nil { 			return nil, ErrLayerDoesNotExist 		} 		pid = p.cacheID 		 		defer func() { 			if err != nil { 				ls.layerL.Lock() 				ls.releaseLayer(p) 				ls.layerL.Unlock() 			} 		}() 	} 	 	m = &mountedLayer{ 		name:       name, 		parent:     p, 		mountID:    ls.mountID(name), 		layerStore: ls, 		references: map[RWLayer]*referencedRWLayer{}, 	} 	if initFunc != nil { 		pid, err = ls.initMount(m.mountID, pid, mountLabel, initFunc, storageOpt) 		if err != nil { 			return nil, err 		} 		m.initID = pid 	} 	 	if err = ls.driver.CreateReadWrite(m.mountID, pid, "", storageOpt); err != nil { 		return nil, err 	} 	if err = ls.saveMount(m); err != nil { 		return nil, err 	} 	return m.getReference(), nil } 
  | 
ReleaseRWLayer()
ReleaseRWLayer()可以删除一个读写层。主要流程如下:
- 删除driver的容器读写层;
 
- 删除driver的容器init层;
 
- 从fileStore上删除该层的信息。
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 
  | func (ls *layerStore) ReleaseRWLayer(l RWLayer) ([]Metadata, error) { 	ls.mountL.Lock() 	defer ls.mountL.Unlock() 	m, ok := ls.mounts[l.Name()] 	if !ok { 		return []Metadata{}, nil 	} 	if err := m.deleteReference(l); err != nil { 		return nil, err 	} 	if m.hasReferences() { 		return []Metadata{}, nil 	} 	 	if err := ls.driver.Remove(m.mountID); err != nil { 		logrus.Errorf("Error removing mounted layer %s: %s", m.name, err) 		m.retakeReference(l) 		return nil, err 	} 	if m.initID != "" { 		 		if err := ls.driver.Remove(m.initID); err != nil { 			logrus.Errorf("Error removing init layer %s: %s", m.name, err) 			m.retakeReference(l) 			return nil, err 		} 	} 	if err := ls.store.RemoveMount(m.name); err != nil { 		logrus.Errorf("Error removing mount metadata: %s: %s", m.name, err) 		m.retakeReference(l) 		return nil, err 	} 	delete(ls.mounts, m.Name()) 	ls.layerL.Lock() 	defer ls.layerL.Unlock() 	if m.parent != nil { 		return ls.releaseLayer(m.parent) 	} 	return []Metadata{}, nil } 
  | 
 
saveMount()
saveMount()可以持久化mount信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 
  | func (ls *layerStore) saveMount(mount *mountedLayer) error { 	 	if err := ls.store.SetMountID(mount.name, mount.mountID); err != nil { 		return err 	} 	 	if mount.initID != "" { 		if err := ls.store.SetInitID(mount.name, mount.initID); err != nil { 			return err 		} 	} 	 	if mount.parent != nil { 		if err := ls.store.SetMountParent(mount.name, mount.parent.chainID); err != nil { 			return err 		} 	} 	ls.mounts[mount.name] = mount 	return nil } 
  | 
CreateChainID()
最后来看下计算chainID的函数,定义在/layer/layer.go中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 
  | 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:]...) } 
  | 
可见,整个过程是把上一次的哈希结果和下一个diff合并成字符串,接着计算哈希值。
总结
方法很多,分析中的代码也很长。只要记着以下几点:
- 可以使用Register()向layerdb注册一个layer;
 
- layerStore对应的目录为/var/lib/docker/image/aufs/layerdb;
 
- layerStore中有driver连接镜像存储;