码迷,mamicode.com
首页 > 其他好文 > 详细

docker volume具体实现

时间:2015-11-05 19:12:54      阅读:312      评论:0      收藏:0      [点我收藏+]

标签:

想要了解Docker Volume,首先我们需要知道Docker的文件系统是如何工作的。Docker镜像是由多个文件系统(只读层)叠加而成。当我们启动一个容器的时候,Docker会加载只读镜像层并在其上(译者注:镜像栈顶部)添加一个读写层。如果运行中的容器修改了现有的一个已经存在的文件,那该文件将会从读写层下面的只读层复制到读写层,该文件的只读版本仍然存在,只是已经被读写层中该文件的副本所隐藏。当删除Docker容器,并通过该镜像重新启动时,之前的更改将会丢失。在Docker中,只读层及在顶部的读写层的组合被称为(联合文件系统)。

为了能够保存(持久化)数据以及共享容器间的数据,Docker提出了Volume的概念。简单来说,Volume就是目录或者文件,它可以绕过默认的联合文件系统,而以正常的文件或者目录的形式存在于宿主机上。

Volume的接口方式:

// Volume is a place to store data. It is backed by a specific driver, and can be mounted.
type Volume interface {
	// Name returns the name of the volume
	Name() string
	// DriverName returns the name of the driver which owns this volume.
	DriverName() string
	// Path returns the absolute path to the volume.
	Path() string
	// Mount mounts the volume and returns the absolute path to
	// where it can be consumed.
	Mount() (string, error)
	// Unmount unmounts the volume when it is no longer in use.
	Unmount() error
}

创建Root:

func New(scope string) (*Root, error) {
	rootDirectory := filepath.Join(scope, volumesPathName) 

	if err := os.MkdirAll(rootDirectory, 0700); err != nil {
		return nil, err
	}

	r := &Root{
		scope:   scope,
		path:    rootDirectory,
		volumes: make(map[string]*localVolume),
	}

	dirs, err := ioutil.ReadDir(rootDirectory)
	if err != nil {
		return nil, err
	}
        //主要是初始化Root结构的Volumes的map[string]*localVolume
	for _, d := range dirs {
		name := filepath.Base(d.Name())
		r.volumes[name] = &localVolume{
			driverName: r.Name(),
			name:       name,
			path:       r.DataPath(name),
		}
	}

	return r, nil
}

下面再来看看Root的结构

type Root struct {
	m       sync.Mutex  
	scope   string
	path    string
	volumes map[string]*localVolume  //主要是这个map结构      
}
//Root 申明 Driver 的接口,方便管理volumes的创建和删除

//Driver的接口
type Driver interface {
	// Name returns the name of the volume driver.
	Name() string
	// Create makes a new volume with the given id.
	Create(name string, opts map[string]string) (Volume, error)
	// Remove deletes the volume.
	Remove(Volume) error
}

创建Volume:

func (r *Root) Create(name string, _ map[string]string) (volume.Volume, error) {
	r.m.Lock()
	defer r.m.Unlock() //创建的时候需要锁

	v, exists := r.volumes[name]
	if exists {
		return v, nil
	}

	path := r.DataPath(name)
	if err := os.MkdirAll(path, 0755); err != nil {
		if os.IsExist(err) {
			return nil, fmt.Errorf("volume already exists under %s", filepath.Dir(path))
		}
		return nil, err
	}
	v = &localVolume{
		driverName: r.Name(),
		name:       name,
		path:       path,
	}
	r.volumes[name] = v
	return v, nil
}

同理删除和获取volume的方法:

func (r *Root) Remove(v volume.Volume) error {
	r.m.Lock()
	defer r.m.Unlock()
	lv, ok := v.(*localVolume)
	if !ok {
		return errors.New("unknown volume type")
	}

	realPath, err := filepath.EvalSymlinks(lv.path)
	if err != nil {
		return err
	}
	if !r.scopedPath(realPath) {
		return fmt.Errorf("Unable to remove a directory of out the Docker root: %s", realPath)
	}

	if err := os.RemoveAll(realPath); err != nil {
		return err
	}

	delete(r.volumes, lv.name)
	return os.RemoveAll(filepath.Dir(lv.path))
}

// Get looks up the volume for the given name and returns it if found
func (r *Root) Get(name string) (volume.Volume, error) {
	r.m.Lock()
	v, exists := r.volumes[name]
	r.m.Unlock()
	if !exists {
		return nil, ErrNotFound
	}
	return v, nil
}

具体什么时候调用local.New

func configureVolumes(config *Config) (*volumeStore, error) {
	volumesDriver, err := local.New(config.Root)
	if err != nil {
		return nil, err
	}
	volumedrivers.Register(volumesDriver, volumesDriver.Name())
	return newVolumeStore(volumesDriver.List()), nil
}

//在Daemon创建New Daemon时候Configure the volumes driver调用到



docker volume具体实现

标签:

原文地址:http://my.oschina.net/yang1992/blog/526595

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!