at 22.05-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 "Docker Registry"; 51 52 listenAddress = mkOption { 53 description = "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 = "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 = '' 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 = "Enable delete for manifests and blobs."; 77 }; 78 79 enableRedisCache = mkEnableOption "redis as blob cache"; 80 81 redisUrl = mkOption { 82 type = types.str; 83 default = "localhost:6379"; 84 description = "Set redis host and port."; 85 }; 86 87 redisPassword = mkOption { 88 type = types.str; 89 default = ""; 90 description = "Set redis password."; 91 }; 92 93 extraConfig = mkOption { 94 description = '' 95 Docker extra registry configuration via environment variables. 96 ''; 97 default = {}; 98 type = types.attrs; 99 }; 100 101 enableGarbageCollect = mkEnableOption "garbage collect"; 102 103 garbageCollectDates = mkOption { 104 default = "daily"; 105 type = types.str; 106 description = '' 107 Specification (in the format described by 108 <citerefentry><refentrytitle>systemd.time</refentrytitle> 109 <manvolnum>7</manvolnum></citerefentry>) of the time at 110 which the garbage collect will occur. 111 ''; 112 }; 113 }; 114 115 config = mkIf cfg.enable { 116 systemd.services.docker-registry = { 117 description = "Docker Container Registry"; 118 wantedBy = [ "multi-user.target" ]; 119 after = [ "network.target" ]; 120 script = '' 121 ${pkgs.docker-distribution}/bin/registry serve ${configFile} 122 ''; 123 124 serviceConfig = { 125 User = "docker-registry"; 126 WorkingDirectory = cfg.storagePath; 127 AmbientCapabilities = mkIf (cfg.port < 1024) "cap_net_bind_service"; 128 }; 129 }; 130 131 systemd.services.docker-registry-garbage-collect = { 132 description = "Run Garbage Collection for docker registry"; 133 134 restartIfChanged = false; 135 unitConfig.X-StopOnRemoval = false; 136 137 serviceConfig.Type = "oneshot"; 138 139 script = '' 140 ${pkgs.docker-distribution}/bin/registry garbage-collect ${configFile} 141 /run/current-system/systemd/bin/systemctl restart docker-registry.service 142 ''; 143 144 startAt = optional cfg.enableGarbageCollect cfg.garbageCollectDates; 145 }; 146 147 users.users.docker-registry = 148 (if cfg.storagePath != null 149 then { 150 createHome = true; 151 home = cfg.storagePath; 152 } 153 else {}) // { 154 group = "docker-registry"; 155 isSystemUser = true; 156 }; 157 users.groups.docker-registry = {}; 158 }; 159}