Bladeren bron

devmapper: Add --storage-opt options for basic devicemapper settings

This allows setting these settings to be passed:
dm.basesize
dm.loopdatasize
dm.loopmetadatasize

Docker-DCO-1.1-Signed-off-by: Alexander Larsson <alexl@redhat.com> (github: alexlarsson)
Alexander Larsson 11 jaren geleden
bovenliggende
commit
7f5ba068f4

+ 73 - 0
daemon/graphdriver/devmapper/README.md

@@ -0,0 +1,73 @@
+## devicemapper - a storage backend based on Device Mapper
+
+### Theory of operation
+
+The device mapper graphdriver uses the device mapper thin provisioning
+module (dm-thinp) to implement CoW snapshots. For each devicemapper
+graph locaion (typically `/var/lib/docker/devicemapper`, $graph below)
+a thin pool is created based on two block devices, one for data and
+one for metadata.  By default these block devices are created
+automatically by using loopback mounts of automatically creates sparse
+files.
+
+The default loopback files used are `$graph/devicemapper/data` and
+`$graph/devicemapper/metadata`. Additional metadata required to map
+from docker entities to the corresponding devicemapper volumes is
+stored in the `$graph/devicemapper/json` file (encoded as Json).
+
+In order to support multiple devicemapper graphs on a system the thin
+pool will be named something like: `docker-0:33-19478248-pool`, where
+the `0:30` part is the minor/major device nr and `19478248` is the
+inode number of the $graph directory.
+
+On the thin pool docker automatically creates a base thin device,
+called something like `docker-0:33-19478248-base` of a fixed
+size. This is automatically formated on creation and contains just an
+empty filesystem. This device is the base of all docker images and
+containers. All base images are snapshots of this device and those
+images are then in turn used as snapshots for other images and
+eventually containers.
+
+### options
+
+The devicemapper backend supports some options that you can specify
+when starting the docker daemon using the --storage-opt flags.
+This uses the `dm` prefix and would be used somthing like `docker -d --storage-opt dm.foo=bar`.
+
+Here is the list of supported options:
+
+ *  `dm.basesize`
+
+    Specifies the size to use when creating the base device, which
+    limits the size of images and containers. The default value is
+    10G. Note, thin devices are inherently "sparse", so a 10G device
+    which is mostly empty doesn't use 10 GB of space on the
+    pool. However, the filesystem will use more space for the empty
+    case the larger the device is.
+
+    Example use:
+
+    ``docker -d --storage-opt dm.basesize=20G``
+
+ *  `dm.loopdatasize`
+
+    Specifies the size to use when creating the loopback file for the
+    "data" device which is used for the thin pool. The default size is
+    100G. Note that the file is sparse, so it will not initially take
+    up this much space.
+
+    Example use:
+
+    ``docker -d --storage-opt dm.loopdatasize=200G``
+
+ *  `dm.loopmetadatasize`
+
+    Specifies the size to use when creating the loopback file for the
+    "metadadata" device which is used for the thin pool. The default size is
+    2G. Note that the file is sparse, so it will not initially take
+    up this much space.
+
+    Example use:
+
+    ``docker -d --storage-opt dm.loopmetadatasize=4G``
+

+ 47 - 7
daemon/graphdriver/devmapper/deviceset.go

@@ -13,12 +13,14 @@ import (
 	"path"
 	"path/filepath"
 	"strconv"
+	"strings"
 	"sync"
 	"syscall"
 	"time"
 
 	"github.com/dotcloud/docker/daemon/graphdriver"
 	"github.com/dotcloud/docker/pkg/label"
+	"github.com/dotcloud/docker/pkg/units"
 	"github.com/dotcloud/docker/utils"
 )
 
@@ -65,6 +67,11 @@ type DeviceSet struct {
 	TransactionId    uint64
 	NewTransactionId uint64
 	nextDeviceId     int
+
+	// Options
+	dataLoopbackSize     int64
+	metaDataLoopbackSize int64
+	baseFsSize           uint64
 }
 
 type DiskUsage struct {
@@ -378,8 +385,8 @@ func (devices *DeviceSet) setupBaseImage() error {
 	// Ids are 24bit, so wrap around
 	devices.nextDeviceId = (id + 1) & 0xffffff
 
-	utils.Debugf("Registering base device (id %v) with FS size %v", id, DefaultBaseFsSize)
-	info, err := devices.registerDevice(id, "", DefaultBaseFsSize)
+	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)
 		utils.Debugf("\n--->Err: %s\n", err)
@@ -567,12 +574,12 @@ func (devices *DeviceSet) initDevmapper(doInit bool) error {
 		}
 
 		createdLoopback = !hasData || !hasMetadata
-		data, err := devices.ensureImage("data", DefaultDataLoopbackSize)
+		data, err := devices.ensureImage("data", devices.dataLoopbackSize)
 		if err != nil {
 			utils.Debugf("Error device ensureImage (data): %s\n", err)
 			return err
 		}
-		metadata, err := devices.ensureImage("metadata", DefaultMetaDataLoopbackSize)
+		metadata, err := devices.ensureImage("metadata", devices.metaDataLoopbackSize)
 		if err != nil {
 			utils.Debugf("Error device ensureImage (metadata): %s\n", err)
 			return err
@@ -1091,12 +1098,45 @@ func (devices *DeviceSet) Status() *Status {
 	return status
 }
 
-func NewDeviceSet(root string, doInit bool) (*DeviceSet, error) {
+func NewDeviceSet(root string, doInit bool, options []string) (*DeviceSet, error) {
 	SetDevDir("/dev")
 
 	devices := &DeviceSet{
-		root:     root,
-		MetaData: MetaData{Devices: make(map[string]*DevInfo)},
+		root:                 root,
+		MetaData:             MetaData{Devices: make(map[string]*DevInfo)},
+		dataLoopbackSize:     DefaultDataLoopbackSize,
+		metaDataLoopbackSize: DefaultMetaDataLoopbackSize,
+		baseFsSize:           DefaultBaseFsSize,
+	}
+
+	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.FromHumanSize(val)
+			if err != nil {
+				return nil, err
+			}
+			devices.baseFsSize = uint64(size)
+		case "dm.loopdatasize":
+			size, err := units.FromHumanSize(val)
+			if err != nil {
+				return nil, err
+			}
+			devices.dataLoopbackSize = size
+		case "dm.loopmetadatasize":
+			size, err := units.FromHumanSize(val)
+			if err != nil {
+				return nil, err
+			}
+			devices.metaDataLoopbackSize = size
+		default:
+			return nil, fmt.Errorf("Unknown option %s\n", key)
+		}
 	}
 
 	if err := devices.initDevmapper(doInit); err != nil {

+ 1 - 1
daemon/graphdriver/devmapper/driver.go

@@ -27,7 +27,7 @@ type Driver struct {
 }
 
 func Init(home string, options []string) (graphdriver.Driver, error) {
-	deviceSet, err := NewDeviceSet(home, true)
+	deviceSet, err := NewDeviceSet(home, true, options)
 	if err != nil {
 		return nil, err
 	}