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>
| ... | ... |
@@ -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. |