Skip to content

Commit ba375e5

Browse files
Merge pull request #17 from 99linesofcode/declaratively-install-docker-plugins
feat(docker): install and remote docker plugins declaratively
2 parents 83cdff3 + 07bdc1e commit ba375e5

File tree

5 files changed

+117
-2
lines changed

5 files changed

+117
-2
lines changed

hosts/luna/default.nix

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@ in
6161
k3s.enable = true;
6262
nvidia.enable = true;
6363
power-management.enable = true;
64+
rclone.enable = true;
6465
sound.enable = true;
65-
6666
openssh.enable = true;
6767
qmk.enable = true;
6868
steam.enable = true;

hosts/mars/default.nix

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ in
3838
rootless.enable = false;
3939
};
4040
k3s.enable = true;
41-
4241
openssh.enable = true;
42+
rclone.enable = true;
4343
};
4444
}

hosts/shared/secrets/rclone.conf

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"data": "ENC[AES256_GCM,data:je5a4n4qKJWcAVNJ6OkfX2DABeUXPzOrhbhErib17crMOS4xk3FFRef5+laz6Jbggj8nmhOEE+lnnp5JoDQejlzxIgtdmYFu9i347NK3cWnbNDUAA8Tw8tYlYyN6tttYpLkx5bPEIHo3NNE0WoDj61cn61IUuo568qFX5GwV/0wX4VAHXWZDGIG4uk4iGjWvv/kxOYEcIE4pnHJzZ7jpLqWxC35qwmkZgBkoavpSEQ+6Pe8ZWeiKIPzWd63ZoNFvSFv1b2Wa1ikKYIrfc/NzB2Mi8XeZD/pK3Y1NsxWdxo+kBIhx3Y8DrtW1pQdZW5P25vbDykCQKQOA+8V6rg9EYDFxl/JlztxPCj/Un5D65ymhjJSyau6/4TN/Z+lGf5eT8GRjaIdqhYrk2ap0WhBRt03s7fDe2SkCw3pqazhCRrkTvrc1Mo0An3fH2Eduf6rR9bIw6IKBXMk+w1pMeBIXGyJLKZ4Uwqb7Mj1++rGC11PvZiHrT4bijZ6UCY0G4CegzidIlX/EPZat7kMW93cYKjIl6A6EOWdlyP9mRr/j7b72YDndd8BZrJNJUQF5uqEqDN/i8LhUUB7Ekv/B8RKq0e4pGWglC5MQumjo3yYJB4zJ1Nsgh7GH2W4o1FhziDhlHjLT6pMx6MvnbNYLn3MZ6NhCeqsDiZ9EKg20bUYoJo2Q4l/x3WSHDQXgM92jkE5RpVaxZ4IuLCmLVVdwlVHsuwAgZRHaF6+0WpC5xHSiXCjzqY9KVhmliO/ZHmM3UKVoNto62W67YtUVofypOzBsIJCPWPH+xVpas6zAt//xq01A+WcKaS3YTB8d1tANC00aDIgiOFdZUUueiizFlOjt3hbxqgvKAZlqadqocePjtlqc0Mw95bAikmjeoC74HYdIVYWGTOmtXUsSxbRP/BhRIuKNeZTVHSDeYTP8ze9KHhaa3IDKIhaObee+k5GOfmF5HOScHqEWBSGZH6QA6+Wfkz06Sgz54MYs3X5gYiw+uSjJhCKNrdeGBvlh2pGi/m9LAYeZAtJW1kmrCG7PHEDRiJFKX7P5CLIaHzUpmpUBYDWHS0/LG94ZdGP617H6C4Kx4oamQa52xKNh8f51WeZXm9D8JCD15POJ6IFynyDoEGtO+AMXH+jsBs6x5vdRDjbxvr6mFNkPbhIpifdeNQiKa0YHUbkIzJFO17b+aDbKABtkQ8jp1qoNBtNlJt4jjUq85sGGnHkPEOv5CYi5x1Ig+ipI/bq8Kl/W5KyAZZIFYrNQ1PFZsposns0o6X/zR2DayROJ+ckatE93EbK44HllzyvuEJ7KqpoKvv8=,iv:SMqZAY/ntaTn2O1j/CGBhxrxw2BOzASeybaVq3EnEIA=,tag:TL0w7C5BgNhce76Zs9cwqg==,type:str]",
3+
"sops": {
4+
"age": [
5+
{
6+
"recipient": "age1hy523tlslqas8qgs0lxgxanp9gx06fjekn608w4qf66mxkjzmucqh0g6vg",
7+
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB4MGM2dnMwNGlSQ1JhYys2\nSGUwRis4YzVDZVdlWllVajhrV3puR2x6VnhzCitXU2N0cWJISEdqeFlRUVltdEw2\nT2s1eUpBT1A2VXowYWhhMXJoV2RKUVUKLS0tIHlJWm5QUktpU0dFWlJpZnNsY3FR\na3B2ZVBYeXZtenhHVFNhb2ZWTFprNEEKTiMVhH4bRAp7+qy4MhZTZirW8Iusi7/w\nMirjR7WtHYI1fHtg09ZBRqxAbclxFah1f3Lpe5PzvZ09Aa3pMyuzEA==\n-----END AGE ENCRYPTED FILE-----\n"
8+
},
9+
{
10+
"recipient": "age10a049meemjvgdgukx6zu5lwu82mqul83l7fyd66tzy9sm8637s7q07ujez",
11+
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBxNUV4VE03dHNZeEh3SU5t\nbjJDdUxSMHN4OWpIbitHZk9wQ1k1b3dBOGprCkdNbThOM0xPS04wNENtVEY2MmZM\nY0NsM2FKK2ZyZm5xMTI4Q3FsZ0Vkd0UKLS0tIC8vY3I5VmoxbmM2a0xrVFI5am9G\naHJVVnJqTytLTFpoQ3h0WXN2ZFVIaGsKV14Jcw9BNzqqPDWLetPBFKMdJgKKzuAG\nY6m2UYcYZwNUW+PEldrJw9EKz+LmsVRccB+k7SrenlMpazdKhjS2Ag==\n-----END AGE ENCRYPTED FILE-----\n"
12+
},
13+
{
14+
"recipient": "age1epkfxmjk0tlne8rmxqq77u06q3lnf5xfjcrwq42nuasswefndyfscw84cy",
15+
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA4c0hkN0VTSGdkdjJyaUZ6\nSUE4K0YwNnpOaDg0MnUzVFNWK01jY1FQUWtVCnBvTEZYVW5Oc3lZWW5FREI1QXgy\nZ3d4Ny9IdWN0cU5HOEZNWEJEWml2SncKLS0tIGd3THh0TXZHbU03T2YrNUdGbjdN\nNlB2L0R1dFNOdzZyY2FxaVVPMlJjNkkKgCSaMuigobeNLC19vzGT/loYkHIHPCke\nFzAIKJpyi3LVCYFxKAxH3H6yHnrZE0Tl00lO+h3yo8pyJUqEhVSNEA==\n-----END AGE ENCRYPTED FILE-----\n"
16+
}
17+
],
18+
"lastmodified": "2025-02-12T10:44:19Z",
19+
"mac": "ENC[AES256_GCM,data:4HjJJw4j3RZua+l3hahhtZOXUNlur6aSaRHMIlbinDEzWrpQiBE0luWOPy0P2BFFmViUD6EGU69RVkZlB/8abbzNoXuSfB7DVL2vjCC194Jamdq0SvkheSOlmyeOUDYTmTK+XBSfj9aviW0deMuQtTTgdRFgqUcjWlohDE4xYaU=,iv:kN7dMlPgN8EQXe1MG3QYKbrZY5Pv8NA7uWVgVqSV79Q=,tag:qxKH9yPhvQLV/2mqsfjDUg==,type:str]",
20+
"unencrypted_suffix": "_unencrypted",
21+
"version": "3.9.4"
22+
}
23+
}

modules/docker.nix

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,21 @@ with lib;
1212
{
1313
options.host.docker = with types; {
1414
enable = mkEnableOption "docker";
15+
plugins = lib.mkOption {
16+
type = lib.types.listOf lib.types.str;
17+
default = [
18+
"rclone/docker-volume-rclone:amd64"
19+
];
20+
example = [
21+
"rclone/docker-volume-rclone:latest"
22+
"vieux/sshfs:latest"
23+
];
24+
description = ''
25+
A list of Docker plugins to install automatically after Docker starts.
26+
Each item should be a valid plugin name or plugin reference usable with
27+
`docker plugin install`.
28+
'';
29+
};
1530
rootless.enable = mkEnableOption "rootless mode";
1631
};
1732

@@ -45,6 +60,40 @@ with lib;
4560
};
4661
};
4762

63+
systemd.services = {
64+
install-docker-plugins = {
65+
description = "Install Docker plugins";
66+
documentation = [ "man:rclone(1)" ];
67+
wants = [ "network-online.target" ];
68+
wantedBy = [ "multi-user.target" ];
69+
serviceConfig = {
70+
Type = "oneshot";
71+
RemainAfterExit = false;
72+
ExecStart =
73+
pkgs.writeShellScript "install-docker-plugins" # bash
74+
''
75+
#!/usr/bin/env sh
76+
77+
docker="${pkgs.docker}/bin/docker"
78+
79+
installedPlugins="$($docker plugin list --format '{{ .Name }}')"
80+
requiredPlugins="${builtins.concatStringsSep "\n" cfg.plugins}"
81+
82+
printf '%s\n' "$installedPlugins" | grep -F -x -v "$requiredPlugins" | while IFS= read -r plugin; do
83+
"$docker" plugin disable "$plugin"
84+
"$docker" plugin rm "$plugin"
85+
printf '%s\n' "Uninstalled $plugin"
86+
done >/dev/null
87+
88+
printf '%s\n' "$requiredPlugins" | grep -F -x -v "$installedPlugins" | while IFS= read -r plugin; do
89+
"$docker" plugin install --grant-all-permissions "$plugin"
90+
printf '%s\n' "Installed $plugin"
91+
done >/dev/null
92+
'';
93+
};
94+
};
95+
};
96+
4897
security.wrappers = mkIf config.host.docker.rootless.enable {
4998
docker-rootlesskit = {
5099
owner = "root";
@@ -53,5 +102,6 @@ with lib;
53102
source = "${pkgs.rootlesskit}/bin/rootlesskit";
54103
};
55104
};
105+
56106
};
57107
}

modules/rclone.nix

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
{
2+
config,
3+
lib,
4+
pkgs,
5+
...
6+
}:
7+
8+
let
9+
cfg = config.host.rclone;
10+
dockerHasRclonePlugin = builtins.any (
11+
p: builtins.match ".*rclone.*" p != null
12+
) config.host.docker.plugins;
13+
in
14+
with lib;
15+
{
16+
options = {
17+
host.rclone.enable = mkEnableOption "rclone";
18+
};
19+
20+
config = mkIf cfg.enable {
21+
environment.systemPackages = with pkgs; [
22+
fuse
23+
rclone
24+
];
25+
26+
# TODO: encrypt to disk using rclone config encryption?
27+
sops.secrets = mkIf (config.host.docker.enable && dockerHasRclonePlugin) {
28+
"docker-rclone/rclone.conf" = {
29+
format = "binary";
30+
sopsFile = ../hosts/shared/secrets/rclone.conf;
31+
path = "/var/lib/docker-plugins/rclone/config/rclone.conf";
32+
};
33+
};
34+
35+
systemd.tmpfiles.rules =
36+
mkIf (config.host.docker.enable && config.host.docker.rootless.enable && dockerHasRclonePlugin)
37+
[
38+
"d /var/lib/docker-plugins/rclone/config 0755 root root -"
39+
"d /var/lib/docker-plugins/rclone/cache 0755 root root -"
40+
];
41+
};
42+
}

0 commit comments

Comments
 (0)