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)
This commit is contained in:
parent
822ea97ffc
commit
7f5ba068f4
3 changed files with 121 additions and 8 deletions
73
daemon/graphdriver/devmapper/README.md
Normal file
73
daemon/graphdriver/devmapper/README.md
Normal file
|
@ -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``
|
||||
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue