From f5c0b3f887a90c0dee1467d6e3ac151d4a2e9649 Mon Sep 17 00:00:00 2001 From: Michele Catalano Date: Sun, 4 Feb 2018 14:15:47 +0100 Subject: [PATCH 1/3] nixos/docker-registry: add more configuration options for docker-registry --- .../modules/services/misc/docker-registry.nix | 79 ++++++++++++++++++- 1 file changed, 78 insertions(+), 1 deletion(-) diff --git a/nixos/modules/services/misc/docker-registry.nix b/nixos/modules/services/misc/docker-registry.nix index 96ac2a1cf2c9dc..4866ecf7793a3f 100644 --- a/nixos/modules/services/misc/docker-registry.nix +++ b/nixos/modules/services/misc/docker-registry.nix @@ -5,6 +5,57 @@ with lib; let cfg = config.services.dockerRegistry; + blogCache = if cfg.enableRedisCache + then "redis" + else "inmemory"; + + registryConfig = { + version = "0.1"; + log = { + fields = { + service = "registry"; + }; + }; + storage = { + cache = { + blobdescriptor = "${blogCache}"; + }; + filesystem = { + rootdirectory = "/var/lib/registry"; + }; + delete = { + enabled = cfg.enableDelete; + }; + }; + http = { + addr = ":5000"; + 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"; + }; + }; + in { options.services.dockerRegistry = { enable = mkEnableOption "Docker Registry"; @@ -27,6 +78,30 @@ in { description = "Docker registry storage path."; }; + enableDelete = mkOption { + type = types.bool; + default = false; + description = "Enable delete for manifests and blobs."; + }; + + enableRedisCache = mkOption { + type = types.bool; + default = false; + description = "Enable redis as blob cache instade of inmemory."; + }; + + redisUrl = mkOption { + type = types.str; + default = "localhost:6379"; + description = "Set redis host and port."; + }; + + redisPassword = mkOption { + type = types.str; + default = "asecret"; + description = "Set redis password."; + }; + extraConfig = mkOption { description = '' Docker extra registry configuration via environment variables. @@ -37,6 +112,8 @@ in { }; config = mkIf cfg.enable { + environment.etc."docker/registry/config.yml".text = builtins.toJSON registryConfig; + systemd.services.docker-registry = { description = "Docker Container Registry"; wantedBy = [ "multi-user.target" ]; @@ -49,7 +126,7 @@ in { script = '' ${pkgs.docker-distribution}/bin/registry serve \ - ${pkgs.docker-distribution.out}/share/go/src/github.com/docker/distribution/cmd/registry/config-example.yml + /etc/docker/registry/config.yml ''; serviceConfig = { From 593dc4514192354491473ba00e1b9104f456c50c Mon Sep 17 00:00:00 2001 From: Maximilian Bosch Date: Mon, 26 Mar 2018 13:54:01 +0200 Subject: [PATCH 2/3] nixos/docker-registry: cleanup module definition & enhance testcase The following changes have been applied: - the property `http.headers.X-Content-Type-Options` must a list of strings rather than a serialized list - instead of `/etc/docker/registry/config.yml` the configuration will be written with `pkgs.writeText` and the store path will be used to run the registry. This reduces the risk of possible impurities by relying on the Nix store only. - cleaned up the property paths to easy readability and reduce the verbosity. - enhanced the testcase to ensure that digests can be deleted as well - the `services.docker-registry.extraConfig` object will be merged with `registryConfig` /cc @ironpinguin --- nixos/doc/manual/release-notes/rl-1809.xml | 7 +++ .../modules/services/misc/docker-registry.nix | 57 ++++++------------- nixos/tests/docker-registry.nix | 8 ++- 3 files changed, 32 insertions(+), 40 deletions(-) diff --git a/nixos/doc/manual/release-notes/rl-1809.xml b/nixos/doc/manual/release-notes/rl-1809.xml index 62f1b769463be1..5ff5caaf255451 100644 --- a/nixos/doc/manual/release-notes/rl-1809.xml +++ b/nixos/doc/manual/release-notes/rl-1809.xml @@ -77,6 +77,13 @@ following incompatible changes: accepted by the nc command. + + + The services.docker-registry.extraConfig object doesn't contain + environment variables anymore. Instead it needs to provide an object structure + that can be mapped onto the YAML configuration defined in the docker/distribution docs. + + diff --git a/nixos/modules/services/misc/docker-registry.nix b/nixos/modules/services/misc/docker-registry.nix index 4866ecf7793a3f..c0dbcf380db326 100644 --- a/nixos/modules/services/misc/docker-registry.nix +++ b/nixos/modules/services/misc/docker-registry.nix @@ -5,40 +5,26 @@ with lib; let cfg = config.services.dockerRegistry; - blogCache = if cfg.enableRedisCache - then "redis" - else "inmemory"; + blobCache = if cfg.enableRedisCache + then "redis" + else "inmemory"; registryConfig = { version = "0.1"; - log = { - fields = { - service = "registry"; - }; - }; + log.fields.service = "registry"; storage = { - cache = { - blobdescriptor = "${blogCache}"; - }; - filesystem = { - rootdirectory = "/var/lib/registry"; - }; - delete = { - enabled = cfg.enableDelete; - }; + cache.blobdescriptor = blobCache; + filesystem.rootdirectory = cfg.storagePath; + delete.enabled = cfg.enableDelete; }; http = { - addr = ":5000"; - headers = { - X-Content-Type-Options = "[nosniff]"; - }; + addr = ":${builtins.toString cfg.port}"; + headers.X-Content-Type-Options = ["nosniff"]; }; - health = { - storagedriver = { - enabled = true; - interval = "10s"; - threshold = 3; - }; + health.storagedriver = { + enabled = true; + interval = "10s"; + threshold = 3; }; }; @@ -98,7 +84,7 @@ in { redisPassword = mkOption { type = types.str; - default = "asecret"; + default = ""; description = "Set redis password."; }; @@ -112,21 +98,14 @@ in { }; config = mkIf cfg.enable { - environment.etc."docker/registry/config.yml".text = builtins.toJSON registryConfig; - systemd.services.docker-registry = { description = "Docker Container Registry"; wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; - - environment = { - REGISTRY_HTTP_ADDR = "${cfg.listenAddress}:${toString cfg.port}"; - REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY = cfg.storagePath; - } // cfg.extraConfig; - - script = '' - ${pkgs.docker-distribution}/bin/registry serve \ - /etc/docker/registry/config.yml + script = let + configFile = pkgs.writeText "docker-registry-config.yml" (builtins.toJSON (registryConfig // cfg.extraConfig)); + in '' + ${pkgs.docker-distribution}/bin/registry serve ${configFile} ''; serviceConfig = { diff --git a/nixos/tests/docker-registry.nix b/nixos/tests/docker-registry.nix index 109fca440e57e0..943773ee391848 100644 --- a/nixos/tests/docker-registry.nix +++ b/nixos/tests/docker-registry.nix @@ -3,12 +3,13 @@ import ./make-test.nix ({ pkgs, ...} : { name = "docker-registry"; meta = with pkgs.stdenv.lib.maintainers; { - maintainers = [ globin ]; + maintainers = [ globin ma27 ]; }; nodes = { registry = { config, pkgs, ... }: { services.dockerRegistry.enable = true; + services.dockerRegistry.enableDelete = true; services.dockerRegistry.port = 8080; services.dockerRegistry.listenAddress = "0.0.0.0"; networking.firewall.allowedTCPPorts = [ 8080 ]; @@ -22,6 +23,7 @@ import ./make-test.nix ({ pkgs, ...} : { client2 = { config, pkgs, ...}: { virtualisation.docker.enable = true; virtualisation.docker.extraOptions = "--insecure-registry registry:8080"; + environment.systemPackages = [ pkgs.jq ]; }; }; @@ -39,5 +41,9 @@ import ./make-test.nix ({ pkgs, ...} : { $client2->waitForUnit("docker.service"); $client2->succeed("docker pull registry:8080/scratch"); $client2->succeed("docker images | grep scratch"); + + $client2->succeed( + 'curl -fsS -X DELETE registry:8080/v2/scratch/manifests/$(curl registry:8080/v2/scratch/manifests/latest | jq ".fsLayers[0].blobSum" | sed -e \'s/"//g\')' + ); ''; }) From afd3136e8efe2cbd477cb6db7be5ad7b2eb7efc6 Mon Sep 17 00:00:00 2001 From: Michele Catalano Date: Fri, 6 Apr 2018 15:11:52 +0200 Subject: [PATCH 3/3] nixos/docker-registry: Add support for garbage collector to docker registry --- .../modules/services/misc/docker-registry.nix | 41 +++++++++++++++---- nixos/tests/docker-registry.nix | 20 +++++++-- 2 files changed, 50 insertions(+), 11 deletions(-) diff --git a/nixos/modules/services/misc/docker-registry.nix b/nixos/modules/services/misc/docker-registry.nix index c0dbcf380db326..45931cb42b54fd 100644 --- a/nixos/modules/services/misc/docker-registry.nix +++ b/nixos/modules/services/misc/docker-registry.nix @@ -42,6 +42,8 @@ let }; }; + configFile = pkgs.writeText "docker-registry-config.yml" (builtins.toJSON (registryConfig // cfg.extraConfig)); + in { options.services.dockerRegistry = { enable = mkEnableOption "Docker Registry"; @@ -70,11 +72,7 @@ in { description = "Enable delete for manifests and blobs."; }; - enableRedisCache = mkOption { - type = types.bool; - default = false; - description = "Enable redis as blob cache instade of inmemory."; - }; + enableRedisCache = mkEnableOption "redis as blob cache"; redisUrl = mkOption { type = types.str; @@ -95,6 +93,19 @@ in { default = {}; type = types.attrsOf types.str; }; + + enableGarbageCollect = mkEnableOption "garbage collect"; + + garbageCollectDates = mkOption { + default = "daily"; + type = types.str; + description = '' + Specification (in the format described by + systemd.time + 7) of the time at + which the garbage collect will occur. + ''; + }; }; config = mkIf cfg.enable { @@ -102,9 +113,7 @@ in { description = "Docker Container Registry"; wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; - script = let - configFile = pkgs.writeText "docker-registry-config.yml" (builtins.toJSON (registryConfig // cfg.extraConfig)); - in '' + script = '' ${pkgs.docker-distribution}/bin/registry serve ${configFile} ''; @@ -114,6 +123,22 @@ in { }; }; + systemd.services.docker-registry-garbage-collect = { + description = "Run Garbage Collection for docker registry"; + + restartIfChanged = false; + unitConfig.X-StopOnRemoval = false; + + serviceConfig.Type = "oneshot"; + + script = '' + ${pkgs.docker-distribution}/bin/registry garbage-collect ${configFile} + ${pkgs.systemd}/bin/systemctl restart docker-registry.service + ''; + + startAt = optional cfg.enableGarbageCollect cfg.garbageCollectDates; + }; + users.extraUsers.docker-registry = { createHome = true; home = cfg.storagePath; diff --git a/nixos/tests/docker-registry.nix b/nixos/tests/docker-registry.nix index 943773ee391848..1fbd199c7bc4f1 100644 --- a/nixos/tests/docker-registry.nix +++ b/nixos/tests/docker-registry.nix @@ -3,7 +3,7 @@ import ./make-test.nix ({ pkgs, ...} : { name = "docker-registry"; meta = with pkgs.stdenv.lib.maintainers; { - maintainers = [ globin ma27 ]; + maintainers = [ globin ma27 ironpinguin ]; }; nodes = { @@ -12,6 +12,7 @@ import ./make-test.nix ({ pkgs, ...} : { services.dockerRegistry.enableDelete = true; services.dockerRegistry.port = 8080; services.dockerRegistry.listenAddress = "0.0.0.0"; + services.dockerRegistry.enableGarbageCollect = true; networking.firewall.allowedTCPPorts = [ 8080 ]; }; @@ -23,7 +24,6 @@ import ./make-test.nix ({ pkgs, ...} : { client2 = { config, pkgs, ...}: { virtualisation.docker.enable = true; virtualisation.docker.extraOptions = "--insecure-registry registry:8080"; - environment.systemPackages = [ pkgs.jq ]; }; }; @@ -35,6 +35,7 @@ import ./make-test.nix ({ pkgs, ...} : { $registry->start(); $registry->waitForUnit("docker-registry.service"); + $registry->waitForOpenPort("8080"); $client1->succeed("docker push registry:8080/scratch"); $client2->start(); @@ -43,7 +44,20 @@ import ./make-test.nix ({ pkgs, ...} : { $client2->succeed("docker images | grep scratch"); $client2->succeed( - 'curl -fsS -X DELETE registry:8080/v2/scratch/manifests/$(curl registry:8080/v2/scratch/manifests/latest | jq ".fsLayers[0].blobSum" | sed -e \'s/"//g\')' + 'curl -fsS -X DELETE registry:8080/v2/scratch/manifests/$(curl -fsS -I -H"Accept: application/vnd.docker.distribution.manifest.v2+json" registry:8080/v2/scratch/manifests/latest | grep Docker-Content-Digest | sed -e \'s/Docker-Content-Digest: //\' | tr -d \'\r\')' + ); + + $registry->systemctl("start docker-registry-garbage-collect.service"); + $registry->waitUntilFails("systemctl status docker-registry-garbage-collect.service"); + $registry->waitForUnit("docker-registry.service"); + + $registry->fail( + 'ls -l /var/lib/docker-registry/docker/registry/v2/blobs/sha256/*/*/data' + ); + + $client1->succeed("docker push registry:8080/scratch"); + $registry->succeed( + 'ls -l /var/lib/docker-registry/docker/registry/v2/blobs/sha256/*/*/data' ); ''; })