Docker registry first steps

Here at Octo, we are fond of Docker. Not because we completely master it, but because we don’t (yet). And as DevOps-minded guys, we like new perspectives in Dev / Ops relationship. Docker is mainly about this, shifting each other’s expectation. Now that the 0.7 and 0.8 releases are out, its production readiness has never been closer and it’s getting pretty exciting.

In a previous article, we’ve answered a few questions allowing to understand the basic concepts of Dockers, let’s play around with few Docker command lines and manage a local repository (also called registry).



Docker is a new approach in application packaging and deployment in many ways. Some quite disturbing paradigms are therefore considered:

  • Ops don’t have to care about how the containers are built neither do they have to care about what they are made of. They just have to consider them as application-level (almost) black boxes which are simply connected to each other. Docker containers are usually made of everything needed to run over a LXC-aware Linux kernel (libC, middleware, application). They are often based on a regular distribution (CentOS, ubuntu, Debian…).
  • Container images are built once (usually by dev guys) and reused as-is everywhere, from development workstation to production envs, with no modification at all.
  • Prefer the «rebuild/redeploy» pattern rather than «upgrade» when deploying new application version. Upgrades simply consist of shutting down the former container and start a new one in its place.
  • Rely on registries to store and version container images.


Registries are a major component in Docker ecosystem. They are used at different stages of the application lifecycle:

  • Dev guys use the public registry as some kind of github to easily get ready-to-use containers with application stacks (Java, PHP, Rails…) deployed
  • Ops guys might contribute to those middleware-ready containers by applying internal security and deployent patterns, if needed.
  • Dev guys uses their local Docker instance and internal Docker registries as Git with origins: (think commit, tag, pull, push) to produce ready-to-deploy applications.
  • Ops guys rely on internal Docker registries as a Nexus platform: download a container based on a given version number and deploy it. Container upgrades however only download the missing commits, not all the new container.

Some examples by practice

All the following commands must be run on a LXC-aware Linux, physical or virtual, with Docker freshly install. You can follow the Ubuntu installation procedure to perform such install, it’s pretty straight forward.

Let’s start a local registry. It can itself run within a Docker container of course to ease its deployment. Let’s use the container proposed on’s registry and expose its TCP/5000 port on the host:

$ docker run -d -p=5000:5000 stackbrew/registry:latest

Now let’s create a local copy of the standard ubuntu container image:

$ docker pull ubuntu:latest

If we have a look at the local images by running:

$ docker images
REPOSITORY           TAG                 IMAGE ID            CREATED             SIZE
stackbrew/registry   latest              3321c2caa0cf        3 weeks ago         472.2 MB (virtual 3 GB)
ubuntu               latest              8dbd9e392a96        8 months ago        128 MB (virtual 128 MB)

We can see that 2 container images are locally known.

Let’s tag the ubuntu:latest to prepare it to be pushed on the local registry. Tagging is a way to give a more understandable name to a container image, but also a way to push them on a remote registry, private or public.

$ docker tag 8dbd9e392a96
$ docker images
REPOSITORY              TAG                 IMAGE ID            CREATED             SIZE
stackbrew/registry      latest              3321c2caa0cf        3 weeks ago         472.2 MB (virtual 3 GB)
ubuntu                  latest              8dbd9e392a96        8 months ago        128 MB (virtual 128 MB)   latest              8dbd9e392a96        8 months ago        128 MB (virtual 128 MB)

ubuntu:latest has the same IMAGE ID as the one freshly tagged onto our new registry, looks good. Let’s push it on our local regsitry, listening on the TCP/5000 port. By uploading this image, we make it available to any other Docker host around.

$ docker push
The push refers to a repository [] (len: 1)
Sending image list
Pushing repository (1 tags)
Pushing 8dbd9e392a964056420e5d58ca5cc376ef18e2de93b5cc90e868a1bbc8318c1c
Pushing tags for rev [8dbd9e392a964056420e5d58ca5cc376ef18e2de93b5cc90e868a1bbc8318c1c] on {}

Now let’s start our own new docker container by creating the following Dockerfile:


# tweak ubuntu's initctl
RUN dpkg-divert --local --rename --add /sbin/initctl
RUN ln -s /bin/true /sbin/initctl

RUN apt-get install -y memcached

EXPOSE 11211
CMD    ["/"]
USER daemon

You might have noticed that we added a file which content might look like:


exec memcached

It’s very trivial at this stage and could have been totally written into the CMD Dockerfile statement. Let’s keep it that way for further improvements.

We can now build our brand new container image:

$ docker build -t .

Once the container image has been built, we don’t need the Dockerfile anymore, except if we want to re-build the image later on or on another docker host. The local Docker agent keep tracks of this local image. It’s therefore possible to have a look at the full tree of Docker images using a docker images --tree:

└─8dbd9e392a96 Size: 128 MB (virtual 128 MB) Tags: ubuntu:latest,
  └─b5f46a480005 Size: 155.8 kB (virtual 128.2 MB)
    └─86f4d2bdda8b Size: 16 B (virtual 128.2 MB)
      └─55bc3a7d11cb Size: 50.99 MB (virtual 179.2 MB)
        └─d60079a9c49b Size: 28 B (virtual 179.2 MB)
          └─34d94e18df44 Size: 178.4 MB (virtual 357.6 MB)
            └─43f04dd23753 Size: 178.4 MB (virtual 535.9 MB)
              └─4fd5c706f3a8 Size: 178.4 MB (virtual 714.3 MB) Tags:

You can see that several patches (for instance, filesystem content changes due to RUN or ADD statements in the Dockerfile, container configuration change by ENV, CMD or USER) have been applied on top of the standard ubuntu:latest image to produce the final memcached one.

Docker history command details the patches that have been applied. They represent each non-comment line of the Dockerfile. Be aware that the oldest change is at the bottom of the stack, as in some kind of git log output.

docker history
IMAGE               CREATED             CREATED BY                                      SIZE
4fd5c706f3a8        6 seconds ago       /bin/sh -c #(nop) USER daemon                   178.4 MB
43f04dd23753        8 seconds ago       /bin/sh -c #(nop) CMD [/]           178.4 MB
34d94e18df44        9 seconds ago       /bin/sh -c #(nop) EXPOSE [11211]                178.4 MB
d60079a9c49b        11 seconds ago      /bin/sh -c #(nop) ADD in /         28 B
55bc3a7d11cb        13 seconds ago      /bin/sh -c apt-get install -y memcached         50.99 MB
86f4d2bdda8b        28 seconds ago      /bin/sh -c ln -s /bin/true /sbin/initctl        16 B
b5f46a480005        29 seconds ago      /bin/sh -c dpkg-divert --local --rename --add   155.8 kB
8dbd9e392a96        9 months ago                                                        128 MB

Now, it’s time to push it on the local registry and run it:

$ docker push
$ docker run -d -p 11211:11211

A truncated output of a ps afx might give you something like:

/usr/bin/docker -d
 \_ lxc-start -n 84273abb1fcf73e6b538893c1b703a9c9e5911d36c1ba876e82db06d30f25259 -f /var/lib/docker/containers/84273abb1fcf73e6b538893c1b703a9c9e5911d36c1ba876e82db06d30f25259
 |   \_ /bin/sh -c cd /docker-registry && ./ && ./
 |       \_ /bin/bash ./
 |           \_ /usr/bin/python /usr/local/bin/gunicorn --access-logfile - --debug --max-requests 100 --graceful-timeout 3600 -t 3600 -k gevent -b -w 4 wsgi:applic
 |               \_ /usr/bin/python /usr/local/bin/gunicorn --access-logfile - --debug --max-requests 100 --graceful-timeout 3600 -t 3600 -k gevent -b -w 4 wsgi:ap
 |               \_ /usr/bin/python /usr/local/bin/gunicorn --access-logfile - --debug --max-requests 100 --graceful-timeout 3600 -t 3600 -k gevent -b -w 4 wsgi:ap
 |               \_ /usr/bin/python /usr/local/bin/gunicorn --access-logfile - --debug --max-requests 100 --graceful-timeout 3600 -t 3600 -k gevent -b -w 4 wsgi:ap
 |               \_ /usr/bin/python /usr/local/bin/gunicorn --access-logfile - --debug --max-requests 100 --graceful-timeout 3600 -t 3600 -k gevent -b -w 4 wsgi:ap
 \_ lxc-start -n 621385033517cdc180d4f66c7f4687216602a070178fee15976caff2c325a924 -f /var/lib/docker/containers/621385033517cdc180d4f66c7f4687216602a070178fee15976caff2c325a924
     \_ memcached

Two Docker containers are running, the first is the registry (which, as you can see, happens to be using gunicorn) and the second one, only runs a single memcached process. It’s now possible to simply use the memcached service:

$ telnet 11211
Connected to
Escape character is '^]'.
VERSION 1.4.13
Connection closed by foreign host.

Now what?

We just saw how to basically play with Docker containers and a local repository. The actions we performed can be summarized like this.


Note that we didn’t get into details with the Docker save and load commands which are backup / restore features from / to a local tar archive.
We didn’t either explicitely use the commit statement, which is used each time docker build applies a line from a Dockerfile and save it as a new image version.

In the next article, we will discuss about the configuration of Docker containers. Stay tuned!


2 commentaires sur “Docker registry first steps”

  • Nice Info Shared!I would like to add: Use of the registry, without the index, which is under the full control of Docker, is best suited for storing images on private networks. The registry spins up in a special mode which restricts communication with the Docker index. All security and authentication needs to be taken care of by the user
  • Can we have the steps for the following scenario, 1. Private Docker registry creation on rhel. 2. Storing the docker container image on private registry. 3. Setup Websphere Application Server on the docker container 4. Export the docker container to other environments; Import docker container Thanks.
    1. Leave a Reply

      Your email address will not be published. Required fields are marked *

      This form is protected by Google Recaptcha