Skip to content

Commit 1cbe8cc

Browse files
committed
Proof of Conceptt, take 2
1 parent 24524a7 commit 1cbe8cc

File tree

8 files changed

+100
-197
lines changed

8 files changed

+100
-197
lines changed

Dockerfile.debian

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# build
2+
FROM golang:stretch as builder
3+
RUN apt update -y && \
4+
apt install -y build-essential
5+
ADD ./ /go/src/github.com/ashald/docker-volume-loopback/
6+
WORKDIR /go/src/github.com/ashald/docker-volume-loopback
7+
RUN go build && \
8+
mv ./docker-volume-loopback /usr/bin/
9+
10+
11+
# package
12+
FROM debian:stretch-slim
13+
RUN apt update -y && \
14+
apt install -y xfsprogs && \
15+
rm -rf /var/lib/apt/lists/*
16+
COPY --from=builder /usr/bin/docker-volume-loopback /usr/bin/docker-volume-loopback
17+
CMD [ "/usr/bin/docker-volume-loopback" ]

README.md

Lines changed: 4 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -1,133 +1,5 @@
1-
<h1 align="center">xfsvol 📂 </h1>
2-
3-
<h5 align="center">Docker Volume Plugin for managing local XFS-based volumes</h5>
4-
5-
<br/>
6-
7-
[![Build Status](https://travis-ci.org/cirocosta/xfsvol.svg?branch=master)](https://travis-ci.org/cirocosta/xfsvol)
8-
9-
## Quickstart
10-
11-
1. Create a mountpoint at `/mnt/xfs` and a directory `/mnt/xfs/volumes`.
12-
13-
For testing purposes this mountpoint can be a loopback device (note: use a loopback device for testing purposes only).
14-
15-
```sh
16-
sudo dd if=/dev/zero of=/xfs.1G bs=1M count=1024
17-
sudo losetup /dev/loop0 /xfs.1G
18-
sudo mkfs -t xfs -n ftype=1 /dev/loop0
19-
sudo mkdir -p /mnt/xfs/volumes
20-
sudo mount /dev/loop0 /mnt/xfs -o pquota
21-
```
22-
23-
2. Install the plugin
24-
25-
```
26-
docker plugin install \
27-
--grant-all-permissions \
28-
--alias xfsvol \
29-
cirocosta/xfsvol
30-
31-
docker plugin ls
32-
ID NAME DESCRIPTION ENABLED
33-
06545b643c6a xfsvol:latest Docker plugin to manage XFS-mounted volumes true
34-
```
35-
36-
3. Create a named volume
37-
38-
```
39-
docker volume create \
40-
--driver xfsvol \
41-
--opt size=10M \
42-
myvolume1
43-
```
44-
45-
4. Run a container with the volume attached
46-
47-
```
48-
docker run -it \
49-
-v myvolume1:/myvolume1 \
50-
alpine /bin/sh
51-
52-
dd if=/dev/zero of=/myvolume1/file bs=1M count=100
53-
(fail!)
54-
```
55-
56-
5. Check the volumes list
57-
58-
```
59-
docker volume ls
60-
DRIVER VOLUME NAME
61-
xfsvol:latest myvolume1 (1.004MB)
62-
local dockerdev-go-pkg-cache-gopath
63-
local dockerdev-go-pkg-cache-goroot-linux_amd64
64-
local dockerdev-go-pkg-cache-goroot-linux_amd64_netgo
65-
```
66-
67-
and the `xfsvolctl` utility:
68-
69-
```
70-
sudo /usr/bin/xfsvolctl ls --root /mnt/xfs/volumes/
71-
NAME QUOTA
72-
ciro 1.004 MB
73-
```
74-
75-
## `xfsvolctl`
76-
77-
This tool is made to help inspect the project quotas created under a given root path as well as create/delete others. It's usage is documented under `--help`:
78-
79-
```
80-
xfsvolctl --help
81-
NAME:
82-
xfsvolctl - Controls the 'xfsvol' volume plugin
83-
84-
USAGE:
85-
xfsvolctl [global options] command [command options] [arguments...]
86-
87-
VERSION:
88-
0.0.0
89-
90-
COMMANDS:
91-
ls Lists the volumes managed by 'xfsvol' plugin
92-
create Creates a volume with XFS project quota enforcement
93-
delete Deletes a volume managed by 'xfsvol' plugin
94-
help, h Shows a list of commands or help for one command
95-
96-
GLOBAL OPTIONS:
97-
--help, -h show help
98-
--version, -v print the version
99-
```
100-
101-
### Under the hood
102-
103-
104-
```
105-
$ sudo mkdir -p /mnt/xfs/tmp/bbb
106-
$ sudo strace -f xfsvolctl create \
107-
--root /mnt/xfs/tmp/bbb \
108-
--name ccc \
109-
--size 1024 \
110-
--inode 1024
111-
112-
stat("/mnt/xfs/tmp/bbb", {st_mode=S_IFDIR|0755, st_size=6, ...}) = 0
113-
unlinkat(AT_FDCWD, "/mnt/xfs/tmp/bbb/backingFsBlockDev", 0) = -1 ENOENT (No such file or directory)
114-
mknodat(AT_FDCWD, "/mnt/xfs/tmp/bbb/backingFsBlockDev", S_IFBLK|0600, makedev(7, 0)) = 0
115-
quotactl(Q_XSETQLIM|PRJQUOTA, "/mnt/xfs/tmp/bbb/backingFsBlockDev", 1, {version=1, flags=XFS_PROJ_QUOTA, fieldmask=0xc, id=1, blk_hardlimit=0, blk_softlimit=0, ino_hardlimit=0, ino_softlimit=0, bcount=0, icount=0, ...}) = 0
116-
...
117-
mkdirat(AT_FDCWD, "/mnt/xfs/tmp/bbb/ccc", 0755) = 0
118-
open("/mnt/xfs/tmp/bbb/ccc", O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = 3
119-
fstat(3, {st_mode=S_IFDIR|0755, st_size=6, ...}) = 0
120-
ioctl(3, FS_IOC_FSGETXATTR, 0xc4201a95e4) = 0
121-
ioctl(3, FS_IOC_FSSETXATTR, 0xc4201a95e4) = 0
122-
123-
quotactl(Q_XSETQLIM|PRJQUOTA, "/mnt/xfs/tmp/bbb/backingFsBlockDev", 2, {version=1, flags=XFS_PROJ_QUOTA, fieldmask=0xc, id=2, blk_hardlimit=2, blk_softlimit=2, ino_hardlimit=1024, ino_softlimit=1024, bcount=0, icount=0, ...}) = 0
124-
[pid 6833] ioctl(2, TCGETS, {B38400 opost isig icanon echo ...}) = 0
125-
126-
127-
// retrieving (ls)
128-
129-
[pid 8609] quotactl(Q_XGETQUOTA|PRJQUOTA, "/mnt/xfs/tmp/ddd/backingFsBlockDev", 2, {version=1, flags=XFS_PROJ_QUOTA, fieldmask=0, id=2, blk_hardlimit=8, blk_softlimit=8, ino_hardlimit=0, ino_softlimit=0, bcount=8, icount=104, ...}) = 0
130-
131-
132-
```
1+
# Performance
2+
https://serverfault.com/questions/166748/performance-of-loopback-filesystems
3+
https://kernelnewbies.org/Linux_4.4#Faster_and_leaner_loop_device_with_Direct_I.2FO_and_Asynchronous_I.2FO_support
1334

5+
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=bc07c10a3603a5ab3ef01ba42b3d41f9ac63d1b6

Vagrantfile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Vagrant.configure(2) do |config|
2+
config.vm.box = "ubuntu/trusty64"
3+
config.vm.provision :docker
4+
end

driver/driver.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
type Config struct {
2020
StateDir string
2121
DataDir string
22+
MountDir string
2223
DefaultSize string
2324
}
2425

@@ -38,6 +39,7 @@ func NewDriver(cfg Config) (d Driver, err error) {
3839
m, err := manager.New(manager.Config{
3940
StateDir: cfg.StateDir,
4041
DataDir: cfg.DataDir,
42+
MountDir: cfg.MountDir,
4143
})
4244
if err != nil {
4345
err = errors.Wrapf(err,
@@ -144,14 +146,14 @@ func (d Driver) Get(req *v.GetRequest) (*v.GetResponse, error) {
144146
resp.Volume = &v.Volume{
145147
Name: req.Name,
146148
CreatedAt: fmt.Sprintf(vol.CreatedAt.Format(time.RFC3339)),
147-
Mountpoint: vol.EntrypointPath,
149+
Mountpoint: vol.MountPointPath,
148150
Status: map[string]interface{}{
149151
"size": strconv.FormatUint(vol.SizeInBytes, 10),
150152
},
151153
}
152154

153155
logger.Debug().
154-
Str("mountpoint", vol.EntrypointPath).
156+
Str("mountpoint", vol.MountPointPath).
155157
Msg("finished retrieving volume")
156158
return resp, nil
157159
}
@@ -195,11 +197,11 @@ func (d Driver) Path(req *v.PathRequest) (*v.PathResponse, error) {
195197
}
196198

197199
logger.Debug().
198-
Str("path", vol.EntrypointPath).
200+
Str("path", vol.MountPointPath).
199201
Msg("finished retrieving volume path")
200202

201203
resp := new(v.PathResponse)
202-
resp.Mountpoint = vol.EntrypointPath
204+
resp.Mountpoint = vol.MountPointPath
203205
return resp, nil
204206
}
205207

@@ -231,7 +233,7 @@ func (d Driver) Mount(req *v.MountRequest) (*v.MountResponse, error) {
231233
func (d Driver) Unmount(req *v.UnmountRequest) (error) {
232234
var logger = d.logger.With().
233235
Str("log-id", shortid.MustGenerate()).
234-
Str("method", "mount").
236+
Str("method", "unmount").
235237
Str("name", req.Name).
236238
Str("id", req.ID).
237239
Logger()

main.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,24 @@ import (
1212
)
1313

1414
const (
15-
socketAddress = "/run/docker/plugins/dvl.sock"
15+
socketAddress = "/run/docker/plugins/loop.sock"
1616
)
1717

1818
type config struct {
1919
StateDir string `arg:"--state-dir,env:STATE_DIR,help:dir used to keep track of currently mounted volumes"`
2020
DataDir string `arg:"--data-dir,env:DATA_DIR,help:dir used to store actual volume data"`
21+
MountDir string `arg:"--mount-dir,env:MOUNT_DIR,help:dir used to create mount-points"`
2122
DefaultSize string `arg:"--default-size,env:DEFAULT_SIZE,help:default size for volumes created"`
2223
Debug bool `arg:"env:DEBUG,help:enable debug logs"`
2324
}
2425

2526
var (
26-
version = "master-dev"
2727
logger = zerolog.New(os.Stdout)
2828
args = &config{
29+
StateDir: "/run/docker-volume-loopback",
30+
DataDir: "/var/lib/docker-volume-loopback",
31+
MountDir: "/mnt",
32+
DefaultSize: "1G",
2933
Debug: false,
3034
}
3135
)
@@ -34,7 +38,6 @@ func main() {
3438
arg.MustParse(args)
3539

3640
logger.Info().
37-
Str("version", version).
3841
Str("socket-address", socketAddress).
3942
Interface("args", args).
4043
Msg("initializing plugin")
@@ -46,6 +49,7 @@ func main() {
4649
d, err := driver.NewDriver(driver.Config{
4750
StateDir: args.StateDir,
4851
DataDir: args.DataDir,
52+
MountDir: args.MountDir,
4953
DefaultSize: args.DefaultSize,
5054
})
5155
if err != nil {

0 commit comments

Comments
 (0)