标签:
想要了解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调用到
标签:
原文地址:http://my.oschina.net/yang1992/blog/526595