標籤:docker devicemapper
// 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/devicemapperroot string//建立thin device名字使用的首碼,預設使用`docker-${major}:${minor}-${inode}-XXX-pool`devicePrefix stringTransactionId uint64NewTransactionId uint64nextDeviceId 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 stringmkfsArgs []string//格式化base image檔案系統時的選項dataDevice string//指定使用哪個裝置作為data device,eg,/dev/sdametadataDevice string//指定使用哪個裝置作為metadata device,eg,/dev/sdadoBlkDiscard boolthinpBlockSize uint32//thin pool block size}// devmapper的driver資料結構type Driver struct {*DeviceSethome string //home預設為/var/lib/docker/devicemapper}
docker使用device mapper的架構方式:
//初始化devicemapper driver//home=/var/lib/docker/devicemapper//options=device mapper的選項//調用路徑:newdevice->initfunc1.1 func Init(home string, options []string) (graphdriver.Driver, error) {//初始化devicesetdeviceSet, 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->NewDeviceSet1.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->initDevmapper1.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目錄所在裝置的 inodest, 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-pooldevices.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 poolif info.Exists == 0 {utils.Debugf("Pool doesn't exist. Creating it.")var (dataFile *os.FilemetadataFile *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 loopdeviceif !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...//沒有建立新loopback device,則從目錄/var/lib/docker/devicemapper/metadata/$ids//載入舊的metadataif !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/baseoldInfo, _ := devices.lookupDevice("")//之前已經建立,並完成了初始化,則直接成功返回if oldInfo != nil && oldInfo.Initialized {return nil}//已建立,但未完成初始化,刪除base deviceif oldInfo != nil && !oldInfo.Initialized {utils.Debugf("Removing uninitialized base image")if err := devices.deleteDevice(oldInfo); err != nil {return err}}//下一個可用的deviceidid := devices.nextDeviceId//建立base deviceif err := createDevice(devices.getPoolDevName(), &id); err != nil {return err}devices.nextDeviceId = (id + 1) & 0xffffff//向thin pool註冊base deviceutils.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 deviceif 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 = trueif err = devices.saveMetadata(info); err != nil {info.Initialized = falsereturn err}return nil}