Uncategorized

Setting Up Docker Private Registry

Last year Containers based technology showed up big boom. A lot of OpenSource projects and startups wrapped over Docker. Now Docker became a favourite tool for both Dev and Ops guys. I’m a big fan of Docker and i do all my hacks on containers. This time i decided to play with Docker private registry, so that i sync all my docker clients with a central registry. In this test setup i’m using Ubuntu 12.04 server with Nginx as a reverse proxy. With the Nginx proxy i can easily enforce basic auth and can protect my private docker registry from unauthorized access.

Installing Docker Registry

Download the latest release of Docker Registry from the Docker’s github repo

$ wget https://github.com/docker/docker-registry/archive/0.9.0.tar.gz -O /usr/local/src/0.9.0.tar.gz

$ tar xvzf 0.9.0.tar.gz && mv docker-registry-0.9.0 docker-registry


Let's install the dependencies,

$ apt-get update && apt-get install swig python-pip python-dev libssl-dev liblzma-dev libevent1-dev patch


Once the dependencies are installed, lets go ahead and install the docker-registry app

$ cat /usr/local/src/docker-registry/config/boto.cfg > /etc/boto.cfg

$ pip install /usr/local/src/docker-registry/depends/docker-registry-core/

$ pip install file:///usr/local/src/docker-registry

$ patch $(python -c 'import boto; import os; print os.path.dirname(boto.__file__)')/connection.py < /usr/local/src/docker-registry/contrib/boto_header_patch.diff

$ cp /usr/local/src/docker-registry/config/config_sample.yml /usr/local/src/docker-registry/config/config.yml 


We can edit the `config.yml` file, if we want to change the local storage path (default => /tmp/registry) and also we can use redis as a local cache + sqlite based search backend. The repo already contains a sample init [init](https://raw.githubusercontent.com/docker/docker-registry/master/contrib/docker-registry_debian.sh) script that can be used directly.

$ cp -rvf /usr/local/src/docker-registry/contrib/docker-registry_debian.sh /etc/init.d/docker-registry

Also let's setup a default file, `/etc/default/docker-registry`, so that init script can read the necessary env variables. Below is the content of my default file.

DOCKER_REGISTRY_HOME=/usr/local/src/docker-registry
DOCKER_REGISTRY_CONFIG=/usr/local/src/docker-registry/config/config.yml
SETTINGS_FLAVOR=dev
GUNICORN_OPTS=[--preload]
LOGLEVEL=debug

Let's start the registry service,

$ /etc/init.d/docker-registry start

Setting up Docker Client

Now we have a private Docker registry running, Now let’s setup an Nginx proxy, so that we dont have to expose the registry directly to outside world.

$ apt-get install nginx-extras

The docker-registry repo also contains basic nginx config that can be used directly.

$ cat /usr/local/src/docker-registry/contrib/nginx/nginx.conf > /etc/nginx/sites-enabled/default

$ cp /usr/local/src/docker-registry/contrib/nginx/docker-registry.conf /etc/nginx/

Also create a basic auth file that contains the username password. We can use htpasswd to generate the password. The filename mentioned the nginx config is docker-registry.htpasswd

$ echo "dockeradmin:$apr1$.BzsRrxN$fng.12mJL/TJenKjkZSMS0" >> /etc/nginx/docker-registry.htpasswd  # replace the username and password with the one generated by htpasswd

Now let’s generate a self signed SSL certificate that can be used with nginx. There are websites like StartSSL which provides free 1 year SSL certificate.

$ mkdir /opt/certs && cd /opt/certs

$ openssl genrsa -out devdockerCA.key 2048

$ openssl req -x509 -new -nodes -key devdockerCA.key -days 10000 -out devdockerCA.crt

$ openssl genrsa -out dev-docker-registry.com.key 2048

$ openssl req -new -key dev-docker-registry.com.key -out dev-docker-registry.com.csr

    Country Name (2 letter code) [AU]: US
        State or Province Name (full name) [Some-State]: CA
        Locality Name (eg, city) []: SF
        Organization Name (eg, company) [Internet Widgits Pty Ltd]: Beingasysadmin
        Organizational Unit Name (eg, section) []: tech
        Common Name (e.g. server FQDN or YOUR name) []: docker.example.com
        Email Address []: docker@example.com

        Please enter the following 'extra' attributes
        to be sent with your certificate request
        A challenge password []:                          # leave the password blank
        An optional company name []:

$ openssl x509 -req -in dev-docker-registry.com.csr -CA devdockerCA.crt -CAkey devdockerCA.key -CAcreateserial -out dev-docker-registry.com.crt -days 10000

Copy the certificates to the SSL path mentioned the nginx config,

$ cp dev-docker-registry.com.crt /etc/ssl/certs/docker-registry

$ cp dev-docker-registry.com.key /etc/ssl/private/docker-registry

Now let’s restart the nginx process to reflect the changes

$ service nginx restart

Now once the nginx is up, we can check the connectivity between docker client and registry server. Since registry is using a self signed certificate, we need to whitelist the CA on the Docker client machine.

$ cd /opt/certs

$ mkdir /usr/local/share/ca-certificates/docker-dev-cert

$ cp devdockerCA.crt /usr/local/share/ca-certificates/docker-dev-cert

$ update-ca-certificates

Note: If the CA is not added to trusted list, Docker client wont be able to authenticate against the registry server. Once the CA is added to trusted list, we can test the connectivity between Docker client and Registry server. If the Docker daemon was running before adding the CA, then we need to restart the Docker daemon

$ root@docker:~# docker login https://docker.example.com      # use the nginx basic auth creds here, email can be blank
    Username: dockeradmin
    Password:xxxxxxxx
    Email:                          # This we can leave blank
    Login Succeeded                                         # Successful login message

Once the login is succeeded, lets add some base docker images to our Private registry.

$ docker pull ubuntu:12.04                             #  Pulling the latest image of Ubuntu 12.04
    ubuntu:12.04: The image you are pulling has been verified
    ed52aaa56e98: Pull complete
    b875af6dcb23: Pull complete
    41959ee20b93: Pull complete
    f959d044ebdf: Pull complete
    511136ea3c5a: Already exists
    Status: Downloaded newer image for ubuntu:12.04


$ docker images                             # Check the downloaded images
    REPOSITORY                  TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
    ubuntu                      12.04               f959d044ebdf        5 days ago          130.1 MB

So, as per the Documentation, we need to create a tag for the image that we are going to push to our private registry. The tag must be of the syntax ”/:”

$ docker tag ubuntu:12.04 docker.example.com/ubuntu:12.04     # We need to create a tag of format "<registry-server-fqdn>/<image-name>:<optional-tag>"


$ docker push docker.example.com/ubuntu:12.04                 # push the image to our new private registry
    The push refers to a repository [docker.example.com/ubuntu] (len: 1)
    Sending image list
    Pushing repository docker.example.com/ubuntu (1 tags)
    Image 511136ea3c5a already pushed, skipping
    ed52aaa56e98: Image successfully pushed
    b875af6dcb23: Image successfully pushed
    41959ee20b93: Image successfully pushed
    f959d044ebdf: Image successfully pushed
    Pushing tag for rev [f959d044ebdf] on {https://docker.example.com/v1/repositories/ubuntu/tags/12.04}

Let’s query the registry API for the pushed image

curl http://localhost:5000/v1/search
    {"num_results": 2, "query": "", "results": [{"description": "", "name": "library/wheezy"}, {"description": "", "name": "library/ubuntu"}]}

Currently both the Docker Client and Registry resides on the same machine, we can test push/pull image from a remote machine. The only dependency is we need to add the Self Signed CA to the trusted CA list, otherwise docker client will raise an SSL error while trying to login against the private registry.

Now let’s try pulling the images from the private registry.

$ docker pull docker.example.com/ubuntu:12.04
    Pulling repository docker.example.com/ubuntu
    f959d044ebdf: Download complete
    511136ea3c5a: Download complete
    ed52aaa56e98: Download complete
    b875af6dcb23: Download complete
    41959ee20b93: Download complete
    Status: Downloaded newer image for docker.example.com/ubuntu:12.04

$ docker images
    REPOSITORY                  TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
    debian                      wheezy              479215127fa7        5 days ago          84.99 MB
    docker.example.com/wheezy   latest              479215127fa7        5 days ago          84.99 MB
    docker.example.com/ubuntu   12.04               f959d044ebdf        5 days ago          130.1 MB

Setting up S3 Backend for Docker Registry

Docker registry by default supports S3 backend for storing the images. But if we are using S3, it’s better to cache the image locally so that we don’t have to fetch S3 all the time. Redis really comes to the rescue. We can set up Redis Server as an LRU Cache and can define the settings in the config.yml of the registry or as an env variable.

$ apt-get install redis-server

Once Redis server is installed, we need to define the maxmemory to be allocated for the cache and maxmemory-policy which tells Redis how to clean the old cache when the maxmemory limit is reached. Add below settings to the redis.conf file

maxmemory 2000mb              # i'm allocating 2GB of cache size

maxmemory-policy volatile-lru     # removes the key with an expire set using an LRU algorithm

Now let’s define the env variables so that docker-registry can use them while starting up. Add the below variables to the /etc/default/docker-registry file.

CACHE_REDIS_HOST=localhost
CACHE_REDIS_PORT=6379
CACHE_REDIS_DB=0

CACHE_LRU_REDIS_HOST=localhost
CACHE_LRU_REDIS_PORT=6379
CACHE_LRU_REDIS_DB=0

Let’s start the Docker Registry in foreground and see if it’s starting with Redis Cache.

root@docker:~# docker-registry

   13/Jan/2015:19:07:42 +0000 INFO: Enabling storage cache on Redis
   13/Jan/2015:19:07:42 +0000 INFO: Redis host: localhost:6379 (db0)
   13/Jan/2015:19:07:42 +0000 INFO: Enabling lru cache on Redis
       13/Jan/2015:19:07:42 +0000 INFO: Redis lru host: localhost:6379 (db0)
       13/Jan/2015:19:07:42 +0000 INFO: Enabling storage cache on Redis

The above logs shows us that registry has started with Redis cache. Now we need to setup the S3 backend storage. By default for dev env, defaul backend is file storage. We need to change it to S3 in the config.yml

dev: &dev
    <<: *s3                            #by default this will be local, which is local file storage
    loglevel: _env:LOGLEVEL:debug
    debug: _env:DEBUG:true
    search_backend: _env:SEARCH_BACKEND:sqlalchemy

Now if we check the config.yml, in the S3 backend section, the mandatory variables are the ones mentioned below. The boto variables are needed only if we are using any non-Amazon S3-compliant object store.

AWS_REGION   => S3 region where the bucket is located
AWS_BUCKET   => S3 bucket name
STORAGE_PATH => the sub "folder" where image data will be stored
AWS_ENCRYPT  => if true, the container will be encrypted on the server-side by S3 and will be stored in an encrypted form while at rest in S3. Default value is `True`
AWS_SECURE   => true for HTTPS to S3
AWS_KEY      => S3 Access key
AWS_SECRET   => S3 secret key

We can define the above variables in the /etc/default/docker-registry file. And we need to restart the registry process to make the changes effective.

$ docker-registry         

    13/Jan/2015:23:40:39 +0000 INFO: Enabling storage cache on Redis
    13/Jan/2015:23:40:39 +0000 INFO: Redis host: localhost:6379 (db0)
    13/Jan/2015:23:40:39 +0000 INFO: Enabling lru cache on Redis
    13/Jan/2015:23:40:39 +0000 INFO: Redis lru host: localhost:6379 (db0)
    13/Jan/2015:23:40:39 +0000 INFO: Enabling storage cache on Redis
    13/Jan/2015:23:40:39 +0000 INFO: Redis config: {'path': '/registry1', 'host': 'localhost', 'password': None, 'db': 0, 'port': 6379}
    13/Jan/2015:23:40:39 +0000 DEBUG: Will return docker-registry.drivers.s3.Storage
    13/Jan/2015:23:40:39 +0000 DEBUG: Using access key provided by client.
    13/Jan/2015:23:40:39 +0000 DEBUG: Using secret key provided by client.
    13/Jan/2015:23:40:39 +0000 DEBUG: path=/
    13/Jan/2015:23:40:39 +0000 DEBUG: auth_path=/my-docker/
    13/Jan/2015:23:40:39 +0000 DEBUG: Method: HEAD
    13/Jan/2015:23:40:39 +0000 DEBUG: Path: /
    13/Jan/2015:23:40:39 +0000 DEBUG: Data:
    13/Jan/2015:23:40:39 +0000 DEBUG: Headers: {}
    13/Jan/2015:23:40:39 +0000 DEBUG: Host: my-docker.s3-us-west-2.amazonaws.com
    13/Jan/2015:23:40:39 +0000 DEBUG: Port: 443
    13/Jan/2015:23:40:39 +0000 DEBUG: Params: {}
    13/Jan/2015:23:40:39 +0000 DEBUG: establishing HTTPS connection: host=my-docker.s3-us-west-2.amazonaws.com, kwargs={'port': 443, 'timeout': 70}
    13/Jan/2015:23:40:39 +0000 DEBUG: Token: None
    13/Jan/2015:23:40:39 +0000 DEBUG: StringToSign:
    HEAD


    Tue, 13 Jan 2015 23:40:39 GMT
    /my-docker/
    13/Jan/2015:23:40:39 +0000 DEBUG: Signature:
    AWS XXXXXXXXXXXXXXXXXXXX:********************
    13/Jan/2015:23:40:39 +0000 DEBUG: Final headers: {'Date': 'Tue, 13 Jan 2015 23:40:39 GMT', 'Content-Length': '0', 'Authorization': u'AWS XXXXXXXXXXXXXXXXXXXX:********************', 'User-Agent': 'Boto/2.34.0 Python/2.7.3 Linux/3.8.0-44-generic'}
    13/Jan/2015:23:40:39 +0000 DEBUG: Response headers: [('x-amz-id-2', '*************************************************'), ('server', 'AmazonS3'), ('transfer-encoding', 'chunked'), ('x-amz-request-id', 'XXXXXXXXXXXXXX'), ('date', 'Tue, 13 Jan 2015 23:40:40 GMT'), ('content-type', 'application/xml')]
    13/Jan/2015:23:40:39 +0000 INFO: Boto based storage initialized
    2015-01-13 23:40:39 [21909] [INFO] Starting gunicorn 19.1.0
    2015-01-13 23:40:39 [21909] [INFO] Listening at: http://0.0.0.0:5000 (21909)
    2015-01-13 23:40:39 [21909] [INFO] Using worker: gevent
    2015-01-13 23:40:39 [21919] [INFO] Booting worker with pid: 21919
    2015-01-13 23:40:39 [21920] [INFO] Booting worker with pid: 21920
    2015-01-13 23:40:39 [21921] [INFO] Booting worker with pid: 21921
    2015-01-13 23:40:39 [21922] [INFO] Booting worker with pid: 21922
    2015-01-13 23:40:39 [21909] [INFO] 4 workers

So now we have the Docker registry with S3 backend and Redis cache. Let’s push one of our local image see if registry can upload it to the S3 bucket.

$ docker push docker.example.com/mydocker/debian:wheezy

    The push refers to a repository [docker.example.com/mydocker/debian] (len: 1)
    Sending image list
    Pushing repository docker.example.com/mydocker/debian (1 tags)
    511136ea3c5a: Image successfully pushed
    1aeada447715: Image successfully pushed
    479215127fa7: Image successfully pushed
    3192d5ea7137: Image successfully pushed
    Pushing tag for rev [3192d5ea7137] on {https://docker.example.com/v1/repositories/mydocker/debian/tags/wheezy}

Now let’s check debug logs to have a more glimpse on what’s happening in the background.

# Sample output of S3 image upload

    Tue, 13 Jan 2015 20:05:05 GMT
    /my-docker/registry1/images/3192d5ea7137e4f47f4624a5cc7786af2159a44f49511aeed28aa672416cec63/json
    13/Jan/2015:20:05:05 +0000 DEBUG: Signature:
    AWS XXXXXXXXXXXXXXXXXXXX:********************
    13/Jan/2015:20:05:05 +0000 DEBUG: Final headers: {'Date': 'Tue, 13 Jan 2015 20:05:05 GMT', 'Content-Length': '0', 'Authorization': u'AWS   XXXXXXXXXXXXXXXXXXXX:********************', 'User-Agent': 'Boto/2.34.0 Python/2.7.3 Linux/3.8.0-44-generic'}
    13/Jan/2015:20:05:05 +0000 DEBUG: Response headers: [('x-amz-id-2', '*****************************************************'), ('server', 'AmazonS3'), ('transfer-encoding', 'chunked'), ('x-amz-request-id', 'XXXXXXXXXXXXX'), ('date', 'Tue, 13 Jan 2015 20:05:05 GMT'), ('content-type', 'application/xml')]
    13/Jan/2015:20:05:05 +0000 DEBUG: path=/registry1/images/3192d5ea7137e4f47f4624a5cc7786af2159a44f49511aeed28aa672416cec63/_inprogress
    13/Jan/2015:20:05:05 +0000 DEBUG: auth_path=/my-docker/registry1/images/3192d5ea7137e4f47f4624a5cc7786af2159a44f49511aeed28aa672416cec63/_inprogress
    13/Jan/2015:20:05:05 +0000 DEBUG: Method: PUT
    13/Jan/2015:20:05:05 +0000 DEBUG: Path: /registry1/images/3192d5ea7137e4f47f4624a5cc7786af2159a44f49511aeed28aa672416cec63/_inprogress
    13/Jan/2015:20:05:05 +0000 DEBUG: Data:
    13/Jan/2015:20:05:05 +0000 DEBUG: Headers: {'Content-MD5': u'xxxxxxxxxxxxxxx', 'Content-Length': '4', 'Expect': '100-Continue', 'x-amz-server-side-encryption': 'AES256', 'Content-Type': 'application/octet-stream', 'User-Agent': 'Boto/2.34.0 Python/2.7.3 Linux/3.8.0-44-generic'}
    13/Jan/2015:20:05:05 +0000 DEBUG: Host: my-docker.s3-us-west-2.amazonaws.com
    13/Jan/2015:20:05:05 +0000 DEBUG: Port: 443
    13/Jan/2015:20:05:05 +0000 DEBUG: Params: {}
    13/Jan/2015:20:05:05 +0000 DEBUG: Token: None
    13/Jan/2015:20:05:05 +0000 DEBUG: StringToSign:
    PUT
    xxxxxxxxxxxxxxx
    application/octet-stream
    Tue, 13 Jan 2015 20:05:05 GMT
    x-amz-server-side-encryption:AES256
    /my-docker/registry1/images/3192d5ea7137e4f47f4624a5cc7786af2159a44f49511aeed28aa672416cec63/_inprogress
    13/Jan/2015:20:05:05 +0000 DEBUG: Signature:
    AWS XXXXXXXXXXXXXXXXXXXX:********************
    13/Jan/2015:20:05:05 +0000 DEBUG: Final headers: {'Content-MD5': 'xxxxxxxxxxxxx', 'Content-Length': '4', 'Expect': '100-Continue', 'Date': 'Tue,              13 Jan 2015 20:05:05 GMT', 'x-amz-server-side-encryption': 'AES256', 'Content-Type': 'application/octet-stream', 'Authorization': u'AWS XXXXXXXXXXXXXXXXXXXX:********************', 'User-Agent': 'Boto/2.34.0 Python/2.7.3 Linux/3.8.0-44-generic'}
    13/Jan/2015:20:05:05 +0000 DEBUG: Response headers: [('content-length', '0'), ('x-amz-id-2', '*************************************'), ('server', 'AmazonS3'), ('x-amz-request-id', 'xxxxxxxxxxxxxx'), ('etag', '"b326b5062b2f0e69046810717534cb09"'), ('date', 'Tue, 13 Jan 2015 20:05:06 GMT'), ('x-amz-server-side-encryption', 'AES256')]
    13/Jan/2015:20:05:05 +0000 DEBUG: path=/registry1/images/3192d5ea7137e4f47f4624a5cc7786af2159a44f49511aeed28aa672416cec63/_checksum
    13/Jan/2015:20:05:05 +0000 DEBUG: auth_path=/my-docker/registry1/images/3192d5ea7137e4f47f4624a5cc7786af2159a44f49511aeed28aa672416cec63/_checksum
    13/Jan/2015:20:05:05 +0000 DEBUG: Method: HEAD
    13/Jan/2015:20:05:05 +0000 DEBUG: Path: /registry1/images/3192d5ea7137e4f47f4624a5cc7786af2159a44f49511aeed28aa672416cec63/_checksum
    13/Jan/2015:20:05:05 +0000 DEBUG: Data:
    13/Jan/2015:20:05:05 +0000 DEBUG: Headers: {}
    13/Jan/2015:20:05:05 +0000 DEBUG: Host: my-docker.s3-us-west-2.amazonaws.com
    13/Jan/2015:20:05:05 +0000 DEBUG: Port: 443
    13/Jan/2015:20:05:05 +0000 DEBUG: Params: {}
    13/Jan/2015:20:05:05 +0000 DEBUG: Token: None
    13/Jan/2015:20:05:05 +0000 DEBUG: StringToSign:
    HEAD

    Tue, 13 Jan 2015 20:05:05 GMT
    /my-docker/registry1/images/3192d5ea7137e4f47f4624a5cc7786af2159a44f49511aeed28aa672416cec63/_checksum
    13/Jan/2015:20:05:05 +0000 DEBUG: Signature:
    AWS XXXXXXXXXXXXXXXXXXXX:********************
    13/Jan/2015:20:05:05 +0000 DEBUG: Final headers: {'Date': 'Tue, 13 Jan 2015 20:05:05 GMT', 'Content-Length': '0', 'Authorization': u'AWS   XXXXXXXXXXXXXXXXXXXX:********************', 'User-Agent': 'Boto/2.34.0 Python/2.7.3 Linux/3.8.0-44-generic'}
    13/Jan/2015:20:05:05 +0000 DEBUG: Response headers: [('x-amz-id-2', '***************************************************'), ('server', 'AmazonS3'), ('transfer-encoding', 'chunked'), ('x-amz-request-id', 'xxxxxxxxxxxxxxx'), ('date', 'Tue, 13 Jan 2015 20:05:05 GMT'), ('content-type', 'application/xml')]
    13/Jan/2015:20:05:05 +0000 DEBUG: path=/
    13/Jan/2015:20:05:05 +0000 DEBUG: auth_path=/my-docker/
    13/Jan/2015:20:05:05 +0000 DEBUG: path=/?delimiter=/&prefix=registry1/images/3192d5ea7137e4f47f4624a5cc7786af2159a44f49511aeed28aa672416cec63/_checksum/
    13/Jan/2015:20:05:05 +0000 DEBUG: auth_path=/my-docker/? delimiter=/&prefix=registry1/images/3192d5ea7137e4f47f4624a5cc7786af2159a44f49511aeed28aa672416cec63/_checksum/
    13/Jan/2015:20:05:05 +0000 DEBUG: Method: GET
    13/Jan/2015:20:05:05 +0000 DEBUG: Path: /?delimiter=/&prefix=registry1/images/3192d5ea7137e4f47f4624a5cc7786af2159a44f49511aeed28aa672416cec63/_checksum/
    13/Jan/2015:20:05:05 +0000 DEBUG: Data:
    13/Jan/2015:20:05:05 +0000 DEBUG: Headers: {}
    13/Jan/2015:20:05:05 +0000 DEBUG: Host: my-docker.s3-us-west-2.amazonaws.com
    13/Jan/2015:20:05:05 +0000 DEBUG: Port: 443
    13/Jan/2015:20:05:05 +0000 DEBUG: Params: {}
    13/Jan/2015:20:05:05 +0000 DEBUG: Token: None
    13/Jan/2015:20:05:05 +0000 DEBUG: StringToSign:
    13/Jan/2015:20:05:07 +0000 DEBUG: args = {'image_id': u'3192d5ea7137e4f47f4624a5cc7786af2159a44f49511aeed28aa672416cec63'}
    13/Jan/2015:20:05:07 +0000 DEBUG: path=/registry1/images/3192d5ea7137e4f47f4624a5cc7786af2159a44f49511aeed28aa672416cec63/layer
    13/Jan/2015:20:05:07 +0000 DEBUG: auth_path=/my-docker/registry1/images/3192d5ea7137e4f47f4624a5cc7786af2159a44f49511aeed28aa672416cec63/layer
    13/Jan/2015:20:05:07 +0000 DEBUG: Method: HEAD
    13/Jan/2015:20:05:07 +0000 DEBUG: Path: /registry1/images/3192d5ea7137e4f47f4624a5cc7786af2159a44f49511aeed28aa672416cec63/layer
    13/Jan/2015:20:05:07 +0000 DEBUG: Data:
    13/Jan/2015:20:05:07 +0000 DEBUG: Headers: {}
    13/Jan/2015:20:05:07 +0000 DEBUG: Host: my-docker.s3-us-west-2.amazonaws.com
    13/Jan/2015:20:05:07 +0000 DEBUG: Port: 443
    13/Jan/2015:20:05:07 +0000 DEBUG: Params: {}
    13/Jan/2015:20:05:07 +0000 DEBUG: Token: None
    13/Jan/2015:20:05:07 +0000 DEBUG: StringToSign:
    HEAD

    Tue, 13 Jan 2015 20:05:07 GMT
    /my-docker/registry1/images/3192d5ea7137e4f47f4624a5cc7786af2159a44f49511aeed28aa672416cec63/layer
    13/Jan/2015:20:05:07 +0000 DEBUG: Signature:
    AWS XXXXXXXXXXXXXXXXXXXX:********************
    13/Jan/2015:20:05:07 +0000 DEBUG: Final headers: {'Date': 'Tue, 13 Jan 2015 20:05:07 GMT', 'Content-Length': '0', 'Authorization': u'AWS   XXXXXXXXXXXXXXXXXXXX:********************', 'User-Agent': 'Boto/2.34.0 Python/2.7.3 Linux/3.8.0-44-generic'}   
    13/Jan/2015:20:05:07 +0000 DEBUG: Token: None
    13/Jan/2015:20:05:07 +0000 DEBUG: StringToSign:
    HEAD

Now let’s query the registry for the newly uploaded image

$ curl -k https://dockeradmin:xxxxxxx@docker.example.com/v1/repositories/mydocker/debian/tags/wheezy

    "3192d5ea7137e4f47f4624a5cc7786af2159a44f49511aeed28aa672416cec63"

$ curl http://localhost:5000/v1/search
    {"num_results": 1, "query": "", "results": [{"description": "", "name": "mydocker/debian"}]}

Also let’s see if our Redis server is caching the image.

$ redis 127.0.0.1:6379> keys *
 1) "cache_path:/tmp/registryrepositories/mydocker/debian/tag_wheezy"
 2) "cache_path:/registry1images/3192d5ea7137e4f47f4624a5cc7786af2159a44f49511aeed28aa672416cec63/ancestry"
 3) "cache_path:/registry1images/1aeada4477158496dc31ee5c6e7174240140d83fddf94bc57fc02bee1b04e44f/json"
 4) "cache_path:/registryimages/511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158/ancestry"
 5) "diff-worker"
 6) "cache_path:/registry1images/511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158/json"
 7) "cache_path:/registry1repositories/mydocker/debian/_index_images"
 8) "cache_path:/registryimages/511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158/_inprogress"
 9) "cache_path:/registry1images/3192d5ea7137e4f47f4624a5cc7786af2159a44f49511aeed28aa672416cec63/_checksum"
10) "cache_path:/registry1repositories/mydocker/debian/tagwheezy_json"
11) "cache_path:/registryimages/511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158/_checksum"
12) "cache_path:/registry1images/479215127fa7b852902ed734f3a7ac69177c0d4d9446ad3a1648938230c3c8ab/ancestry"
13) "cache_path:/registry1repositories/mydocker/debian/tag_wheezy"
14) "cache_path:/registry1images/1aeada4477158496dc31ee5c6e7174240140d83fddf94bc57fc02bee1b04e44f/ancestry"
15) "cache_path:/registry1images/3192d5ea7137e4f47f4624a5cc7786af2159a44f49511aeed28aa672416cec63/json"
16) "cache_path:/registryrepositories/mydocker/debian/_index_images"
17) "cache_path:/registryimages/511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158/json"
18) "cache_path:/registry1images/511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158/ancestry"
19) "cache_path:/registry1images/479215127fa7b852902ed734f3a7ac69177c0d4d9446ad3a1648938230c3c8ab/_checksum"
20) "cache_path:/registry1images/1aeada4477158496dc31ee5c6e7174240140d83fddf94bc57fc02bee1b04e44f/_checksum"
21) "cache_path:/registry1images/511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158/_checksum"
22) "cache_path:/registry1images/479215127fa7b852902ed734f3a7ac69177c0d4d9446ad3a1648938230c3c8ab/json"

Now for those who want to have a Continous Integration system, we can set up Jenkins to build the autmated images and upload to our Private registry and use Mesos/CoreOS to deploy the image through out our infrastructure in a fully automated fashion.

Standard