Pārlūkot izejas kodu

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 8 gadi atpakaļ
vecāks
revīzija
05bac4591a

+ 62 - 11
daemon/graphdriver/overlay2/overlay.go

@@ -24,6 +24,7 @@ import (
 	"github.com/docker/docker/pkg/mount"
 	"github.com/docker/docker/pkg/mount"
 	"github.com/docker/docker/pkg/parsers"
 	"github.com/docker/docker/pkg/parsers"
 	"github.com/docker/docker/pkg/parsers/kernel"
 	"github.com/docker/docker/pkg/parsers/kernel"
+	"github.com/docker/go-units"
 
 
 	"github.com/opencontainers/runc/libcontainer/label"
 	"github.com/opencontainers/runc/libcontainer/label"
 )
 )
@@ -76,15 +77,25 @@ const (
 	idLength = 26
 	idLength = 26
 )
 )
 
 
+type overlayOptions struct {
+	overrideKernelCheck bool
+	quota               graphdriver.Quota
+}
+
 // Driver contains information about the home directory and the list of active mounts that are created using this driver.
 // Driver contains information about the home directory and the list of active mounts that are created using this driver.
 type Driver struct {
 type Driver struct {
-	home    string
-	uidMaps []idtools.IDMap
-	gidMaps []idtools.IDMap
-	ctr     *graphdriver.RefCounter
+	home     string
+	uidMaps  []idtools.IDMap
+	gidMaps  []idtools.IDMap
+	ctr      *graphdriver.RefCounter
+	quotaCtl *graphdriver.QuotaCtl
+	options  overlayOptions
 }
 }
 
 
-var backingFs = "<unknown>"
+var (
+	backingFs             = "<unknown>"
+	projectQuotaSupported = false
+)
 
 
 func init() {
 func init() {
 	graphdriver.Register(driverName, Init)
 	graphdriver.Register(driverName, Init)
@@ -150,11 +161,16 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
 		ctr:     graphdriver.NewRefCounter(graphdriver.NewFsChecker(graphdriver.FsMagicOverlay)),
 		ctr:     graphdriver.NewRefCounter(graphdriver.NewFsChecker(graphdriver.FsMagicOverlay)),
 	}
 	}
 
 
-	return d, nil
-}
+	if backingFs == "xfs" {
+		// Try to enable project quota support over xfs.
+		if d.quotaCtl, err = graphdriver.NewQuotaCtl(home); err == nil {
+			projectQuotaSupported = true
+		}
+	}
 
 
-type overlayOptions struct {
-	overrideKernelCheck bool
+	logrus.Debugf("backingFs=%s,  projectQuotaSupported=%v", backingFs, projectQuotaSupported)
+
+	return d, nil
 }
 }
 
 
 func parseOptions(options []string) (*overlayOptions, error) {
 func parseOptions(options []string) (*overlayOptions, error) {
@@ -171,6 +187,7 @@ func parseOptions(options []string) (*overlayOptions, error) {
 			if err != nil {
 			if err != nil {
 				return nil, err
 				return nil, err
 			}
 			}
+
 		default:
 		default:
 			return nil, fmt.Errorf("overlay2: Unknown option %s\n", key)
 			return nil, fmt.Errorf("overlay2: Unknown option %s\n", key)
 		}
 		}
@@ -253,8 +270,8 @@ func (d *Driver) CreateReadWrite(id, parent, mountLabel string, storageOpt map[s
 // The parent filesystem is used to configure these directories for the overlay.
 // The parent filesystem is used to configure these directories for the overlay.
 func (d *Driver) Create(id, parent, mountLabel string, storageOpt map[string]string) (retErr error) {
 func (d *Driver) Create(id, parent, mountLabel string, storageOpt map[string]string) (retErr error) {
 
 
-	if len(storageOpt) != 0 {
-		return fmt.Errorf("--storage-opt is not supported for overlay")
+	if len(storageOpt) != 0 && !projectQuotaSupported {
+		return fmt.Errorf("--storage-opt is supported only for overlay over xfs with 'pquota' mount option")
 	}
 	}
 
 
 	dir := d.dir(id)
 	dir := d.dir(id)
@@ -277,6 +294,20 @@ func (d *Driver) Create(id, parent, mountLabel string, storageOpt map[string]str
 		}
 		}
 	}()
 	}()
 
 
+	if len(storageOpt) > 0 {
+		driver := &Driver{}
+		if err := d.parseStorageOpt(storageOpt, driver); err != nil {
+			return err
+		}
+
+		if driver.options.quota.Size > 0 {
+			// Set container disk quota limit
+			if err := d.quotaCtl.SetQuota(dir, driver.options.quota); err != nil {
+				return err
+			}
+		}
+	}
+
 	if err := idtools.MkdirAs(path.Join(dir, "diff"), 0755, rootUID, rootGID); err != nil {
 	if err := idtools.MkdirAs(path.Join(dir, "diff"), 0755, rootUID, rootGID); err != nil {
 		return err
 		return err
 	}
 	}
@@ -316,6 +347,26 @@ func (d *Driver) Create(id, parent, mountLabel string, storageOpt map[string]str
 	return nil
 	return nil
 }
 }
 
 
+// Parse overlay storage options
+func (d *Driver) parseStorageOpt(storageOpt map[string]string, driver *Driver) error {
+	// Read size to set the disk project quota per container
+	for key, val := range storageOpt {
+		key := strings.ToLower(key)
+		switch key {
+		case "size":
+			size, err := units.RAMInBytes(val)
+			if err != nil {
+				return err
+			}
+			driver.options.quota.Size = uint64(size)
+		default:
+			return fmt.Errorf("Unknown option %s", key)
+		}
+	}
+
+	return nil
+}
+
 func (d *Driver) getLower(parent string) (string, error) {
 func (d *Driver) getLower(parent string) (string, error) {
 	parentDir := d.dir(parent)
 	parentDir := d.dir(parent)
 
 

+ 7 - 2
docs/reference/commandline/create.md

@@ -171,8 +171,13 @@ Set storage driver options per container.
     $ docker create -it --storage-opt size=120G fedora /bin/bash
     $ docker create -it --storage-opt size=120G fedora /bin/bash
 
 
 This (size) will allow to set the container rootfs size to 120G at creation time. 
 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. This option is only 
-available for the `devicemapper`, `btrfs`, `windowsfilter`, and `zfs` graph drivers.
+This option is only available for the `devicemapper`, `btrfs`, `overlay2`,
+`windowsfilter` and `zfs` graph drivers.
+For the `devicemapper`, `btrfs`, `windowsfilter` and `zfs` graph drivers,
+user cannot pass a size less than the Default BaseFS Size.
+For the `overlay2` storage driver, the size option is only available if the
+backing fs is `xfs` and mounted with the `pquota` mount option.
+Under these conditions, user can pass any size less then the backing fs size.
 
 
 ### Specify isolation technology for container (--isolation)
 ### Specify isolation technology for container (--isolation)
 
 

+ 7 - 2
docs/reference/commandline/run.md

@@ -198,8 +198,13 @@ The `-w` lets the command being executed inside directory given, here
     $ docker run -it --storage-opt size=120G fedora /bin/bash
     $ docker run -it --storage-opt size=120G fedora /bin/bash
 
 
 This (size) will allow to set the container rootfs size to 120G at creation time.
 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. This option is only
-available for the `devicemapper`, `btrfs`, `windowsfilter`, and `zfs` graph drivers.
+This option is only available for the `devicemapper`, `btrfs`, `overlay2`,
+`windowsfilter` and `zfs` graph drivers.
+For the `devicemapper`, `btrfs`, `windowsfilter` and `zfs` graph drivers,
+user cannot pass a size less than the Default BaseFS Size.
+For the `overlay2` storage driver, the size option is only available if the
+backing fs is `xfs` and mounted with the `pquota` mount option.
+Under these conditions, user can pass any size less then the backing fs size.
 
 
 ### Mount tmpfs (--tmpfs)
 ### Mount tmpfs (--tmpfs)
 
 

+ 5 - 2
man/docker-create.1.md

@@ -343,8 +343,11 @@ unit, `b` is used. Set LIMIT to `-1` to enable unlimited swap.
 
 
    $ docker create -it --storage-opt size=120G fedora /bin/bash
    $ docker create -it --storage-opt size=120G fedora /bin/bash
 
 
-   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.
-   This option is only available for the `devicemapper`, `btrfs`, and `zfs` graph drivers.
+   This (size) will allow to set the container rootfs size to 120G at creation time.
+   This option is only available for the `devicemapper`, `btrfs`, `overlay2` and `zfs` graph drivers.
+   For the `devicemapper`, `btrfs` and `zfs` storage drivers, user cannot pass a size less than the Default BaseFS Size.
+   For the `overlay2` storage driver, the size option is only available if the backing fs is `xfs` and mounted with the `pquota` mount option.
+   Under these conditions, user can pass any size less then the backing fs size.
   
   
 **--stop-signal**=*SIGTERM*
 **--stop-signal**=*SIGTERM*
   Signal to stop a container. Default is SIGTERM.
   Signal to stop a container. Default is SIGTERM.

+ 5 - 2
man/docker-run.1.md

@@ -493,8 +493,11 @@ incompatible with any restart policy other than `none`.
 
 
    $ docker run -it --storage-opt size=120G fedora /bin/bash
    $ docker run -it --storage-opt size=120G fedora /bin/bash
 
 
-   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.
-   This option is only available for the `devicemapper`, `btrfs`, and `zfs` graph drivers.
+   This (size) will allow to set the container rootfs size to 120G at creation time.
+   This option is only available for the `devicemapper`, `btrfs`, `overlay2`  and `zfs` graph drivers.
+   For the `devicemapper`, `btrfs` and `zfs` storage drivers, user cannot pass a size less than the Default BaseFS Size.
+   For the `overlay2` storage driver, the size option is only available if the backing fs is `xfs` and mounted with the `pquota` mount option.
+   Under these conditions, user can pass any size less then the backing fs size.
 
 
 **--stop-signal**=*SIGTERM*
 **--stop-signal**=*SIGTERM*
   Signal to stop a container. Default is SIGTERM.
   Signal to stop a container. Default is SIGTERM.