Signed-off-by: Shishir Mahajan <shishir.mahajan@redhat.com>
| ... | ... |
@@ -35,7 +35,7 @@ import ( |
| 35 | 35 |
var ( |
| 36 | 36 |
defaultDataLoopbackSize int64 = 100 * 1024 * 1024 * 1024 |
| 37 | 37 |
defaultMetaDataLoopbackSize int64 = 2 * 1024 * 1024 * 1024 |
| 38 |
- defaultBaseFsSize uint64 = 100 * 1024 * 1024 * 1024 |
|
| 38 |
+ defaultBaseFsSize uint64 = 10 * 1024 * 1024 * 1024 |
|
| 39 | 39 |
defaultThinpBlockSize uint32 = 128 // 64K = 128 512b sectors |
| 40 | 40 |
defaultUdevSyncOverride = false |
| 41 | 41 |
maxDeviceID = 0xffffff // 24 bit, pool limit |
| ... | ... |
@@ -47,6 +47,7 @@ var ( |
| 47 | 47 |
driverDeferredRemovalSupport = false |
| 48 | 48 |
enableDeferredRemoval = false |
| 49 | 49 |
enableDeferredDeletion = false |
| 50 |
+ userBaseSize = false |
|
| 50 | 51 |
) |
| 51 | 52 |
|
| 52 | 53 |
const deviceSetMetaFile string = "deviceset-metadata" |
| ... | ... |
@@ -1056,6 +1057,80 @@ func (devices *DeviceSet) setupVerifyBaseImageUUIDFS(baseInfo *devInfo) error {
|
| 1056 | 1056 |
return nil |
| 1057 | 1057 |
} |
| 1058 | 1058 |
|
| 1059 |
+func (devices *DeviceSet) checkGrowBaseDeviceFS(info *devInfo) error {
|
|
| 1060 |
+ |
|
| 1061 |
+ if !userBaseSize {
|
|
| 1062 |
+ return nil |
|
| 1063 |
+ } |
|
| 1064 |
+ |
|
| 1065 |
+ if devices.baseFsSize < devices.getBaseDeviceSize() {
|
|
| 1066 |
+ return fmt.Errorf("devmapper: Base device size cannot be smaller than %s", units.HumanSize(float64(devices.getBaseDeviceSize())))
|
|
| 1067 |
+ } |
|
| 1068 |
+ |
|
| 1069 |
+ if devices.baseFsSize == devices.getBaseDeviceSize() {
|
|
| 1070 |
+ return nil |
|
| 1071 |
+ } |
|
| 1072 |
+ |
|
| 1073 |
+ info.lock.Lock() |
|
| 1074 |
+ defer info.lock.Unlock() |
|
| 1075 |
+ |
|
| 1076 |
+ devices.Lock() |
|
| 1077 |
+ defer devices.Unlock() |
|
| 1078 |
+ |
|
| 1079 |
+ info.Size = devices.baseFsSize |
|
| 1080 |
+ |
|
| 1081 |
+ if err := devices.saveMetadata(info); err != nil {
|
|
| 1082 |
+ // Try to remove unused device |
|
| 1083 |
+ delete(devices.Devices, info.Hash) |
|
| 1084 |
+ return err |
|
| 1085 |
+ } |
|
| 1086 |
+ |
|
| 1087 |
+ return devices.growFS(info) |
|
| 1088 |
+} |
|
| 1089 |
+ |
|
| 1090 |
+func (devices *DeviceSet) growFS(info *devInfo) error {
|
|
| 1091 |
+ if err := devices.activateDeviceIfNeeded(info, false); err != nil {
|
|
| 1092 |
+ return fmt.Errorf("Error activating devmapper device: %s", err)
|
|
| 1093 |
+ } |
|
| 1094 |
+ |
|
| 1095 |
+ defer devices.deactivateDevice(info) |
|
| 1096 |
+ |
|
| 1097 |
+ fsMountPoint := "/run/docker/mnt" |
|
| 1098 |
+ if _, err := os.Stat(fsMountPoint); os.IsNotExist(err) {
|
|
| 1099 |
+ if err := os.MkdirAll(fsMountPoint, 0700); err != nil {
|
|
| 1100 |
+ return err |
|
| 1101 |
+ } |
|
| 1102 |
+ defer os.RemoveAll(fsMountPoint) |
|
| 1103 |
+ } |
|
| 1104 |
+ |
|
| 1105 |
+ options := "" |
|
| 1106 |
+ if devices.BaseDeviceFilesystem == "xfs" {
|
|
| 1107 |
+ // XFS needs nouuid or it can't mount filesystems with the same fs |
|
| 1108 |
+ options = joinMountOptions(options, "nouuid") |
|
| 1109 |
+ } |
|
| 1110 |
+ options = joinMountOptions(options, devices.mountOptions) |
|
| 1111 |
+ |
|
| 1112 |
+ if err := mount.Mount(info.DevName(), fsMountPoint, devices.BaseDeviceFilesystem, options); err != nil {
|
|
| 1113 |
+ return fmt.Errorf("Error mounting '%s' on '%s': %s", info.DevName(), fsMountPoint, err)
|
|
| 1114 |
+ } |
|
| 1115 |
+ |
|
| 1116 |
+ defer syscall.Unmount(fsMountPoint, syscall.MNT_DETACH) |
|
| 1117 |
+ |
|
| 1118 |
+ switch devices.BaseDeviceFilesystem {
|
|
| 1119 |
+ case "ext4": |
|
| 1120 |
+ if out, err := exec.Command("resize2fs", info.DevName()).CombinedOutput(); err != nil {
|
|
| 1121 |
+ return fmt.Errorf("Failed to grow rootfs:%v:%s", err, string(out))
|
|
| 1122 |
+ } |
|
| 1123 |
+ case "xfs": |
|
| 1124 |
+ if out, err := exec.Command("xfs_growfs", info.DevName()).CombinedOutput(); err != nil {
|
|
| 1125 |
+ return fmt.Errorf("Failed to grow rootfs:%v:%s", err, string(out))
|
|
| 1126 |
+ } |
|
| 1127 |
+ default: |
|
| 1128 |
+ return fmt.Errorf("Unsupported filesystem type %s", devices.BaseDeviceFilesystem)
|
|
| 1129 |
+ } |
|
| 1130 |
+ return nil |
|
| 1131 |
+} |
|
| 1132 |
+ |
|
| 1059 | 1133 |
func (devices *DeviceSet) setupBaseImage() error {
|
| 1060 | 1134 |
oldInfo, _ := devices.lookupDeviceWithLock("")
|
| 1061 | 1135 |
|
| ... | ... |
@@ -1069,9 +1144,8 @@ func (devices *DeviceSet) setupBaseImage() error {
|
| 1069 | 1069 |
return err |
| 1070 | 1070 |
} |
| 1071 | 1071 |
|
| 1072 |
- if devices.baseFsSize != defaultBaseFsSize && devices.baseFsSize != devices.getBaseDeviceSize() {
|
|
| 1073 |
- logrus.Warnf("devmapper: Base device is already initialized to size %s, new value of base device size %s will not take effect",
|
|
| 1074 |
- units.HumanSize(float64(devices.getBaseDeviceSize())), units.HumanSize(float64(devices.baseFsSize))) |
|
| 1072 |
+ if err := devices.checkGrowBaseDeviceFS(oldInfo); err != nil {
|
|
| 1073 |
+ return err |
|
| 1075 | 1074 |
} |
| 1076 | 1075 |
|
| 1077 | 1076 |
return nil |
| ... | ... |
@@ -2379,6 +2453,7 @@ func NewDeviceSet(root string, doInit bool, options []string, uidMaps, gidMaps [ |
| 2379 | 2379 |
if err != nil {
|
| 2380 | 2380 |
return nil, err |
| 2381 | 2381 |
} |
| 2382 |
+ userBaseSize = true |
|
| 2382 | 2383 |
devices.baseFsSize = uint64(size) |
| 2383 | 2384 |
case "dm.loopdatasize": |
| 2384 | 2385 |
size, err := units.RAMInBytes(val) |
| ... | ... |
@@ -213,11 +213,23 @@ options for `zfs` start with `zfs`. |
| 213 | 213 |
* `dm.basesize` |
| 214 | 214 |
|
| 215 | 215 |
Specifies the size to use when creating the base device, which limits the |
| 216 |
- size of images and containers. The default value is 100G. Note, thin devices |
|
| 217 |
- are inherently "sparse", so a 100G device which is mostly empty doesn't use |
|
| 218 |
- 100 GB of space on the pool. However, the filesystem will use more space for |
|
| 216 |
+ size of images and containers. The default value is 10G. Note, thin devices |
|
| 217 |
+ are inherently "sparse", so a 10G device which is mostly empty doesn't use |
|
| 218 |
+ 10 GB of space on the pool. However, the filesystem will use more space for |
|
| 219 | 219 |
the empty case the larger the device is. |
| 220 | 220 |
|
| 221 |
+ The base device size can be increased at daemon restart which will allow |
|
| 222 |
+ all future images and containers (based on those new images) to be of the |
|
| 223 |
+ new base device size. |
|
| 224 |
+ |
|
| 225 |
+ Example use: |
|
| 226 |
+ |
|
| 227 |
+ $ docker daemon --storage-opt dm.basesize=50G |
|
| 228 |
+ |
|
| 229 |
+ This will increase the base device size to 50G. The Docker daemon will throw an |
|
| 230 |
+ error if existing base device size is larger than 50G. A user can use |
|
| 231 |
+ this option to expand the base device size however shrinking is not permitted. |
|
| 232 |
+ |
|
| 221 | 233 |
This value affects the system-wide "base" empty filesystem |
| 222 | 234 |
that may already be initialized and inherited by pulled images. Typically, |
| 223 | 235 |
a change to this value requires additional steps to take effect: |
| ... | ... |
@@ -249,11 +249,11 @@ You can use the `lsblk` command to see the device files created above and the `p |
| 249 | 249 |
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT |
| 250 | 250 |
xvda 202:0 0 8G 0 disk |
| 251 | 251 |
└─xvda1 202:1 0 8G 0 part / |
| 252 |
- xvdf 202:80 0 100G 0 disk |
|
| 252 |
+ xvdf 202:80 0 10G 0 disk |
|
| 253 | 253 |
├─vg--docker-data 253:0 0 90G 0 lvm |
| 254 |
- │ └─docker-202:1-1032-pool 253:2 0 100G 0 dm |
|
| 254 |
+ │ └─docker-202:1-1032-pool 253:2 0 10G 0 dm |
|
| 255 | 255 |
└─vg--docker-metadata 253:1 0 4G 0 lvm |
| 256 |
- └─docker-202:1-1032-pool 253:2 0 100G 0 dm |
|
| 256 |
+ └─docker-202:1-1032-pool 253:2 0 10G 0 dm |
|
| 257 | 257 |
|
| 258 | 258 |
The diagram below shows the image from prior examples updated with the detail from the `lsblk` command above. |
| 259 | 259 |
|
| ... | ... |
@@ -271,12 +271,22 @@ Example use: `docker daemon --storage-opt dm.thinpooldev=/dev/mapper/thin-pool` |
| 271 | 271 |
#### dm.basesize |
| 272 | 272 |
|
| 273 | 273 |
Specifies the size to use when creating the base device, which limits |
| 274 |
-the size of images and containers. The default value is 100G. Note, |
|
| 275 |
-thin devices are inherently "sparse", so a 100G device which is mostly |
|
| 276 |
-empty doesn't use 100 GB of space on the pool. However, the filesystem |
|
| 274 |
+the size of images and containers. The default value is 10G. Note, |
|
| 275 |
+thin devices are inherently "sparse", so a 10G device which is mostly |
|
| 276 |
+empty doesn't use 10 GB of space on the pool. However, the filesystem |
|
| 277 | 277 |
will use more space for base images the larger the device |
| 278 | 278 |
is. |
| 279 | 279 |
|
| 280 |
+The base device size can be increased at daemon restart which will allow |
|
| 281 |
+all future images and containers (based on those new images) to be of the |
|
| 282 |
+new base device size. |
|
| 283 |
+ |
|
| 284 |
+Example use: `docker daemon --storage-opt dm.basesize=50G` |
|
| 285 |
+ |
|
| 286 |
+This will increase the base device size to 50G. The Docker daemon will throw an |
|
| 287 |
+error if existing base device size is larger than 50G. A user can use |
|
| 288 |
+this option to expand the base device size however shrinking is not permitted. |
|
| 289 |
+ |
|
| 280 | 290 |
This value affects the system-wide "base" empty filesystem that may already |
| 281 | 291 |
be initialized and inherited by pulled images. Typically, a change to this |
| 282 | 292 |
value requires additional steps to take effect: |