Create a Private Docker Registry

By | June 9, 2016
Reading Time: 6 minutes
Nexus-and-Docker

Nexus 3 and Docker – I couldn’t use the Nexus 3 logo, so I drew one myself!

In this article I will show how to set up a private Docker registry with Sonatype’s Nexus Repository Manager 3.0 OSS. There may be other guides to this, but if nothing else I am writing for myself.
The main motivations for me to set up a private Docker registry are:

  • Distribution of Docker images.
    This may be either small-scale between multiple computers or inside an organization.
  • Restrict distribution of Docker images.
    While I prefer to make my Docker images available at DockerHub, there are cases when I feel that the Docker images are not ready for distribution to a larger audience.
    In an organization, it may undesirable or unsuitable to deploy Docker images to a public registry.
  • Use identical versions of Docker images on all my computers.
    If I build a Docker image on first one computer and then, at some later point in time, on another computer there may be differences between the images. This can be caused by updates to the software repositories used when creating the images, patches to the operating system etc. Such differences may be subtle but I prefer to eliminate as many potential sources of confusion, or even errors, that I possibly can.

Since I am already fiddling around with Docker, I will run Nexus 3 OSS in a Docker container using the Docker image from Sonatype.

Preparations

As an example, I will make a copy of the official Tomcat Docker image to my own, private, Docker registry. To do this, we first need to pull the Tomcat image:

docker pull tomcat:latest

In addition I will create a directory in the host to hold Nexus 3 data and logs, as described in the Nexus 3 image’s documentation:

mkdir -p /some/dir/nexus3/data
chown -R 200 /some/dir/nexus3/data

Create a Docker Compose Configuration

In order to simplify start of the Nexus 3 Docker container, I will use Docker Compose.

  • Go to the “nexus3” directory.
    This is the parent directory of the “data” directory that we created as part of the preparations above.
  • Create a file named “docker-compose.yml” with the following content:
nexus:
    image: sonatype/nexus3:latest
    ports:
        - "8081:8081"
        - "8123:8123"
    volumes:
        - ./data:/nexus-data

Note that:

  • Two ports are exposed.
    On port 8081 the web GUI of Nexus 3 will be available. The Docker registry API will be exposed on port 8123. The latter port may be changed as desired, just remember to configure Nexus 3 accordingly.
  • The shared directory “nexus-data”, which is mapped to the host directory “data”.
    This directory will contain the persistent data of Nexus 3.

Launch Nexus

In a terminal window, the Docker Quickstart terminal if you are using Docker Toolbox, with the current directory being the directory with the docker-compose.yml file we created earlier, launch the Nexus 3 Repository manager using this command:

docker-compose up -d

If you are running Docker in Linux, you’ll have to add “sudo” before the above command.
Then use the logs command to view the logs from the Nexus Docker container:

docker-compose logs

After some time, log output similar to this should appear in the Nexus log, indicating that Nexus has successfully started up:

nexus_1 | -------------------------------------------------------------------
nexus_1 |
nexus_1 | Started Sonatype Nexus OSS 3.0.0-03
nexus_1 |
nexus_1 | -------------------------------------------------------------------

Create a Docker Registry in Nexus 3

With Nexus 3 up and running, we should now be able to create a Docker registry.

  • Find the IP address of the Docker host.
    If you are running Docker on Mac OS X or on Windows, it can be obtained using the command “docker-machine ip default”.
    If you are running Docker on Linux, it will be the same IP address as the host, which can be found using the “ifconfig” command.
    In my case, the IP address of the Docker host is 192.168.1.72.
  • Open the URL [Docker host IP address]:8081 in a web browser.
  • Sign in to Nexus 3.
    Click the Sign In button in the upper right corner and use the username “admin” and the password “admin123”. If these credentials have changed, please check the Nexus 3 Docker image page in DockerHub.
  • Click the cogwheel to go to the server administration and configuration section.
  • Click Repositories.
    docker_reg_nexus3_2
  • Click the Create repository button.
    docker_reg_nexus3_3
  • In the list of repository types, select “docker (hosted)” as the type of the new registry.
    docker_reg_nexus3_4
  • Configure the Docker repository.
    Give the repository a name – in my case it is “IvansDockerRepo”.
    Make sure that the Online checkbox is checked.
    Check the HTTP checkbox under Repository Connectors and enter the port number 8123.
    Check the Enable Docker V1 API checkbox.
    Select default under Blob store.
  • Click the button Create repository.
    docker_reg_nexus3_5

The private Docker registry is now ready to be used.

Log in to the Private Docker Registry from the Client

Before we can interact with the Docker registry from a Docker client, we need to log into the registry.

– Allow Unsecure Connections Windows and OS X

Since we have exposed the private Docker registry on a plain HTTP endpoint, we need to configure the Docker daemon(s) that will act as client(s) to the private Docker registry as to allow for unsecure connections. This may not be advisable in all environments, but for the sake of this example unsecure connections are simple and will suffice.

  • Locate the Docker config.json file that contains the key “InsecureRegistry”.
    On Mac OS X and assuming that the name of the Docker machine is “default”, it is located in the directory ~/.docker/machine/machines/default.
    On Windows, again assuming the name of the Docker machine is “default”, it is located in the directory C:\Users\[your user name]\.docker\machine\machines\default.
    The section of the configuration file in which the “InsecureRegistry” key can be found looks like this:

        "HostOptions": {
            "Driver": "",
            "Memory": 0,
            "Disk": 0,
            "EngineOptions": {
                "ArbitraryFlags": [],
                "Dns": null,
                "GraphDir": "",
                "Env": [],
                "Ipv6": false,
                "InsecureRegistry": [],
                "Labels": [],
                "LogLevel": "",
                "StorageDriver": "",
                "SelinuxEnabled": false,
                "TlsVerify": true,
                "RegistryMirror": [],
                "InstallURL": "https://get.docker.com"
            },
  • Insert the IP on which the Nexus 3 GUI is exposed along with the port number 8123 to the value of the key “InsecureRegistry”. In my case, the modified key-value will look like this:
    "InsecureRegistry": [“192.168.1.72:8123”],
  • If you are using the Docker for Mac or Windows Beta:
    New method (make sure you have the latest update): Insecure registries can be configured in the Docker Preferences, in the Advanced tab.
    Old method: Create a file named config.json with this contents (replace the IP address as needed):
    {“storage-driver”:”aufs”,”debug”:true,”insecure-registries”:[“192.168.1.72:8123”]}
    The set the configuration using the commando:
    pinata set daemon @conf.json
  • Restart the Docker machine.

– Allow Unsecure Connections Linux

To allow for unsecure connections from a Docker client running on Linux:

  • Edit the file /etc/default/docker and append the following line:
    DOCKER_OPTS=”$DOCKER_OPTS –insecure-registry=[Nexus3 Docker host IP]:8123″
  • Restart the Docker service using: sudo service docker restart

– Log in to the Private Docker Registry

You should now be able to log in to the Nexus 3 registry using the following command (replace IP address as necessary) using the username “admin” and the password “admin123”, both without quotes:

docker login -u admin -p admin123 192.168.1.72:8123

The result should be a message saying that login succeeded.

Pushing a Docker Image to the Private Registry

Having pulled the official Tomcat image earlier and having logged in to our private registry, we are now ready to push the Tomcat Docker image to our registry. In the instructions below, replace the IP address of the Docker registry as needed.

  • Tag the image.
    docker tag tomcat:latest 192.168.1.72:8123/ivans_tomcat:latest
    This tells Docker the new name that will be used for the Docker image and the IP address of the registry to which we later will push the image.
  • Push the image to our private registry.
    docker push 192.168.1.72:8123/ivans_tomcat:latest
  • Open the URL http://192.168.1.72:8081 in a browser.
  • Click the Components category in the Browse column on the left.
  • Click the Docker registry with the name “IvansDockerRepo” in the list of components that appear.
    docker_reg_nexus3_6
  • In the list of components in IvansDockerRepo, there should be one single entry with the name “ivans_tomcat”.
    docker_reg_nexus3_7
  • To pull the image, perhaps on another computer, use the following commands.
    docker login -u admin -p admin123 192.168.1.72:8123
    docker pull 192.168.1.72:8123/ivans_tomcat:latest

This concludes this article.
Happy coding!

30 thoughts on “Create a Private Docker Registry

  1. Amir

    Thanks for the great article. I am wondering why you didn’t use official docker registry (now they call it distribution) instead nexus? Is there any benefit in using nexus when we only need docker registry and not other codebases provided by nexus (e.g. bower, npm, etc.)?

    Reply
    1. Ivan Krizsan Post author

      The reason for using Nexus is, which is not in the article, that I have been using Nexus as a Maven repository and in this way I can use one and the same repository management solution.
      I haven’t really tried the official Docker registry so I cannot compare it to Nexus.
      Happy coding!

      Reply
  2. Andre

    Next best thing about using Nexus: You can configure the scheduler to free up space from deleted/orphaned images and layers.. Something that the official docker registry cannot do right now.

    On the downside: I couldn’t easily configure Nexus as a caching proxy(which should work in theory, but fails at Nexus’ inability to allow anonymous access to the proxy and Docker’s failure to re-prompt authentication when hitting a 401)…

    Also the API of Nexus 3 leaves quite a few loose ends.. If you’re ok with clicking your configuration, it’s fine.. If you try to make it work with the scripting API, it’s not 🙂

    Reply
  3. tolibin

    i have try your tutorial but i have a little problem with “docker login -u admin -p admin123 my_ip:8123”
    the respons like this 🙁 “Error response from daemon: Get https://my_ip:8123/v1/users/: http: server gave HTTP response to HTTPS client

    Reply
    1. AK

      Hi Ivan,

      I tried connecting via command line to Nexus registry. I had same error – http: server gave HTTP response to HTTPS client.

      sudo docker login -u “admin” -p “admin123” nexus_ip_address:8123

      What could be the issue?
      I use docker version – 18.03.1-ce, build 9ee9f40
      Nexus Repository Manager – OSS 3.0.2-02

      Appreciate your help in this!

      Reply
  4. sivaji

    Is there any reason to go with nexus docker registry instead by default docker provide by docker registry container? Is there any advantages using nexus docker repository ?

    Reply
    1. Ivan Krizsan Post author

      Hello! The question has been asked before, see earlier comments.
      Having had the opportunity to use Nexus 3 a bit more, I cannot say that I am too fond of it.
      As far as a Maven repository is concerned, I liked Nexus 2 better. As far as a Docker registry is concerned, it is very basic, almost crude.
      I will be looking for alternatives when I have time.
      Happy coding!

      Reply
  5. James Patterson

    Hello!
    All seemed to work, including the push and even pull of the container. But when I try to browse my docker repository it says:

    “No components/assets found in repository”

    Note, if I curl from the repository server itself, it shows it:
    curl -X GET http://localhost:5000/v2/_catalog
    {“repositories”:[“ivans_tomcat”,”my-ubuntu”]}

    Any thoughts?

    Reply
    1. Ivan Krizsan Post author

      Is it perhaps a bug in Nexus? Try updating to the latest version. I know some version that we had installed were quite unstable but it has been taken care of in later versions i believe.

      Reply
  6. anoop

    Have you any success with https? nexus docs explains a way for that.
    Its safer and also its a bit cumbersome to –insecure-reg.. for all the clients which pushes.

    Reply
    1. Ivan Krizsan Post author

      Yes, we’ve tried https at the office where we even have a custom DNS name for our repository. It works well and is, as you say, very convenient.

      Reply
      1. Anup

        Hi Ivan
        I am trying https but not succeeded. Can you please guide me the steps in the same way.
        Regards
        Anup yadav

        Reply
  7. Jorge

    Hi.
    I get a connection refused error:
    $ docker login -u admin -p admin123 http://192.168.99.100:5000
    Error response from daemon: Get http://192.168.99.100:5000/v2/: dial tcp 192.168.99.100:5000: getsockopt: connection refused

    I setup a configuration based in this post dzone_com/articles/setting-up-a-docker-private-registry-with-authenti

    Any idea?

    I used 5000 port and it´s working as you can see in the logs:
    2018-02-23 23:08:35,373+0000 INFO [jetty-main-1] *SYSTEM org.eclipse.jetty.server.ServerConnector – Started ServerConnector@1780a1b5{HTTP/1.1,[http/1.1]}{0.0.0.0:8081}
    2018-02-23 23:08:35,382+0000 INFO [jetty-main-1] *SYSTEM org.eclipse.jetty.server.Server – Started @188203ms
    2018-02-23 23:08:35,387+0000 INFO [jetty-main-1] *SYSTEM org.sonatype.nexus.bootstrap.jetty.JettyServer –
    ————————————————-

    Started Sonatype Nexus OSS 3.0.2-02

    ————————————————-
    2018-02-23 23:08:35,443+0000 INFO [jetty-main-1] *SYSTEM org.eclipse.jetty.server.ServerConnector – Started ServerConnector@6ac45b98{HTTP/1.1,[http/1.1]}{0.0.0.0:5000}

    Reply
  8. Reddysekhar

    Hi,
    Thanks for the detailed info.
    i am facing below error after all the setup during the logsin,
    any idea, what could be the issue ?
    -> docker login -u admin -p admin123 IP:7000
    Error response from daemon: Login: Account is not active. Please see the documentation of the registry http://IP:7000/v1/ for instructions how to activate it.

    checked user status in Nexus, it is active and working for UI login

    Reply
  9. Jitendra

    If you are trying to make this work on RHEL 7. x, the error “Error response from daemon: Get http://192.168.99.100:8123/v2/: dial tcp 192.168.99.100:5000: getsockopt: connection refused” will come up eventually unless :

    a. modify the file /lib/systemd/system/docker.service and append –insecure-registries 192.168.99.100:8123
    b. flush daemon and
    c. restart the docker service
    Now, in the status of docker service, you should be able to find the daemon running with the insecure setting. Follow the usual commands to login, push, pull :
    docker login -u admin -p admin123 192.168.99.100:8123/
    docker tag
    docker push

    Reply
  10. Atanu Banerjee

    Hi Ivan / Friends

    This is an excellent article. Could anyone please help how I could define restart policy with docker-compose.yml Ivan mentioned above ?

    Reply
  11. xtone-hari

    I have a problem with the images I have pushed to Nexus 3 repo.

    1) I pulled the images from Harbor repo
    2) Checked the images by running “docker images” command and noted the images id
    3) Tag the images with image_id and release_no
    e.g.: docker tag c502fb61b442 p-nexus-3.development.abc.com:18443/application1:0.6.0
    4) pushed the images to Nexus 3 repo
    e.g.: docker push p-nexus-3.development.abc.com:18443/application1:0.6.0

    All the above steps worked fine. No Problem.

    But when I tagged the images in step3, by mistake I used the wrong image_id for the images.

    On the instance/node where I pulled the images to run the container, the microservice did not start and we found that the image_id is incorrect for respective images.

    I deleted all the images on the laptop and pulled the images again from Harbor, I tried to re-tag the images with the correct image_id and push to Nexus 3. But I got the below message

    docker push p-nexus-3.development.abc.com:18443/application1:0.6.1
    The push refers to repository [p-nexus-3.development.abc.com:18443/application1]
    27f6a910c92d: Layer already exists
    92aefcecb5cb: Layer already exists
    bd46775d45ee: Layer already exists
    21d439503428: Layer already exists
    3f1d62758814: Layer already exists
    129ba078f157: Layer already exists
    8c8f1eccd524: Layer already exists
    68442845474f: Layer already exists
    503e53e365f3: Layer already exists
    0.6.1: digest: sha256:9f86f87241e34d003e1ac7b96df6a4dbab49a77f7556d4acbe905813a3f033b4 size: 2197

    I am really stuck and not sure how to fix this. Could you please help.

    Thank you

    Reply
  12. Simon

    Interesting, I’ve been struggling to make the login part work, I stumbled on your blog post, which was the first to mention docker-compose, and it worked. Other methods such as following the instructions from the nexus image or installing nexus directly on my PC would just give me this error:

    Error response from daemon: Get http://localhost:8123/v2/: dial tcp 127.0.0.1:8123: connect: connection refused

    Any clues why?

    Reply
    1. Ivan Krizsan Post author

      Hello!
      I have completely given up on Nexus as far as a Docker registry is concerned. Instead I would recommend having a look at Harbor.
      Happy coding!

      Reply
  13. Nandlal

    To all whoever are getting “connect: connection refused”
    sudo docker login -u admin -p password 52.3.59.147:8123
    WARNING! Using –password via the CLI is insecure. Use –password-stdin.
    Error response from daemon: Get http://52.3.59.147:8123/v2/: dial tcp 52.3.59.147:8123: connect: connection refused

    Solution : You have to expose the port which you want to use while creating repository as in above example 8123 has been exposed.

    To expose while running container use run with -p 8123:8123

    Hope it will help

    Reply
  14. Navin Prasad

    Hey Ivan Krizsan,
    May I know why did you enable docker v1 API? nexus3 doesn’t support docker v2 API?

    Reply
  15. Augustine

    Hey Ivan,

    Is there any benefit in using nexus for docker registry in terms of cost?

    Reply
    1. Ivan Krizsan Post author

      I will have to answer with the usual: It depends.
      Using a self-hosted Docker registry will allow you to get started with almost no cost but you will need to have the infrastructure on which to run the repository yourself. A hidden cost will be time spent on updating the Docker registry software and other maintenance chores if it is a long-term solution.
      Cloud offerings such as Amazon’s ECR will take the burden of infrastructure and maintenance off your shoulders but you still should invest some time in, for instance, cleaning up old, unused, images.
      If the question only concerns itself with the price tag of Nexus compared to other products, there are better, free, alternatives such as Harbor.
      Hope this answers your question to some extent.

      Reply

Leave a Reply to James Patterson Cancel reply

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