diff --git a/snapshots/overlay/overlay.go b/snapshots/overlay/overlay.go index e566aa5c6..8e4428a26 100644 --- a/snapshots/overlay/overlay.go +++ b/snapshots/overlay/overlay.go @@ -46,6 +46,7 @@ type SnapshotterConfig struct { ms MetaStore mountOptions []string remapIds bool + slowChown bool } // Opt is an option to configure the overlay snapshotter @@ -98,6 +99,11 @@ func WithRemapIds(config *SnapshotterConfig) error { return nil } +func WithSlowChown(config *SnapshotterConfig) error { + config.slowChown = true + return nil +} + type snapshotter struct { root string ms MetaStore @@ -105,6 +111,7 @@ type snapshotter struct { upperdirLabel bool options []string remapIds bool + slowChown bool } // NewSnapshotter returns a Snapshotter which uses overlayfs. The overlayfs @@ -161,6 +168,7 @@ func NewSnapshotter(root string, opts ...Opt) (snapshots.Snapshotter, error) { upperdirLabel: config.upperdirLabel, options: config.mountOptions, remapIds: config.remapIds, + slowChown: config.slowChown, }, nil } diff --git a/snapshots/overlay/plugin/plugin.go b/snapshots/overlay/plugin/plugin.go index 645bc8c95..89adeebb2 100644 --- a/snapshots/overlay/plugin/plugin.go +++ b/snapshots/overlay/plugin/plugin.go @@ -28,7 +28,8 @@ import ( ) const ( - capaRemapIds = "remap-ids" + capaRemapIds = "remap-ids" + capaOnlyRemapIds = "only-remap-ids" ) // Config represents configuration for the overlay plugin. @@ -38,6 +39,11 @@ type Config struct { UpperdirLabel bool `toml:"upperdir_label"` SyncRemove bool `toml:"sync_remove"` + // slowChown allows the plugin to fallback to a recursive chown if fast options (like + // idmap mounts) are not available. See more info about the overhead this can have in + // github.com/containerd/containerd/docs/user-namespaces/. + SlowChown bool `toml:"slow_chown"` + // MountOptions are options used for the overlay mount (not used on bind mounts) MountOptions []string `toml:"mount_options"` } @@ -76,6 +82,14 @@ func init() { ic.Meta.Capabilities = append(ic.Meta.Capabilities, capaRemapIds) } + if config.SlowChown { + oOpts = append(oOpts, overlay.WithSlowChown) + } else { + // If slowChown is false, we use capaOnlyRemapIds to signal we only + // allow idmap mounts. + ic.Meta.Capabilities = append(ic.Meta.Capabilities, capaOnlyRemapIds) + } + ic.Meta.Exports["root"] = root return overlay.NewSnapshotter(root, oOpts...) }, diff --git a/snapshotter_opts_unix.go b/snapshotter_opts_unix.go index 2dff9b424..d0f208d90 100644 --- a/snapshotter_opts_unix.go +++ b/snapshotter_opts_unix.go @@ -26,7 +26,8 @@ import ( ) const ( - capabRemapIDs = "remap-ids" + capabRemapIDs = "remap-ids" + capaOnlyRemapIds = "only-remap-ids" ) // WithRemapperLabels creates the labels used by any supporting snapshotter @@ -72,6 +73,17 @@ func resolveSnapshotOptions(ctx context.Context, client *Client, snapshotterName return parent, nil } + capaOnlyRemap := false + for _, capa := range capabs { + if capa == capaOnlyRemapIds { + capaOnlyRemap = true + } + } + + if capaOnlyRemap { + return "", fmt.Errorf("snapshotter %q doesn't support idmap mounts on this host, configure `slow_chown` to allow a slower and expensive fallback", snapshotterName) + } + var ctrUID, hostUID, length uint32 _, err = fmt.Sscanf(uidMap, "%d:%d:%d", &ctrUID, &hostUID, &length) if err != nil {