rexray是EMC推出的一个为docker容器分配persistent volume的一款开源插件,最近在做这方面的二次开发项目,所以对这个插件总结一下:
在rexray的rexray/drivers/文件夹下,有三个目录,分别代表rexray目前所支持的几种driver:比如
os中:
const providerName = "linux"
type driver struct{
r *core.RexRay
}
storage中有以下几种产品的driver:
亚马逊的EWS:
const providerName = "ec2"
type driver struct{
instanceDocument *instanceIdentityDocument
ec2Instance *ec2.EC2
r *core.RexRay
}
谷歌的GCE:
const providerName = "gce"
type driver struct {
currentInstanceID string
client *compute.Service
r *core.RexRay
zone string
project string
}
EMC的isilon:
const providerName = "Isilon"
type driver struct {
client *isi.Client
r *core.RexRay
}
openstack:
const providerName = "Openstack"
type driver struct {
provider *gophercloud.ProviderClient
client *gophercloud.ServiceClient
clientBlockStorage *gophercloud.ServiceClient
clientBlockStoragev2 *gophercloud.ServiceClient
region string
availabilityZone string
instanceID string
r *core.RexRay
}
rackspace:
const providerName = "Rackspace"
type driver struct {
provider *gophercloud.ProviderClient
client *gophercloud.ServiceClient
clientBlockStorage *gophercloud.ServiceClient
region string
instanceID string
r *core.RexRay
EMC的scaleio:
const providerName = "ScaleIO"
type driver struct {
client *goscaleio.Client
system *goscaleio.System
protectionDomain *goscaleio.ProtectionDomain
storagePool *goscaleio.StoragePool
sdc *goscaleio.Sdc
r *core.RexRay
}
virtualbox:
const providerName = "virtualbox"
type driver struct {
virtualbox *vbox.VirtualBox
machine *vbox.Machine
r *core.RexRay
m sync.Mutex
}
EMC的vmax:
const providerName = "VMAX"
type driver struct {
client *govmax.SMIS
arrayID string
volPrefix string
instanceID string
vmh *govmax.VMHost
r *core.RexRay
}
EMC的xtremio:
const providerName = "XtremIO"
type driver struct {
client *xtio.Client
initiator xtio.Initiator
volumesSig string
lunMapsSig string
initiatorsSig string
volumesByNaa map[string]xtio.Volume
initiatorsByName map[string]xtio.Initiator
r *core.RexRay
}
Volume中:
const providerName = "docker"
type driver struct {
r *core.RexRay
}
以上,所有类型的driver都实现了下面这个接口:
type Driver interface {
Name() string
Init(rexray *RexRay) error
}
在引入所有driver所在的包时,都会在init函数中执行下面这个步骤:
core.RegisterDriver(providerName, newDriver)
在package core中,RegisterDriver函数如下所示:
func RegisterDriver(driverName string, ctor NewDriver) {
driverCtors[driverName] = ctor
}
其中,driverCtors的类型为:
driverCtors map[string]NewDriver
这样,以上所有driver实例都会被存放在driverCtors中。
下面首先看一下os。
对于os,定义了两个接口,如下所示:
type OSDriver interface {
Driver
GetMounts(string, string) (MountInfoArray, error)
Mounted(string) (bool, error)
Unmount(string) error
Mount(string, string, string, string) error
Format(string, string, bool) error
}
type OSDriverManager interface {
OSDriver
Drivers() <-chan OSDriver
}
os的driver实例(Linux)实现了上面的OSDriver这个接口。
下面是针对os driver的manager。
type odm struct {
rexray *RexRay
drivers map[string]OSDriver
}
其中,odm实现了OSDriverManager、OSDriver、Driver这几个接口。
对于,storage:
type StorageDriver interface {
Driver
GetVolumeMapping() ([]*BlockDevice, error)
GetInstance() (*Instance, error)
GetVolume(volumeID, volumeName string) ([]*Volume, error)
GetVolumeAttach(volumeID, instanceID string) ([]*VolumeAttachment, error)
CreateSnapshot(。。。
GetSnapshot(volumeID, snapshotID, snapshotName string) ([]*Snapshot, error)
RemoveSnapshot(snapshotID string) error
CreateVolume(
RemoveVolume(volumeID string) error
GetDeviceNextAvailable() (string, error)
AttachVolume(。。。
DetachVolume(runAsync bool, volumeID string, instanceID string, force bool) error
CopySnapshot(。。。
虽然没有仔细看每一个srotage driver的代码,但是我相信每一个storage driver的实例都应该实现了StorageDriver接口。
type StorageDriverManager interface {
StorageDriver
Drivers() <-chan StorageDriver
GetInstances() ([]*Instance, error)
}
下面是针对storage driver的manager
type sdm struct {
rexray *RexRay
drivers map[string]StorageDriver
}
其中,sdm实现了Driver、StorageDriver、StorageDriverManager这几个接口。
对于volume:
type VolumeDriver interface {
Driver
Mount(。。。
Unmount(volumeName, volumeID string) error
Path(volumeName, volumeID string) (string, error)
Create(volumeName string, opts VolumeOpts) error
Remove(volumeName string) error
Get(volumeName string) (VolumeMap, error)
List() ([]VolumeMap, error)
Attach(volumeName, instanceID string, force bool) (string, error)
Detach(volumeName, instanceID string, force bool) error
NetworkName(volumeName, instanceID string) (string, error)
}
volume实例(provider=docker)实现了VolumeDriver这个接口。
type VolumeDriverManager interface {
VolumeDriver
Drivers() <-chan VolumeDriver
UnmountAll() error
RemoveAll() error
DetachAll(instanceID string) error
}
type vdm struct {
rexray *RexRay
drivers map[string]VolumeDriver
m sync.Mutex
mapUsedCount map[string]*int
}
vdm实现了上面的Driver、VolumeDriver、VolumeDriverManager这三个接口。
Rexray是统一的存储管理平台,其具体结构如下所示:
type RexRay struct {
Config gofig.Config
OS OSDriverManager
Volume VolumeDriverManager
Storage StorageDriverManager
Context string
drivers map[string]Driver
}
下面的步骤将会把所有的driver实例添加到RexRay实例的drivers属性中:
for name, ctor := range driverCtors {
r.drivers[name] = ctor()
log.WithField("driverName", name).Debug("constructed driver")
}
下面的步骤则是将RexRay实例中的每一个driver实例进行初始化:
od := map[string]OSDriver{}
vd := map[string]VolumeDriver{}
sd := map[string]StorageDriver{}
for n, d := range r.drivers {
switch td := d.(type) {
case OSDriver:
if gotil.StringInSlice(n, osDrivers) {
if err := d.Init(r); err != nil {
log.WithFields(log.Fields{
"driverName": n,
"error": err}).Debug("error initializing driver")
}
od[n] = td
}
case VolumeDriver:
if gotil.StringInSlice(n, volDrivers) {
if err := d.Init(r); err != nil {
。。。
vd[n] = td
}
case StorageDriver:
if gotil.StringInSlice(n, storDrivers) {
if err := d.Init(r); err != nil {
。。。
sd[n] = td
}
r.OS = &odm{
rexray: r,
drivers: od,
}
r.Volume = &vdm{
rexray: r,
drivers: vd,
}
r.Storage = &sdm{
rexray: r,
drivers: sd,
}
完成以上的初始化步骤后,假设rexray开始工作则对应的流程以getVolume为例:
1、allVolumes, err := c.r.Storage.GetVolume(c.volumeID, c.volumeName)
2、c.r.Storage为sdm的实例,即执行func (r *sdm) GetVolume(volumeID, volumeName string) ([]*Volume, error)
3、for _, d := range r.drivers {
return d.GetVolume(volumeID, volumeName)
即执行具体的storage的GetVolume方法
4、以ECS为例,即
resp, err := d.ec2Instance.Volumes(volumeList, filter)