Docker Registry

Create a secure private registry (2.0)

docker run -d \
            -p 5000:5000 \
            -p 443:443 \
            --restart=always \
            --name registry \
            -v /var/lib/docker/volumes/my-registry/_data:/var/lib/registry \
            -v /srv/registry:/srv/registry \
            -e REGISTRY_HTTP_TLS_CERTIFICATE=/srv/registry/domain.crt \
            -e REGISTRY_HTTP_TLS_KEY=/srv/registry/domain.key \
            -e REGISTRY_HTTP_ADDR=0.0.0.0:443 \
            registry:2

Some notes :
– 5000 and 443 are the http port (no sure and secure port) of the registry. Exposing both is maybe not required.
– by default, registry uses a volume for data (/var/lib/registry). To improve performance we use a bind mount on that.
– we overwrite the /srv/registry content of the container with a bind mount (not for performance but for convenience).

Create a private registry with a user/pass access

Two steps :
– first : create the user/password and store it into the docker host

docker run \
  --rm \
  --entrypoint htpasswd \
  registry:2.7 -Bbn fooUser fooPass > /foo/auth/htpasswd

– second : create a new registry instance by setting the user/password info. Here only the docker args to pass related to that :

Set the registry password when the register is created : 
-v /foo/auth:/auth \
-e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
-e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \

Registry login

docker login -u username -p passwordNotBase64Encoded urlOfTheRegistry

If the login is successful, as a result we could access to that docker registry (docker pull, FROM …).
Besides, the user-password will be stored as basic authent (base64 encoded with : separator) and stored in $HOME/.docker/config.json or /root/.docker/config.json (if the user is root).
That file looks like :

{
        "auths": {
                "myregistry.org": {
                        "auth": "base64userAndPass...."
                }
        },
        "HttpHeaders": {
                "User-Agent": "Docker-Client/18.20.1-ce (linux)"
        }
}[

Tag and push a custom local image in a private registry

Here the registry is stored on a machine with the hostname : david-virtual-machine and the port 443 of the docker registry container is mapped on the 444 port of the host.
At last the custom local image is maven-with-nexus-configured:maven-3.6-java-11.

docker tag maven-with-nexus-configured:maven-3.6-java-11 david-virtual-machine:444/maven-with-nexus-configured:maven-3.6-java-11
docker push  david-virtual-machine:444/maven-with-nexus-configured:maven-3.6-java-11

Deploy an unsecure registry

On the host of the registry and on every docker hosts that use the registry, add the registry configuration : /etc/docker/daemon.json :
{ "insecure-registries" : ["myregistrydomain.com:5000"] }

Use a self-signed certificates

This is more secure than the insecure registry solution (above).
Steps :
1) Generate a client certificate (domain.crt) and a private key (domain.key) on the registry host :

 openssl req \
  -newkey rsa:4096 -nodes -sha256 -keyout domain.key \
  -x509 -days 5000 -subj "/C=FR/ST=Foo/L=Foo/O=Foo/CN=myregistrydomain.com" -out domain.crt

2) On the registry host :
* copy domain.crt in /etc/docker/certs.d/myregistrydomain.com:443 folder.
Warn : don’t copy domain.key. Helpless because that is passed as the registry is launched.

* the first time : start the docker registry by passing the domain.key and domain.crt as TLS_CERTIF.. AND TLS… such as :
-e REGISTRY_HTTP_TLS_CERTIFICATE=...foo/registry/domain.crt \
-e REGISTRY_HTTP_TLS_KEY=foo./registry/domain.key

If the certificates have changed: stop and remove the registry container and start a new instance of that.

3) Instruct each docker daemon of docker clients to use that certificate.
* copy and domain.crt in /etc/docker/certs.d/myregistrydomain.com:443 folder
* restart docker daemon

Beware : don’t copy domain.key on docker clients because it may provoke errors.

To view the certificate content:
openssl x509 -in domain.cert -noout -text

Registry WS API

To access to a secure registry :
curl -kv https://localhost:443/v2/_catalog

List repositories
List all images but don’t specify all tags for them:
GET /_catalog

List image tags
List all tags of a image.
GET /<imageName>/tags/list

Get manifest by a reference (tag or digest)
reference parameter :  tag or digest.
It returns metadata such as history, image date creation, layers, and so for…
GET /<imageName>/manifests/<reference>

Retrieve the blob from the registry identified by name and digest (not working):
GET /<name>/blobs/<digest>

Delete a layer (image blob) identified by image name and digest
Digest parameter : the layer digest are listed by Get manifest for an image+tag(see above).
DELETE /v2/<imageName>/blobs/<digest>
ex: delete layer
curl -kv -X DELETE "https://localhost:443/v2/foo/image/blobs/sha256:000000000000e000e0e000"

Delete an image identified by image name and a « special » digest:
First:
Retrieve the digest of the image foo/bar with the version latest:
curl -v -k -X HEAD -H "Accept: application/vnd.docker.distribution.manifest.v2+json" "https://localhost:443/v2/foo/bar/manifests/latest"
Output :

< HTTP/1.1 200 OK
< Content-Length: 12735
< Content-Type: application/vnd.docker.distribution.manifest.v1+prettyjws
< Docker-Content-Digest: sha256:34e8501z4c11c3z7ec873f9a9b5546ce4bc83e7413fzb0z9e68z8333a739z041
< Docker-Distribution-Api-Version: registry/2.0
< Etag: "sha256:34e8501z4c11c3z7ec873f9a9b5546ce4bc83e7413fzb0z9e68z8333a739z041"
< X-Content-Type-Options: nosniff
< Date: Tue, 06 Aug 2020 14:06:43 GMT

Digest is : sha256:34e8501z4c11c3z7ec873f9a9b5546ce4bc83e7413fzb0z9e68z8333a739z041

Then we could delete the image
The version of the tag is helpless here. What we need is the image name and the digest (retrieved above) :
curl -v -k -X DELETE "http://localhost:443/v2/foo/bar/manifests/sha256:34e8501z4c11c3z7ec873f9a9b5546ce4bc83e7413fzb0z9e68z8333a739z041"
Output :

< HTTP/1.1 202 Accepted
< Docker-Distribution-Api-Version: registry/2.0
< X-Content-Type-Options: nosniff
< Date: Tue, 06 Aug 2020 14:07:32 GMT
< Content-Length: 0

Deleting an image may return a 405 (method not allowed) :
{"errors":[{"code":"UNSUPPORTED","message":"The operation is unsupported."}]}
To fix that we need that our registry allows deleting operation.
The storage element of the registry.yml must value the delete.enabled property with true :

storage:
 cache:
    blobdescriptor: inmemory
 filesystem:
    rootdirectory: /var/lib/registry
 delete:
    enabled: true

Common issues

Problem : docker pull foo-image loops on one or multiple layers and terminates with unexpected EOF such as :

7a9d5b1b344: Retrying in XX seconds
7a9d5b1b322: Retrying in XX seconds
7a9d5b1ba11: Retrying in XX seconds
7a9d5b1ba55:  Download complete
unexpected EOF

Solution :

Ce contenu a été publié dans Non classé. Vous pouvez le mettre en favoris avec ce permalien.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *