844
技術社區[雲棲]
graph driver-device mapper-01driver初始化
// thin device數據結構
type DevInfo struct {
Hash string `json:"-"`
DeviceId int `json:"device_id"`
Size uint64 `json:"size"`
TransactionId uint64 `json:"transaction_id"`
Initialized bool `json:"initialized"`
devices *DeviceSet `json:"-"`
mountCount int `json:"-"`
mountPath string `json:"-"`
lock sync.Mutex `json:"-"`
}
// thin pool數據結構
type DeviceSet struct {
MetaData
//根目錄,默認為/var/lib/docker/devicemapper
root string
//創建thin device名字使用的前綴,`docker-${major}:${minor}-${inode}`
devicePrefix string
TransactionId uint64
NewTransactionId uint64
nextDeviceId int
//選項
dataLoopbackSize int64 ///var/lib/docker /devicemapper/devicemapper/data稀疏文件大小
metaDataLoopbackSize int64 ///var/lib/docker/devicemapper/devicemapper/metadata稀疏文件大小
baseFsSize uint64 //base image之上格式化的文件係統大小
filesystem string //base image之上格式化的文件係統類型
mountOptions string
mkfsArgs []string //格式化base image文件係統時的選項
dataDevice string //指定使用哪個設備作為data device,eg,/dev/sda
metadataDevice string //指定使用哪個設備作為metadata device,eg,/dev/sda
doBlkDiscard bool
thinpBlockSize uint32 //thin pool block size
}
// devmapper的driver數據結構
type Driver struct {
*DeviceSet
home string //home默認為/var/lib/docker/devicemapper
}
docker使用device mapper的架構方式:

//初始化devicemapper driver
// home=/var/lib/docker/devicemapper
// options=device mapper的選項
// 調用路徑:newdevice->initfunc
1.1 func Init(home string, options []string) (graphdriver.Driver, error) {
//初始化deviceset
deviceSet, err := NewDeviceSet(home, true, options)
if err != nil {
return nil, err
}
...
d := &Driver{
DeviceSet: deviceSet,
home: home,
}
return d, nil
}
//初始化deviceset
// device set root=/var/lib/docker/devicemapper
// 調用路徑:Init->NewDeviceSet
1.2 func NewDeviceSet(root string, doInit bool, options []string) (*DeviceSet, error) {
SetDevDir("/dev")
devices := &DeviceSet{
root: root,
//metaData通過deviceID存放thin device的配置信息
MetaData: MetaData{Devices: make(map[string]*DevInfo)},
dataLoopbackSize: DefaultDataLoopbackSize,
metaDataLoopbackSize: DefaultMetaDataLoopbackSize,
baseFsSize: DefaultBaseFsSize,
filesystem: "ext4",
doBlkDiscard: true,
thinpBlockSize: DefaultThinpBlockSize,
}
//初始化deviceset選項參數
for _, option := range options {
key, val, err := utils.ParseKeyValueOpt(option)
if err != nil {
return nil, err
}
key = strings.ToLower(key)
switch key {
case "dm.basesize":
size, err := units.RAMInBytes(val)
if err != nil {
return nil, err
}
devices.baseFsSize = uint64(size)
...
default:
return nil, fmt.Errorf("Unknown option %s\n", key)
}
}
//由deviceset繼續完成初始化
if err := devices.initDevmapper(doInit); err != nil {
return nil, err
}
return devices, nil
}
// 初始化thin pool
// 調用路徑:NewDeviceSet->initDevmapper
1.3 func (devices *DeviceSet) initDevmapper(doInit bool) error {
logInit(devices)
//創建/var/lib/docker/devicemapper/metadata目錄
if err := os.MkdirAll(devices.metadataDir(), 0700); err != nil && !os.IsExist(err) {
return err
}
//獲取/var/lib/docker目錄所在設備的 inode
st, err := os.Stat(devices.root)
if err != nil {
return fmt.Errorf("Error looking up dir %s: %s", devices.root, err)
}
sysSt := st.Sys().(*syscall.Stat_t)
//thin device取名規則docker-$major:$minor-$inode-$imageid/$containerid
//thin poll取名為docker-$major:$minor-$inode-pool
devices.devicePrefix = fmt.Sprintf("docker-%d:%d-%d", major(sysSt.Dev), minor(sysSt.Dev), sysSt.Ino)
//如果thin pool device存在,獲取device的信息
utils.Debugf("Checking for existence of the pool '%s'", devices.getPoolName())
info, err := getInfo(devices.getPoolName())
if info == nil {
utils.Debugf("Error device getInfo: %s", err)
return err
}
setCloseOnExec("/dev/mapper/control")
createdLoopback := false
//創建thin pool
if info.Exists == 0 {
utils.Debugf("Pool doesn't exist. Creating it.")
var (
dataFile *os.File
metadataFile *os.File
)
//沒有指定datadevice設備
if devices.dataDevice == "" {
//檢查/var/lib/docker/devicemapper/devicemapper/data文件是否存在
hasData := devices.hasImage("data")
//既不要求初始化新的devicemapper,又沒有舊的data文件
if !doInit && !hasData {
//返回錯誤
return errors.New("Loopback data file not found")
}
//創建data loopdevice
if !hasData {
createdLoopback = true
}
//創建/var/lib/docker/devicemapper/devicemapper/data 稀疏文件
data, err := devices.ensureImage("data", devices.dataLoopbackSize)
if err != nil {
utils.Debugf("Error device ensureImage (data): %s\n", err)
return err
}
//data文件與loopback device關聯
dataFile, err = attachLoopDevice(data)
if err != nil {
return err
}
} else {
//如果指定了data device,則打開
dataFile, err = os.OpenFile(devices.dataDevice, os.O_RDWR, 0600)
if err != nil {
return err
}
}
defer dataFile.Close()
//通過同樣的辦法初始化metadata device
...
//創建thin pool
if err := createPool(devices.getPoolName(), dataFile, metadataFile, devices.thinpBlockSize); err != nil {
return err
}
//沒有創建新loopback device,則從目錄/var/lib/docker/devicemapper/metadata/$ids
//加載舊的metadata
if !createdLoopback {
if err = devices.initMetaData(); err != nil {
return err
}
}
//初始化一個新的空鏡像文件,作為所有鏡像的祖先鏡像
if doInit {
if err := devices.setupBaseImage(); err != nil {
utils.Debugf("Error device setupBaseImage: %s\n", err)
return err
}
}
return nil
}
// 創建祖先鏡像
1.4 func (devices *DeviceSet) setupBaseImage() error {
//祖先鏡像的描述信息存放在/var/lib/docker/devicemapper/metadata/base
oldInfo, _ := devices.lookupDevice("")
//之前已經創建,並完成了初始化,則直接成功返回
if oldInfo != nil && oldInfo.Initialized {
return nil
}
//已創建,但未完成初始化,刪除base device
if oldInfo != nil && !oldInfo.Initialized {
utils.Debugf("Removing uninitialized base image")
if err := devices.deleteDevice(oldInfo); err != nil {
return err
}
}
//下一個可用的deviceid
id := devices.nextDeviceId
//創建base device
if err := createDevice(devices.getPoolDevName(), &id); err != nil {
return err
}
devices.nextDeviceId = (id + 1) & 0xffffff
//向thin pool注冊base device
utils.Debugf("Registering base device (id %v) with FS size %v", id, devices.baseFsSize)
info, err := devices.registerDevice(id, "", devices.baseFsSize)
if err != nil {
_ = deleteDevice(devices.getPoolDevName(), id)
return err
}
//激活base device
if err = devices.activateDeviceIfNeeded(info); err != nil {
return err
}
//在base device之上格式化新文件係統
if err := devices.createFilesystem(info); err != nil {
return err
}
//完成初始化,保存metadata到/var/lib/docker/devicemapper/metadata/base中
info.Initialized = true
if err = devices.saveMetadata(info); err != nil {
info.Initialized = false
return err
}
return nil
}
最後更新:2017-04-03 05:39:31