Browse code

overlay2: add support for --storage-opt size

Allow passing --storage-opt size=X to docker create/run commands
for the `overlay2` graphriver.

The size option is only available if the backing fs is xfs that is
mounted with the `pquota` mount option.
The user can pass any size less then the backing fs size.

Signed-off-by: Amir Goldstein <amir73il@aquasec.com>

Amir Goldstein authored on 2016/09/19 04:35:55
Showing 5 changed files
... ...
@@ -24,6 +24,7 @@ import (
24 24
 	"github.com/docker/docker/pkg/mount"
25 25
 	"github.com/docker/docker/pkg/parsers"
26 26
 	"github.com/docker/docker/pkg/parsers/kernel"
27
+	"github.com/docker/go-units"
27 28
 
28 29
 	"github.com/opencontainers/runc/libcontainer/label"
29 30
 )
... ...
@@ -76,15 +77,25 @@ const (
76 76
 	idLength = 26
77 77
 )
78 78
 
79
+type overlayOptions struct {
80
+	overrideKernelCheck bool
81
+	quota               graphdriver.Quota
82
+}
83
+
79 84
 // Driver contains information about the home directory and the list of active mounts that are created using this driver.
80 85
 type Driver struct {
81
-	home    string
82
-	uidMaps []idtools.IDMap
83
-	gidMaps []idtools.IDMap
84
-	ctr     *graphdriver.RefCounter
86
+	home     string
87
+	uidMaps  []idtools.IDMap
88
+	gidMaps  []idtools.IDMap
89
+	ctr      *graphdriver.RefCounter
90
+	quotaCtl *graphdriver.QuotaCtl
91
+	options  overlayOptions
85 92
 }
86 93
 
87
-var backingFs = "<unknown>"
94
+var (
95
+	backingFs             = "<unknown>"
96
+	projectQuotaSupported = false
97
+)
88 98
 
89 99
 func init() {
90 100
 	graphdriver.Register(driverName, Init)
... ...
@@ -150,11 +161,16 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
150 150
 		ctr:     graphdriver.NewRefCounter(graphdriver.NewFsChecker(graphdriver.FsMagicOverlay)),
151 151
 	}
152 152
 
153
-	return d, nil
154
-}
153
+	if backingFs == "xfs" {
154
+		// Try to enable project quota support over xfs.
155
+		if d.quotaCtl, err = graphdriver.NewQuotaCtl(home); err == nil {
156
+			projectQuotaSupported = true
157
+		}
158
+	}
155 159
 
156
-type overlayOptions struct {
157
-	overrideKernelCheck bool
160
+	logrus.Debugf("backingFs=%s,  projectQuotaSupported=%v", backingFs, projectQuotaSupported)
161
+
162
+	return d, nil
158 163
 }
159 164
 
160 165
 func parseOptions(options []string) (*overlayOptions, error) {
... ...
@@ -171,6 +187,7 @@ func parseOptions(options []string) (*overlayOptions, error) {
171 171
 			if err != nil {
172 172
 				return nil, err
173 173
 			}
174
+
174 175
 		default:
175 176
 			return nil, fmt.Errorf("overlay2: Unknown option %s\n", key)
176 177
 		}
... ...
@@ -253,8 +270,8 @@ func (d *Driver) CreateReadWrite(id, parent, mountLabel string, storageOpt map[s
253 253
 // The parent filesystem is used to configure these directories for the overlay.
254 254
 func (d *Driver) Create(id, parent, mountLabel string, storageOpt map[string]string) (retErr error) {
255 255
 
256
-	if len(storageOpt) != 0 {
257
-		return fmt.Errorf("--storage-opt is not supported for overlay")
256
+	if len(storageOpt) != 0 && !projectQuotaSupported {
257
+		return fmt.Errorf("--storage-opt is supported only for overlay over xfs with 'pquota' mount option")
258 258
 	}
259 259
 
260 260
 	dir := d.dir(id)
... ...
@@ -277,6 +294,20 @@ func (d *Driver) Create(id, parent, mountLabel string, storageOpt map[string]str
277 277
 		}
278 278
 	}()
279 279
 
280
+	if len(storageOpt) > 0 {
281
+		driver := &Driver{}
282
+		if err := d.parseStorageOpt(storageOpt, driver); err != nil {
283
+			return err
284
+		}
285
+
286
+		if driver.options.quota.Size > 0 {
287
+			// Set container disk quota limit
288
+			if err := d.quotaCtl.SetQuota(dir, driver.options.quota); err != nil {
289
+				return err
290
+			}
291
+		}
292
+	}
293
+
280 294
 	if err := idtools.MkdirAs(path.Join(dir, "diff"), 0755, rootUID, rootGID); err != nil {
281 295
 		return err
282 296
 	}
... ...
@@ -316,6 +347,26 @@ func (d *Driver) Create(id, parent, mountLabel string, storageOpt map[string]str
316 316
 	return nil
317 317
 }
318 318
 
319
+// Parse overlay storage options
320
+func (d *Driver) parseStorageOpt(storageOpt map[string]string, driver *Driver) error {
321
+	// Read size to set the disk project quota per container
322
+	for key, val := range storageOpt {
323
+		key := strings.ToLower(key)
324
+		switch key {
325
+		case "size":
326
+			size, err := units.RAMInBytes(val)
327
+			if err != nil {
328
+				return err
329
+			}
330
+			driver.options.quota.Size = uint64(size)
331
+		default:
332
+			return fmt.Errorf("Unknown option %s", key)
333
+		}
334
+	}
335
+
336
+	return nil
337
+}
338
+
319 339
 func (d *Driver) getLower(parent string) (string, error) {
320 340
 	parentDir := d.dir(parent)
321 341
 
... ...
@@ -171,8 +171,13 @@ Set storage driver options per container.
171 171
     $ docker create -it --storage-opt size=120G fedora /bin/bash
172 172
 
173 173
 This (size) will allow to set the container rootfs size to 120G at creation time. 
174
-User cannot pass a size less than the Default BaseFS Size. This option is only 
175
-available for the `devicemapper`, `btrfs`, `windowsfilter`, and `zfs` graph drivers.
174
+This option is only available for the `devicemapper`, `btrfs`, `overlay2`,
175
+`windowsfilter` and `zfs` graph drivers.
176
+For the `devicemapper`, `btrfs`, `windowsfilter` and `zfs` graph drivers,
177
+user cannot pass a size less than the Default BaseFS Size.
178
+For the `overlay2` storage driver, the size option is only available if the
179
+backing fs is `xfs` and mounted with the `pquota` mount option.
180
+Under these conditions, user can pass any size less then the backing fs size.
176 181
 
177 182
 ### Specify isolation technology for container (--isolation)
178 183
 
... ...
@@ -198,8 +198,13 @@ The `-w` lets the command being executed inside directory given, here
198 198
     $ docker run -it --storage-opt size=120G fedora /bin/bash
199 199
 
200 200
 This (size) will allow to set the container rootfs size to 120G at creation time.
201
-User cannot pass a size less than the Default BaseFS Size. This option is only
202
-available for the `devicemapper`, `btrfs`, `windowsfilter`, and `zfs` graph drivers.
201
+This option is only available for the `devicemapper`, `btrfs`, `overlay2`,
202
+`windowsfilter` and `zfs` graph drivers.
203
+For the `devicemapper`, `btrfs`, `windowsfilter` and `zfs` graph drivers,
204
+user cannot pass a size less than the Default BaseFS Size.
205
+For the `overlay2` storage driver, the size option is only available if the
206
+backing fs is `xfs` and mounted with the `pquota` mount option.
207
+Under these conditions, user can pass any size less then the backing fs size.
203 208
 
204 209
 ### Mount tmpfs (--tmpfs)
205 210
 
... ...
@@ -343,8 +343,11 @@ unit, `b` is used. Set LIMIT to `-1` to enable unlimited swap.
343 343
 
344 344
    $ docker create -it --storage-opt size=120G fedora /bin/bash
345 345
 
346
-   This (size) will allow to set the container rootfs size to 120G at creation time. User cannot pass a size less than the Default BaseFS Size.
347
-   This option is only available for the `devicemapper`, `btrfs`, and `zfs` graph drivers.
346
+   This (size) will allow to set the container rootfs size to 120G at creation time.
347
+   This option is only available for the `devicemapper`, `btrfs`, `overlay2` and `zfs` graph drivers.
348
+   For the `devicemapper`, `btrfs` and `zfs` storage drivers, user cannot pass a size less than the Default BaseFS Size.
349
+   For the `overlay2` storage driver, the size option is only available if the backing fs is `xfs` and mounted with the `pquota` mount option.
350
+   Under these conditions, user can pass any size less then the backing fs size.
348 351
   
349 352
 **--stop-signal**=*SIGTERM*
350 353
   Signal to stop a container. Default is SIGTERM.
... ...
@@ -493,8 +493,11 @@ incompatible with any restart policy other than `none`.
493 493
 
494 494
    $ docker run -it --storage-opt size=120G fedora /bin/bash
495 495
 
496
-   This (size) will allow to set the container rootfs size to 120G at creation time. User cannot pass a size less than the Default BaseFS Size.
497
-   This option is only available for the `devicemapper`, `btrfs`, and `zfs` graph drivers.
496
+   This (size) will allow to set the container rootfs size to 120G at creation time.
497
+   This option is only available for the `devicemapper`, `btrfs`, `overlay2`  and `zfs` graph drivers.
498
+   For the `devicemapper`, `btrfs` and `zfs` storage drivers, user cannot pass a size less than the Default BaseFS Size.
499
+   For the `overlay2` storage driver, the size option is only available if the backing fs is `xfs` and mounted with the `pquota` mount option.
500
+   Under these conditions, user can pass any size less then the backing fs size.
498 501
 
499 502
 **--stop-signal**=*SIGTERM*
500 503
   Signal to stop a container. Default is SIGTERM.