{"id":18686670,"url":"https://github.com/ashald/docker-volume-loopback","last_synced_at":"2025-04-12T05:06:50.724Z","repository":{"id":78666805,"uuid":"170429358","full_name":"ashald/docker-volume-loopback","owner":"ashald","description":"Docker Volume Driver providing fixed size volumes using loopback devices","archived":false,"fork":false,"pushed_at":"2019-06-12T20:52:34.000Z","size":1733,"stargazers_count":26,"open_issues_count":1,"forks_count":6,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-03-26T00:35:52.342Z","etag":null,"topics":["docker","docker-driver","driver","ext4","loop","loopback","volume","xfs"],"latest_commit_sha":null,"homepage":null,"language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ashald.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-02-13T02:53:55.000Z","updated_at":"2025-02-28T16:32:09.000Z","dependencies_parsed_at":"2023-07-08T07:30:25.839Z","dependency_job_id":null,"html_url":"https://github.com/ashald/docker-volume-loopback","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ashald%2Fdocker-volume-loopback","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ashald%2Fdocker-volume-loopback/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ashald%2Fdocker-volume-loopback/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ashald%2Fdocker-volume-loopback/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ashald","download_url":"https://codeload.github.com/ashald/docker-volume-loopback/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248519540,"owners_count":21117761,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["docker","docker-driver","driver","ext4","loop","loopback","volume","xfs"],"created_at":"2024-11-07T10:28:31.155Z","updated_at":"2025-04-12T05:06:50.704Z","avatar_url":"https://github.com/ashald.png","language":"Shell","readme":"# Docker Volume Loopback\n\n## Overview\n\nThe `docker-volume-loopback` is a [Docker volume driver] that allows creating volumes that are fixed in size.\nFixed size volumes are valuable because they can be used to \"reserve\" disk space for a particular container and make sure\nit will be available later when needed or limit the disk space available to a container so that it won't abuse the host\nand affect other processes running there.\n\nThis plugin makes use of Linux [loop devices] that can be used to present a file on a filesystem as a regular block device.\nUsing loop devices allow for great flexibility as there are next to 0 prerequisites and they can be used on arbitrary\nLinux hosts. Volumes themselves are stored as regular files and are very easy to manage or even can be moved between\ndifferent hosts. All of that being said, there are some potential performance and durability implications one may need\nto take into account when using loop devices and this particular plugin - they are discussed in more detail in the\n[\"Known Issues and Limitations\"](#known-issues-and-limitations) section below.\n\nGenerally speaking, an [LVM-based docker volume driver] is a more reliable and efficient alternative in case one can use\nLVM or setting it up is feasible (e.g., may not be an option on managed hosts).\n\n\n## Demo\n\n\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"./docs/demo.svg\"\u003e\n\u003c/div\u003e\n\n\n## Features\n\n### Regular \u0026 Sparse volumes\n\nThe plugin supports `ext4` and `xfs` filesystems that together with `sparse` option (see details in [\"Usage\"](#usage)\nsection) can be used to achieve different levels of disk space reservation guarantees.\n\nWhen `sparse` option is enabled (disabled by default) the driver would create a [sparse file] to back the volume. This\nmeans that even though file will appear to be of a given size, it's not going to be taking that much of disk space.\nInstead, its physical size is going to be equal to its actual usage but won't be able to grow beyond the certain size limit.\nThis can be useful when there is a need to limit disk space available but it might not be necessary to ensure it actually\nwill be available. As a side effect one can create volumes larger than there is actually disk space available for the\npurpose of \"over-subscription\" when volumes are rarely used to their full size.\n\nWhen regular files are used to back volumes the driver will first attempt to allocate as much disk space as was requested\nensure volume can fit onto disk. After that volume is formatted with a filesystem of choice and behavior differs. When\n`xfs` is used the volume data file remains a \"regular file\" and volume still uses as much disk space as was requested\nproviding a guarantee that the entire disk space is going to be available. In case `ext4` is used, the data file is being\nconverted to a sparse file.\nIn other words, both in both cases driver verifies that there is enough disk space available at the moment of creation\nbut then relaxes the reservation (in case of `ext4`) or keeps it place (in case of `xfs`) depending on filesystem used.  \n\nThe table below shows actual data file size on disk before and after formatting depending on whether `sparse` option is \nused and how volume is formatted.\n\n| FS   | Sparse        | Regular     |\n| ---- | ------------- | ----------- |\n| xfs  | 0% / 1%       | 100% / 100% |\n| ext4 | 0% / 3%       | 100% / 3%   |\n\n\n### Volume Root Credentials\n\nPlugin provides means to adjust credentials (`uid`/`gid`/`mode`) on volume root upon creation. This makes driver \nsuitable for use in scenarios that include user namespace remapping for enhanced security. See [\"Usage\"](#usage) for\ndetails.\n\n\n### Extensive Logging\n\nThe plugin is designed to be as reliable as possible and its code is written in way that is slightly more explicit than\none could be used to just to make sure all exceptional situations are handled. Although, we are all mere human beings\ncannot predict everything and things may fail. When that happens its crucial to be able to reproduce the issue and get\nas many details as possible so that one can pin point the source of failure and come up with a solution. For that purpose\nplugin is built around a \"tracing\" concept where every call of any significant interest is being accompanied by a so-called\ntrace identifier that one can use to get a complete overview of what the plugin does. This also can be used for audit\npurposes or to understand how exactly plugin works. One can chose between 5 log levels - from `error` to `trace` to get\ndifferent levels of details.\n\nThere are log samples available for a somehow corner case scenario (so that we can get some warnings!) for a volume\ncreation operation when the plugin has to store its data files on an older filesystem like `ext3` that does not support\n`fallocate` and therefore it falls back to a slower `dd`:\n\n* 0 - [ERROR](./docs/example.0_error.log)\n* 1 - [WARNING](./docs/example.1_warning.log)\n* 2 - [INFO](./docs/example.2_info.log)\n* 3 - [DEBUG](./docs/example.3_debug.log)\n* 4 - [TRACE](./docs/example.4_trace.log)\n\n### Thorough Testing\n\nPlugin comes with an extensive test suite covering all aspects of its behavior which helps to ensure that it works\nas expected and any new changes won't break existing features.  \n\n## Installation\n\n### Automatic\n\nPlugin is compatible with [Docker's managed plugin system] and therefore can be installed as simple as:\n```bash\n$ docker plugin install ashald/docker-volume-loopback\n  Plugin \"ashald/docker-volume-loopback\" is requesting the following privileges:\n   - mount: [/dev]\n   - mount: [/]\n   - allow-all-devices: [true]\n   - capabilities: [CAP_SYS_ADMIN]\n  Do you grant the above permissions? [y/N] y\n  latest: Pulling from ashald/docker-volume-loopback\n  ...\n  Installed plugin ashald/docker-volume-loopback\n```\n\n### Manual\n\nPlugin can be run \"manually\" - just as an executable on the same host as Docker daemon. Plugin default options are such\nthat it should be possible to run it with minimum or no configuration. Plugin itself does not talk to Docker but it's the\nother way around - [Docker expects to find plugin's socket in one of few pre-defined locations].\n\n## Configuration\n\nRegardless of the way plugin is installed certain aspects of its behavior can be controlled. Both command line arguments\nand environment variables are supported.\n\n| Env Var         | Argument          | Default                                             | Comment                                               |\n| --------------- | ----------------- | --------------------------------------------------- | ----------------------------------------------------- |\n| `DATA_DIR`      | `--data-dir`      | `/var/lib/docker-volume-loopback`                   | Persistent dir to store volumes' data                 |\n| `MOUNT_DIR`     | `--mount-dir`     | `/mnt`                                              | Dir to mount volumes so Docker can access them        |\n| `STATE_DIR`     | `--state-dir`     | `/run/docker-volume-loopback`                       | Volatile dir to keep track of currently used volumes  |\n| `LOG_LEVEL`     | `--log-level`     | `2`                                                 | 0-4 for error/warning/info/debug/trace                |\n| `LOG_FORMAT`    | `--log-format`    | `nice`                                              | `json` / `text` / `nice`                              |\n| `SOCKET`        | `--socket`        | `/run/docker/plugins/docker-volume-loopback.sock`   | Name of the socket determines plugin name             |\n| `DEFAULT_SIZE`  | `--default-size`  | `1GiB`                                              |                                                       |\n\nWhen Docker's managed plugin system configuration can be adjusted via environment variables with the exception for\n`SOCKET` and `MOUNT_DIR` that have to be set to specific values. As for `STATE_DIR` and `DATA_DIR` they adjusted to \n`/srv/run/docker-volume-loopback` and `/srv/var/lib/docker-volume-loopback` respectively - host's file system can be\naccessed via `/srv` prefix. \n\n## Usage\n\n### Examples\n\nPlease note that examples below assume that the driver is run in manual mode and therefore is available as `-d docker-volume-loopback`.\nIn managed mode (automatic installation) that will become `-d ashald/docker-volume-loopback`.\n\nCreate a regular volume using default filesystem (`xfs`) and size (`1Gib`):\n```bash\n$ docker volume create -d docker-volume-loopback foobar \n```\n\nCreate a sparse volume using custom filesystem (`ext4`) and size (`100Mib`):\n```bash\n$ docker volume create -d docker-volume-loopback foobar -o sparse=true -o fs=ext4 -o size=100MiB \n```\n\nCreate a regular volume using default filesystem (`xfs`) and size (`1Gib`) but adjust volume's root ownership and permissions:\n```bash\n$ docker volume create -d docker-volume-loopback foobar -o uid=1000 -o gid=2000 -o mode=777 \n```\n\n### Options\n\n| Option            | Default                                       | Comment                                                               |\n| ----------------- |---------------------------------------------- | --------------------------------------------------------------------- |\n| `size`            | Set by `DEFAULT_SIZE` driver config option    | Size in bytes or with a unit suffix K/M/T/P and Ki/Mi/Ti/Pi           |\n| `sparse`          | `false`                                       | Whether to reserve disk space or just set a limit: `true` or `false`  |\n| `fs`              | `xfs`                                         | Filesystem to format volume with: `xfs` or `ext4`                     |\n| `uid`             | `-1`                                          | UID to set as owner of the volume's root, `-1` means do not adjust    |\n| `gid`             | `-1`                                          | GID to set as owner of the volume's root, `-1` means do not adjust    |\n| `mode`            | `0`                                           | Mode to set for volume's root, octal with up to 4 positions           |\n\n## Known Issues and Limitations\n\n### Platforms\n\nOnly designed to be working on Linux.\nPotentially may work on macOS given that it uses an Alpine VM behind the scenes but this has not been tested.\n\n### Minimum Size\n\nThe minimum allowed volume size is 20 MB (20,000,000 bytes) and is necessary to fit any of supported filesystems.\nIf smaller volume is needed it's advised to consider using [Docker's native `tmpfs` volume driver] that also supports\nlimiting disk space available.\n\n### Performance\n\n[Loop devices are notorious for their \"bad\" performance]. While it's not arguable that they incur and some overhead both\nin terms of CPU and memory it, it always should be evaluated in a context of a concrete use case. Generally speaking,\nif one does not constantly `fsync` after each write to a filesystem based on a loopback device \\[and just let kernel do its job\\]\nthe performance seems to be comparable to regular block devices. Although, it must be noted that in such cases write\noperations are susceptible to the \"double caching\" issue where data are cached first while being written to the loopback\ndevice backed filesystem and then data cached again while changes are bing finally committed to the backing block device.\nThis means that there may be a delay (on average, up to a 2 x 30 seconds = 1 minute) before writes will become durable\nby being committed to the backing block device. Also, cache buffers are usually freed and committed more often when\nsystem runs low on memory which means that usage of loopback devices is unlikely to degrade performance of the system as\na whole but system running low on memory is likely to have loopback devices performing worse. For the record, cache memory\nis not being counted against `memory.max_usage_in_bytes` cgroup controller and therefore is ignored by Docker.\n\nLast but not least, the release of Linux kernel `v4.4` includes \"[Faster and leaner loop device with Direct I/O and Asynchronous I/O support]\"\nwhich [circumvents the \"double buffering\" issue].\n\nIn terms of CPU, while no comprehensive benchmarks have been done during development of the plugin, the overhead seem to\nbe negligible.\n\n### Filesystem Compatibility\n\nEach volume entirely stored on disk as a single file. The filesystem those files are stored on makes a difference in\nsome cases. When using a `sparse` volume type its data file is being created with a call to `truncate` which works\ninstantaneously. Otherwise, the driver would attempt using `fallocate` to create a \"regular\" file that would actually\nclaim the disk space and works as fast as `truncate`. Unfortunately `fallocate` is only known to work with newer\nfilesystems such as `ext4` and `xfs` and therefore will fail if underlying filesystem is an older one (e.g., `ext3`).\nIn this case plugin will detect a failure and fall back to using `dd` which is universally compatible but significantly\nslower: depending on backing block device its write throughput may very between 10s of MiB/s to several GiB/s.\n\n### Kernel Compatibility\n\nWhen dealing with volumes based on `XFS` filesystem the driver depends on `mkfs.xfs` from `xfsprogs` package.\nStarting from `v3.2.3` (released on 2015-06-10) of the package newly created `XfS` filesystems default to use of a newer\nmetadata format that is only supported by Linux kernel `v3.16` and above.\n\nThis manifests as a failure during an attempt to mount a volume - the filesystem will be initialized properly upon\nvolume creation but kernel will not be able to mount it.  \n\nThis is unlikely to be an issue if _manual_ installation mode is used as the version of `xfsprogs` available via Linux\ndistribution-specific package manager is likely to be compatible with the version of Linux kernel required.\nWhen _automatic_ installation is used though the plugin is \\[effectively\\] distributed as a container image based on\nAlpine Linux which \\[at the moment of writing\\] uses at least `v4.19.0` of `xfsprogs` package. This means that in case\nthe plugin will be installed on a system based on older version of kernel it won't be able to use `XFS` filesystem.\n\nThere is a workaround available that can be used to circumvent the issue: use an extra `-m crc=0` parameter when calling\n`mkfs.xfs` which will force use of older version of metadata compatible with older versions of kernel. Unfortunately this\ncannot be a default behavior as this flag was added only to `xfsprogs` starting from `v3.2.0` and therefore is unlikely\nto be available on similar systems based on outdated versions of kernel \\[in case _manual_ installation mode is used\\].\n\n\nWhile the workaround is trivial in essence it is trickier to implement as would require fir amount of code to run\ndynamic checks for versions of kernel and `mkfs.xfs`. Hence a conscious decision to not implement this behavior initially.\nIn case there will be interest if support for older systems it can be easily added and should be requested via a GitHub\nissue.\n\nBelow is the list of distributions known to be affected by this:\n\n| Distribution | Version               | Release Date | End of Life Date |\n| ------------ | --------------------- | ------------ | ---------------- |\n| Ubuntu       | 14.04 LTS Trusty Tahr | 2014-04-17   | 2019-04-01       |\n\n\nEntries are going to be removed from the table upon reaching EOL.\nMay the list above be exhausted this notice will be dropped altogether.\n\n## Development\n\nContributions are welcome! See [DEVELOPMENT.md](./DEVELOPMENT.md) for development guidelines.\n\n## License\n\nSee [LICENSE.txt](./LICENSE.txt)\n\n[Docker volume driver]: https://docs.docker.com/storage/volumes/\n[loop devices]: https://en.wikipedia.org/wiki/Loop_device\n[LVM-based docker volume driver]: https://github.com/containers/docker-lvm-plugin\n[sparse file]: https://en.wikipedia.org/wiki/Sparse_file\n[Docker's managed plugin system]: https://docs.docker.com/engine/extend/\n[Docker expects to find plugin's socket in one of few pre-defined locations]: https://docs.docker.com/engine/extend/plugin_api/#plugin-discovery\n[Docker's native `tmpfs` volume driver]: https://docs.docker.com/storage/tmpfs/\n[Loop devices are notorious for their \"bad\" performance]: https://serverfault.com/questions/166748/performance-of-loopback-filesystems\n[Faster and leaner loop device with Direct I/O and Asynchronous I/O support]: https://kernelnewbies.org/Linux_4.4#Faster_and_leaner_loop_device_with_Direct_I.2FO_and_Asynchronous_I.2FO_support\n[circumvents the \"double buffering\" issue]: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=bc07c10a3603a5ab3ef01ba42b3d41f9ac63d1b6\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fashald%2Fdocker-volume-loopback","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fashald%2Fdocker-volume-loopback","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fashald%2Fdocker-volume-loopback/lists"}