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