镜像服务是镜像操作的抽象接口,实际上对镜像的操作包含两部分,镜像信息和镜像数据;镜像服务基于镜像持久化服务image.StoreBackend提供的接口实现镜像信息的操作,通过镜像层服务image.LayerGetReleaser提供的镜像层操作的的操作,因为镜像都是由镜像层组成,也就是实际操作镜像数据。他们之间的关系大概如下:
接着我们先看下镜像服务,镜像持久化服务和镜像层服务的接口定义
在文件docker\image\store.go的镜像服务和镜像层服务接口:
// Store is an interface for creating and accessing images
type Store interface {
Create(config []byte) (ID, error)
Get(id ID) (*Image, error)
Delete(id ID) ([]layer.Metadata, error)
Search(partialID string) (ID, error)
SetParent(id ID, parent ID) error
GetParent(id ID) (ID, error)
Children(id ID) []ID
Map() map[ID]*Image
Heads() map[ID]*Image
}
// LayerGetReleaser is a minimal interface for getting and releasing images.
//实现在docker/layer/layer_store.go
type LayerGetReleaser interface {
Get(layer.ChainID) (layer.Layer, error)
Release(layer.Layer) ([]layer.Metadata, error)
}
在文件docker\image\fs.go的镜像持久化服务接口:
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
}
基本上就是增删改查之类的功能,再看下镜像服务的实现类store和返回该类对象的工厂函数NewImageStore:
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
}
// NewImageStore returns new store object for given layer store
func NewImageStore(fs StoreBackend, ls LayerGetReleaser) (Store, error) {
is := &store{
//实现在/docker/layer/layer_store.go
ls: ls,
images: make(map[ID]*imageMeta),
fs: fs,
digestSet: digest.NewSet(),
}
// load all current images and retain layers
if err := is.restore(); err != nil {
return nil, err
}
return is, nil
}
可以看到镜像服务实现类store成员中包含了镜像持久化服务image.StoreBackend和镜像层服务image.LayerGetReleaser,在而且两者是工厂函数的参数,工厂函数利用两个阐述参数传入的对象实现两个成员的初始化。所以我们还需要看下,镜像持久化服务image.StoreBackend和镜像层服务image.LayerGetReleaser的实现类。
镜像持久化服务image.StoreBackend实现类以及工厂函数,在docker\image\fs.go:
// fs implements StoreBackend using the filesystem.
type fs struct {
sync.RWMutex
root string
}
const (
contentDirName = "content"
metadataDirName = "metadata"
)
// NewFSStoreBackend returns new filesystem based backend for image.Store
func NewFSStoreBackend(root string) (StoreBackend, error) {
//传入镜像的存储位置 "/var/lib/docker/image/(graphDriver名)/imagedb"
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
}
镜像层服务image.LayerGetReleaser实现类以及工厂函数,实现在docker\layer\layer_store.go:
type layerStore struct {
store MetadataStore
driver graphdriver.Driver
layerMap map[ChainID]*roLayer
layerL sync.Mutex
mounts map[string]*mountedLayer
mountL sync.Mutex
}
// StoreOptions are the options used to create a new Store instance
type StoreOptions struct {
StorePath string
MetadataStorePathTemplate string
GraphDriver string
GraphDriverOptions []string
UIDMaps []idtools.IDMap
GIDMaps []idtools.IDMap
PluginGetter getter.PluginGetter
}
// NewStoreFromOptions creates a new Store instance
//没有实现RegisterWithDescriptor接口
func NewStoreFromOptions(options StoreOptions) (Store, error) {
driver, err := graphdriver.New(
options.StorePath,
options.GraphDriver,
options.GraphDriverOptions,
options.UIDMaps,
options.GIDMaps,
options.PluginGetter)
if err != nil {
return nil, fmt.Errorf("error initializing graphdriver: %v", err)
}
logrus.Debugf("Using graph driver %s", driver)
logrus.Debugf("StorePath :%s", options.StorePath)
fms, err := NewFSMetadataStore(fmt.Sprintf(options.MetadataStorePathTemplate, driver))
if err != nil {
return nil, err
}
return NewStoreFromGraphDriver(fms, driver)
}
// NewStoreFromGraphDriver creates a new Store instance using the provided
// metadata store and graph driver. The metadata store will be used to restore
// the Store.
看下他们是如何联系在一起的,这都是在docker\daemon\daemon.go的NewDaemon函数中处理的,看下函数调用过程:
看NewDaemon函数的代码片段:
graphDriver := d.layerStore.DriverName()
//镜像的存储位置"/var/lib/docker/image/(graphDriver名)"
imageRoot := filepath.Join(config.Root, "image", graphDriver)
// Configure and validate the kernels security support
if err := configureKernelSecuritySupport(config, graphDriver); err != nil {
return nil, err
}
logrus.Debugf("Max Concurrent Downloads: %d", *config.MaxConcurrentDownloads)
d.downloadManager = xfer.NewLayerDownloadManager(d.layerStore, *config.MaxConcurrentDownloads)
logrus.Debugf("Max Concurrent Uploads: %d", *config.MaxConcurrentUploads)
d.uploadManager = xfer.NewLayerUploadManager(*config.MaxConcurrentUploads)
//传入镜像的存储位置 "/var/lib/docker/image/(graphDriver名)/imagedb"
ifs, err := image.NewFSStoreBackend(filepath.Join(imageRoot, "imagedb"))
if err != nil {
return nil, err
}
在执行NewFSStoreBackend时,传入镜像信息的存储位置config.Root+/image/(graphDriver名)/imagedb,config.Root默认为/var/lib/docker,也就是镜像信息存储位置为”/var/lib/docker/image/(graphDriver名)/imagedb”:
在文件docker\daemon\config.go的InstallCommonFlags函数:
flags.StringVarP(&config.Root, "graph", "g", defaultGraph, "Root of the Docker runtime")
以及docker\daemon\config_unix.go:
var (
defaultPidFile = "/var/run/docker.pid"
defaultGraph = "/var/lib/docker"
defaultExecRoot = "/var/run/docker"
)
如我启用的存储驱动为overlay,存储位置为”/var/lib/docker/image/overlay/imagedb”: