blob: 93bf71ea3ecc1082c398b16e8b1b9f360258b336 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
|
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.dockerRegistry;
blobCache = if cfg.enableRedisCache
then "redis"
else "inmemory";
registryConfig = {
version = "0.1";
log.fields.service = "registry";
storage = {
cache.blobdescriptor = blobCache;
delete.enabled = cfg.enableDelete;
} // (optionalAttrs (cfg.storagePath != null) { filesystem.rootdirectory = cfg.storagePath; });
http = {
addr = "${cfg.listenAddress}:${builtins.toString cfg.port}";
headers.X-Content-Type-Options = ["nosniff"];
};
health.storagedriver = {
enabled = true;
interval = "10s";
threshold = 3;
};
};
registryConfig.redis = mkIf cfg.enableRedisCache {
addr = "${cfg.redisUrl}";
password = "${cfg.redisPassword}";
db = 0;
dialtimeout = "10ms";
readtimeout = "10ms";
writetimeout = "10ms";
pool = {
maxidle = 16;
maxactive = 64;
idletimeout = "300s";
};
};
configFile = cfg.configFile;
in {
options.services.dockerRegistry = {
enable = mkEnableOption "Docker Registry";
package = mkPackageOption pkgs "docker-distribution" {
example = "gitlab-container-registry";
};
listenAddress = mkOption {
description = "Docker registry host or ip to bind to.";
default = "127.0.0.1";
type = types.str;
};
port = mkOption {
description = "Docker registry port to bind to.";
default = 5000;
type = types.port;
};
openFirewall = mkOption {
type = types.bool;
default = false;
description = "Opens the port used by the firewall.";
};
storagePath = mkOption {
type = types.nullOr types.path;
default = "/var/lib/docker-registry";
description = ''
Docker registry storage path for the filesystem storage backend. Set to
null to configure another backend via extraConfig.
'';
};
enableDelete = mkOption {
type = types.bool;
default = false;
description = "Enable delete for manifests and blobs.";
};
enableRedisCache = mkEnableOption "redis as blob cache";
redisUrl = mkOption {
type = types.str;
default = "localhost:6379";
description = "Set redis host and port.";
};
redisPassword = mkOption {
type = types.str;
default = "";
description = "Set redis password.";
};
extraConfig = mkOption {
description = ''
Docker extra registry configuration via environment variables.
'';
default = {};
type = types.attrs;
};
configFile = lib.mkOption {
default = pkgs.writeText "docker-registry-config.yml" (builtins.toJSON (recursiveUpdate registryConfig cfg.extraConfig));
defaultText = literalExpression ''pkgs.writeText "docker-registry-config.yml" "# my custom docker-registry-config.yml ..."'';
description = ''
Path to CNCF distribution config file.
Setting this option will override any configuration applied by the extraConfig option.
'';
type = types.path;
};
enableGarbageCollect = mkEnableOption "garbage collect";
garbageCollectDates = mkOption {
default = "daily";
type = types.str;
description = ''
Specification (in the format described by
{manpage}`systemd.time(7)`) of the time at
which the garbage collect will occur.
'';
};
};
config = mkIf cfg.enable {
systemd.services.docker-registry = {
description = "Docker Container Registry";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
script = ''
${cfg.package}/bin/registry serve ${configFile}
'';
serviceConfig = {
User = "docker-registry";
WorkingDirectory = cfg.storagePath;
AmbientCapabilities = mkIf (cfg.port < 1024) "cap_net_bind_service";
};
};
systemd.services.docker-registry-garbage-collect = {
description = "Run Garbage Collection for docker registry";
restartIfChanged = false;
unitConfig.X-StopOnRemoval = false;
serviceConfig.Type = "oneshot";
script = ''
${cfg.package}/bin/registry garbage-collect ${configFile}
/run/current-system/systemd/bin/systemctl restart docker-registry.service
'';
startAt = optional cfg.enableGarbageCollect cfg.garbageCollectDates;
};
users.users.docker-registry =
(optionalAttrs (cfg.storagePath != null) {
createHome = true;
home = cfg.storagePath;
}) // {
group = "docker-registry";
isSystemUser = true;
};
users.groups.docker-registry = {};
networking.firewall = mkIf cfg.openFirewall {
allowedTCPPorts = [ cfg.port ];
};
};
}
|