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