瀏覽代碼

Merge pull request #19123 from shishir-a412ed/rootfs_size_configurable

 daemon option (--storage-opt dm.basesize) for increasing the base device size on daemon restart
Sebastiaan van Stijn 9 年之前
父節點
當前提交
661d75f398

+ 79 - 4
daemon/graphdriver/devmapper/deviceset.go

@@ -35,7 +35,7 @@ import (
 var (
 var (
 	defaultDataLoopbackSize     int64  = 100 * 1024 * 1024 * 1024
 	defaultDataLoopbackSize     int64  = 100 * 1024 * 1024 * 1024
 	defaultMetaDataLoopbackSize int64  = 2 * 1024 * 1024 * 1024
 	defaultMetaDataLoopbackSize int64  = 2 * 1024 * 1024 * 1024
-	defaultBaseFsSize           uint64 = 100 * 1024 * 1024 * 1024
+	defaultBaseFsSize           uint64 = 10 * 1024 * 1024 * 1024
 	defaultThinpBlockSize       uint32 = 128 // 64K = 128 512b sectors
 	defaultThinpBlockSize       uint32 = 128 // 64K = 128 512b sectors
 	defaultUdevSyncOverride            = false
 	defaultUdevSyncOverride            = false
 	maxDeviceID                        = 0xffffff // 24 bit, pool limit
 	maxDeviceID                        = 0xffffff // 24 bit, pool limit
@@ -47,6 +47,7 @@ var (
 	driverDeferredRemovalSupport = false
 	driverDeferredRemovalSupport = false
 	enableDeferredRemoval        = false
 	enableDeferredRemoval        = false
 	enableDeferredDeletion       = false
 	enableDeferredDeletion       = false
+	userBaseSize                 = false
 )
 )
 
 
 const deviceSetMetaFile string = "deviceset-metadata"
 const deviceSetMetaFile string = "deviceset-metadata"
@@ -1056,6 +1057,80 @@ func (devices *DeviceSet) setupVerifyBaseImageUUIDFS(baseInfo *devInfo) error {
 	return nil
 	return nil
 }
 }
 
 
+func (devices *DeviceSet) checkGrowBaseDeviceFS(info *devInfo) error {
+
+	if !userBaseSize {
+		return nil
+	}
+
+	if devices.baseFsSize < devices.getBaseDeviceSize() {
+		return fmt.Errorf("devmapper: Base device size cannot be smaller than %s", units.HumanSize(float64(devices.getBaseDeviceSize())))
+	}
+
+	if devices.baseFsSize == devices.getBaseDeviceSize() {
+		return nil
+	}
+
+	info.lock.Lock()
+	defer info.lock.Unlock()
+
+	devices.Lock()
+	defer devices.Unlock()
+
+	info.Size = devices.baseFsSize
+
+	if err := devices.saveMetadata(info); err != nil {
+		// Try to remove unused device
+		delete(devices.Devices, info.Hash)
+		return err
+	}
+
+	return devices.growFS(info)
+}
+
+func (devices *DeviceSet) growFS(info *devInfo) error {
+	if err := devices.activateDeviceIfNeeded(info, false); err != nil {
+		return fmt.Errorf("Error activating devmapper device: %s", err)
+	}
+
+	defer devices.deactivateDevice(info)
+
+	fsMountPoint := "/run/docker/mnt"
+	if _, err := os.Stat(fsMountPoint); os.IsNotExist(err) {
+		if err := os.MkdirAll(fsMountPoint, 0700); err != nil {
+			return err
+		}
+		defer os.RemoveAll(fsMountPoint)
+	}
+
+	options := ""
+	if devices.BaseDeviceFilesystem == "xfs" {
+		// XFS needs nouuid or it can't mount filesystems with the same fs
+		options = joinMountOptions(options, "nouuid")
+	}
+	options = joinMountOptions(options, devices.mountOptions)
+
+	if err := mount.Mount(info.DevName(), fsMountPoint, devices.BaseDeviceFilesystem, options); err != nil {
+		return fmt.Errorf("Error mounting '%s' on '%s': %s", info.DevName(), fsMountPoint, err)
+	}
+
+	defer syscall.Unmount(fsMountPoint, syscall.MNT_DETACH)
+
+	switch devices.BaseDeviceFilesystem {
+	case "ext4":
+		if out, err := exec.Command("resize2fs", info.DevName()).CombinedOutput(); err != nil {
+			return fmt.Errorf("Failed to grow rootfs:%v:%s", err, string(out))
+		}
+	case "xfs":
+		if out, err := exec.Command("xfs_growfs", info.DevName()).CombinedOutput(); err != nil {
+			return fmt.Errorf("Failed to grow rootfs:%v:%s", err, string(out))
+		}
+	default:
+		return fmt.Errorf("Unsupported filesystem type %s", devices.BaseDeviceFilesystem)
+	}
+	return nil
+}
+
 func (devices *DeviceSet) setupBaseImage() error {
 func (devices *DeviceSet) setupBaseImage() error {
 	oldInfo, _ := devices.lookupDeviceWithLock("")
 	oldInfo, _ := devices.lookupDeviceWithLock("")
 
 
@@ -1069,9 +1144,8 @@ func (devices *DeviceSet) setupBaseImage() error {
 				return err
 				return err
 			}
 			}
 
 
-			if devices.baseFsSize != defaultBaseFsSize && devices.baseFsSize != devices.getBaseDeviceSize() {
-				logrus.Warnf("devmapper: Base device is already initialized to size %s, new value of base device size %s will not take effect",
-					units.HumanSize(float64(devices.getBaseDeviceSize())), units.HumanSize(float64(devices.baseFsSize)))
+			if err := devices.checkGrowBaseDeviceFS(oldInfo); err != nil {
+				return err
 			}
 			}
 
 
 			return nil
 			return nil
@@ -2378,6 +2452,7 @@ func NewDeviceSet(root string, doInit bool, options []string, uidMaps, gidMaps [
 			if err != nil {
 			if err != nil {
 				return nil, err
 				return nil, err
 			}
 			}
+			userBaseSize = true
 			devices.baseFsSize = uint64(size)
 			devices.baseFsSize = uint64(size)
 		case "dm.loopdatasize":
 		case "dm.loopdatasize":
 			size, err := units.RAMInBytes(val)
 			size, err := units.RAMInBytes(val)

+ 15 - 3
docs/reference/commandline/daemon.md

@@ -213,11 +213,23 @@ options for `zfs` start with `zfs`.
 *  `dm.basesize`
 *  `dm.basesize`
 
 
     Specifies the size to use when creating the base device, which limits the
     Specifies the size to use when creating the base device, which limits the
-    size of images and containers. The default value is 100G. Note, thin devices
-    are inherently "sparse", so a 100G device which is mostly empty doesn't use
-    100 GB of space on the pool. However, the filesystem will use more space for
+    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.
     the empty case the larger the device is.
 
 
+    The base device size can be increased at daemon restart which will allow
+    all future images and containers (based on those new images) to be of the 
+    new base device size.
+
+    Example use: 
+
+        $ docker daemon --storage-opt dm.basesize=50G
+
+    This will increase the base device size to 50G. The Docker daemon will throw an 
+    error if existing base device size is larger than 50G. A user can use 
+    this option to expand the base device size however shrinking is not permitted.
+
     This value affects the system-wide "base" empty filesystem
     This value affects the system-wide "base" empty filesystem
     that may already be initialized and inherited by pulled images. Typically,
     that may already be initialized and inherited by pulled images. Typically,
     a change to this value requires additional steps to take effect:
     a change to this value requires additional steps to take effect:

+ 3 - 3
docs/userguide/storagedriver/device-mapper-driver.md

@@ -249,11 +249,11 @@ You can use the `lsblk` command to see the device files created above and the `p
     NAME                       MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
     NAME                       MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
     xvda                       202:0    0    8G  0 disk
     xvda                       202:0    0    8G  0 disk
     └─xvda1                    202:1    0    8G  0 part /
     └─xvda1                    202:1    0    8G  0 part /
-    xvdf                       202:80   0  100G  0 disk
+    xvdf                       202:80   0   10G  0 disk
     ├─vg--docker-data          253:0    0   90G  0 lvm
     ├─vg--docker-data          253:0    0   90G  0 lvm
-    │ └─docker-202:1-1032-pool 253:2    0  100G  0 dm
+    │ └─docker-202:1-1032-pool 253:2    0   10G  0 dm
     └─vg--docker-metadata      253:1    0    4G  0 lvm
     └─vg--docker-metadata      253:1    0    4G  0 lvm
-      └─docker-202:1-1032-pool 253:2    0  100G  0 dm
+      └─docker-202:1-1032-pool 253:2    0   10G  0 dm
 
 
 The diagram below shows the image from prior examples updated with the detail from the `lsblk` command above.
 The diagram below shows the image from prior examples updated with the detail from the `lsblk` command above.
 
 

+ 13 - 3
man/docker-daemon.8.md

@@ -271,12 +271,22 @@ Example use: `docker daemon --storage-opt dm.thinpooldev=/dev/mapper/thin-pool`
 #### dm.basesize
 #### dm.basesize
 
 
 Specifies the size to use when creating the base device, which limits
 Specifies the size to use when creating the base device, which limits
-the size of images and containers. The default value is 100G. Note,
-thin devices are inherently "sparse", so a 100G device which is mostly
-empty doesn't use 100 GB of space on the pool. However, the filesystem
+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 base images the larger the device
 will use more space for base images the larger the device
 is.
 is.
 
 
+The base device size can be increased at daemon restart which will allow
+all future images and containers (based on those new images) to be of the 
+new base device size.
+
+Example use: `docker daemon --storage-opt dm.basesize=50G` 
+
+This will increase the base device size to 50G. The Docker daemon will throw an 
+error if existing base device size is larger than 50G. A user can use 
+this option to expand the base device size however shrinking is not permitted.
+
 This value affects the system-wide "base" empty filesystem that may already
 This value affects the system-wide "base" empty filesystem that may already
 be initialized and inherited by pulled images. Typically, a change to this
 be initialized and inherited by pulled images. Typically, a change to this
 value requires additional steps to take effect:
 value requires additional steps to take effect: