-
Notifications
You must be signed in to change notification settings - Fork 362
Sealer Image Cache
Eric Bao edited this page Aug 6, 2021
·
1 revision
本文将描述sealer镜像的cache机制,即sealer build时会复用的cache,而非容器镜像的cache。
ChainID:ChainID的类型就是一个digest:type ChainID digest.Digest
,不过其含义是表示一组文件系统的digest值,所以这个值的计算是一个或多个layer组合计算来的。ChainID相同,则表示有着相同的文件系统,那么说明layer可复用,所以可以依靠ChainID进行cache命中。
sealer在启动时,会读取/var/lib/sealer文件系统,将所有layer进行读取。
func (cs *chainStore) newCacheLayer(layer *v1.Layer) (*Layer, error) {
var cacheLayer = Layer{Type: layer.Type, Value: layer.Value}
// only copy layer needs the cache id.
if layer.Type != common.COPYCOMMAND {
return &cacheLayer, nil
}
cacheIDBytes, err := cs.fs.GetMetadata(layer.ID, common.CacheID)
if err != nil {
return nil, err
}
// TODO maybe we should validate the cacheid over digest
cacheLayer.CacheID = string(cacheIDBytes)
return &cacheLayer, nil
}
func (cs *chainStore) restore() error {
cs.Lock()
defer cs.Unlock()
//read all image layers
images := cs.Images()
for _, image := range images {
layers := image.Spec.Layers
var lastChainItem *chainItem = &chainItem{}
for _, layer := range layers {
var (
chainID ChainID
err error
)
// 传入v1Layer, 获取cacheLayer。该函数特别的是,对于COPY类型的layer,我们会获取其CacheID,设置到cacheLayer对象上,其比其他类型layer就多了这个字段。
cacheLayer, err := cs.newCacheLayer(&layer)
if err != nil {
// 这里也许改成Debug会更合适,因为有些layer build失败,可能会没有设置cache id成功。再读的时候就会报错。
// 但是不会影响build,只是不会hit cache。
logger.Warn("failed to new a cache layer for %v, err: %s", layer, err)
continue
}
// first chainItem's parent chainID is empty
// 计算chainID的方法是传入parent ChainID。
// 具体算法是,digest (parent chainID : layer.CacheID : layer.Type : layer.Value)
chainID, err = cacheLayer.ChainID(lastChainItem.chainID)
if err != nil {
logger.Error(err)
break
}
logger.Debug("current layer %+v, restore chain id: %s", cacheLayer, chainID)
// 最后存到map中。
_, ok := cs.chains[chainID]
if !ok {
cItem := &chainItem{
layer: layer,
chainID: chainID,
}
cs.chains[chainID] = cItem
}
lastChainItem = &chainItem{
layer: layer,
chainID: chainID,
}
}
}
return nil
}
下面介绍下cache的命中。
//后面可能改成tryCache
func (l *LocalBuilder) goCache(parentID cache.ChainID, layer *v1.Layer, cacheService cache.Service) (continueCache bool, chainID cache.ChainID) {
var (
srcDigest = digest.Digest("")
err error
)
// specially for copy command, we would generate digest of src file as srcDigest.
// and use srcDigest as cacheID to generate a cacheLayer, eventually use the cacheLayer
// to hit the cache layer
// 计算copy中source文件的digest
if layer.Type == common.COPYCOMMAND {
srcDigest, err = l.generateSourceFilesDigest(strings.Fields(layer.Value)[0])
if err != nil {
logger.Warn("failed to generate src digest, discard cache, err: %s", err)
}
}
// 获取layer对应的cacheLayer,规则如上面提到的,copy layer会接受上面的digest作为CacheID。
cacheLayer := cacheService.NewCacheLayer(*layer, srcDigest)
// 试探能够撞到cache,最终就是到上面restore获得的map中查看。
cacheLayerID, err := l.Prober.Probe(parentID.String(), &cacheLayer)
if err != nil {
logger.Debug("failed to probe cache for %+v, err: %s", layer, err)
return false, ""
}
// cache hit
logger.Info("---> Using cache %v", cacheLayerID)
// 命中cache,该layer复用之前build成功的layer,这里的cacheLayerID不是cacheID,而是v1Layer中的ID。
layer.ID = cacheLayerID
cID, err := cacheLayer.ChainID(parentID)
if err != nil {
return false, ""
}
return true, cID
}