Preconfigured Nexus Repository Manager (NXRM) Docker container

TL;DR: Link To Project @ GitHub - unfor19/nexus-ops

Recently, I've been looking for a way to avoid hitting DockerHub rate limits. One of the solutions that I came up with was deploying Nexus Repository Manager OSS (NXRM) as part of my CI/CD environment, so the CI/CD runners hit NXRM instead of DockerHub when attempting to pull public Docker images.

As always, I Googled a lot on how to get started with NXRM, and it seemed like it's best just to run it locally and see how it goes.

Ladies and gents, I give you my hands-on experience with provisioning a preconfigured NXRM Docker container.

The Goal

NXRM Docker container that is preconfigured with DockerHub and AWS ECR Public Gallery. Here's what I found in Google:

My Issue With Existing Solutions

I want to run the init-script immediately when NXRM is ready and part of the NXRM startup. I don't want to execute any script manually on my machine; everything should be done as part of NXRM's startup process. Most existing solutions describe running something on your machine that will communicate with NXRM; I'm looking for something different.

Desired Outcome

Let's break it into a few bullet points that will describe the desired output.

  • The init-script is readable and easy to maintain.
  • Restarting the NXRM container should be idempotent; the init-script should not attempt to create existing resources.
  • The init-script should be written in a popular scripting language, like Bash (so I chose Bash).
  • Automated actions should be done using NXRM REST API, to support adding more features easily. Since I chose Bash, I'm using curl to make HTTP requests.

Designing The Init Script

The desired outcome is clear; now, I need to declare the actions that the init-script will perform when starting the NXRM container. Here's the list of actions (in order):

  1. Changes the initial random password that is in /nexus-data/admin.password to admin
  2. Enables anonymous access - allows anonymous users to access localhost:8081 with READ permissions
  3. Adds Docker Bearer Token Realm - allows anonymous pulls from local Nexus registry localhost:8081
  4. Creates two Docker repository of type proxy
    1. docker-hub - DockerHub
    2. docker-ecrpublic - AWS ECR Public
  5. Creates a Docker repository of type group
    1. docker-group - The above Docker repositories are members of this Docker group

Creating A Custom Docker Image

I've created a Docker image based on NXRM official Docker image.

Here's is how the Dockerfile looks like:


ARG NEXUS_VERSION="3.30.1"

FROM sonatype/nexus3:${NEXUS_VERSION} as app
USER root
RUN curl -L -o /usr/local/bin/jq https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64 && \
    chmod +x /usr/local/bin/jq

USER nexus
ENV NEXUS_DATA_PATH="/nexus-data" \
    NEXUS_ADMIN_USERNAME="admin" \
    NEXUS_ADMIN_PASSWORD="admin" \
    NEXUS_API_PATH="service/rest/v1" \
    NEXUS_BASE_PATH="http://localhost:8081" \
    NEXUS_OPS_VERBOSE="false"
WORKDIR /"${NEXUS_DATA_PATH}/nexus-ops/"
COPY provision/ .
CMD /nexus-data/nexus-ops/entrypoint.sh

Note: I added jq to the mix because I intend to use more APIs, and I'll need to analyze some JSON data. I find it best to analyze JSON data with jq when using Bash.

As you can see from the Dockerfile above, I'm copying the directory provision/ to the NXRM image, and instead of running /opt/sonatype/start-nexus-repository-manager.sh as the CMD, I wrapped it with the provision/entrypoint.sh script.

Bottom line, the whole logic is maintained in the init-script called entrypoint.sh.

Here's how the main function looks like

main(){
    start_nexus
    set_global_variables
    wait_for_healthy_response
    set_credentials
    change_initial_password
    enable_anonymous_access
    realms_enable_docker_token
    repositories_create_repository_wrapper "proxy" "docker-hub" "${_NEXUS_OPS_PATH}/repositories/docker-proxy-dockerhub.json"
    repositories_create_repository_wrapper "proxy" "docker-ecrpublic" "${_NEXUS_OPS_PATH}/repositories/docker-proxy-ecrpublic.json"
    repositories_create_repository_wrapper "group" "docker-group" "${_NEXUS_OPS_PATH}/repositories/docker-group.json"
    log_msg "Finished executing - ${_NEXUS_OPS_PATH}/entrypoint.sh"
}

Final Result

Here's my project @ GitHub - unfor19/nexus-ops. To understand how it all works, check the provision/entrypoint.sh file; I tried to make it as neat as possible.

One more thing; you'll find the directory provision/repositories in my project. That directory contains the JSON structure of the provisioned repositories. As an example, here's the command for creating the DockerHub repository

repositories_create_repository_wrapper "proxy" "docker-hub" "${_NEXUS_OPS_PATH}/repositories/docker-proxy-dockerhub.json"

Final Words

Initially, I was slightly intimidated by NXRM; it seemed complex to proxy Docker requests via NXRM. However, after creating this project, I think I got the idea, and I hope you did too.