# How-To Deploy a Private Docker Registry on Google Cloud With Sonatype Nexus Repository

**January 08, 2019**  
By Mohamed Labouardy

5 minute read time

In this post, I will walk you through how to deploy [Sonatype Nexus Repository](/content/products/sonatype-nexus-repository/index.html) on Google Cloud Platform, and how to create a private Docker hosted repository to store your Docker images and other build artifacts (Maven, npm and PyPI, etc.). To achieve this, we need to bake our machine image using Packer to create a gold image with Nexus preinstalled and configured. Terraform will be used to deploy a Google compute instance based on the baked image. The following schema describes the build workflow:

PS: All the templates used in this tutorial can be found on my [GitHub](https://github.com/mlabouardy/terraform-gcp-labs).

To get started, we need to create the machine image to be used with Google Compute Engine (GCE). Packer will create a temporary instance based on the CentOS image and use a shell script to provision the instance:

This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
[Learn more about bidirectional Unicode characters](https://github.co/hiddenchars)

[Show hidden characters](/content/blog/deploy-private-docker-registry-on-google-cloud-platform-with-nexus/index.html)

|     |     |
| --- | --- |
|  | { |
|  | "variables" : { |
|  | "zone" : "YOUR ZONE", |
|  | "project" : "YOUR PROJECT ID", |
|  | "source_image" : "centos-7-v20181210", |
|  | "ssh_username" : "packer", |
|  | "credentials_path" : "PATH/account.json" |
|  | }, |
|  | "builders" : \[ |
|  | { |
|  | "type": "googlecompute", |
|  | "account_file": "{{user \`credentials_path\`}}", |
|  | "project_id": "{{user \`project\`}}", |
|  | "source_image": "{{user \`source_image\`}}", |
|  | "ssh_username": "{{user \`ssh_username\`}}", |
|  | "zone": "{{user \`zone\`}}", |
|  | "image_name" : "nexus-v3-14-0-04" |
|  | } |
|  | \], |
|  | "provisioners" : \[ |
|  | { |
|  | "type" : "file", |
|  | "source" : "./nexus.rc", |
|  | "destination" : "/tmp/nexus.rc" |
|  | }, |
|  | { |
|  | "type" : "file", |
|  | "source" : "./repository.json", |
|  | "destination" : "/tmp/repository.json" |
|  | }, |
|  | { |
|  | "type" : "shell", |
|  | "script" : "./setup.sh", |
|  | "execute_command" : "sudo -E -S sh '{{ .Path }}'" |
|  | } |
|  | \] |
|  | } |

[view raw](https://gist.github.com/mlabouardy/67a76b6959020c1ef9de564bb6f7d505/raw/32f246319975dc5b001f276d13ac8e65ab438d7e/template.json) [template.json](https://gist.github.com/mlabouardy/67a76b6959020c1ef9de564bb6f7d505#file-template-json)
hosted with ❤ by [GitHub](https://github.com/)

The shell script will install the latest stable version of Nexus OSS (now known as [Sonatype Nexus Repository Community Edition](/content/products/nexus-community-edition-download/index.html)) based on [official documentation](https://help.sonatype.com/repomanager2/installing-and-running/installing) and wait for the service to be up and running. Then it will use the Scripting API to post a groovy script:

[Show hidden characters](/content/blog/deploy-private-docker-registry-on-google-cloud-platform-with-nexus/index.html)

|     |     |
| --- | --- |
|  | #!/bin/bash |
|  |  |
|  | NEXUS_USERNAME="admin" |
|  | NEXUS_PASSWORD="admin123" |
|  |  |
|  | echo"Install Java JDK 8" |
|  | yum update -y |
|  | yum install -y java-1.8.0-openjdk wget |
|  |  |
|  | echo"Install Nexus OSS" |
|  | mkdir /opt/nexus |
|  | cd /opt/nexus |
|  | wget https://download.sonatype.com/nexus/3/latest-unix.tar.gz |
|  | tar -xvf latest-unix.tar.gz |
|  | rm latest-unix.tar.gz |
|  | mv nexus-3.14.0-04 nexus |
|  | useradd nexus |
|  | chown -R nexus:nexus /opt/nexus/ |
|  | ln -s /opt/nexus/nexus/bin/nexus /etc/init.d/nexus |
|  | cd /etc/init.d |
|  | chkconfig --add nexus |
|  | chkconfig --levels 345 nexus on |
|  | mv /tmp/nexus.rc /opt/nexus/nexus/bin/nexus.rc |
|  | service nexus restart |
|  |  |
|  | until$(curl --output /dev/null --silent --head --fail http://localhost:8081);do |
|  | printf'.' |
|  | sleep 2 |
|  | done |
|  |  |
|  |  |
|  | echo"Upload Groovy Script" |
|  | curl -v -X POST -u $NEXUS_USERNAME:$NEXUS_PASSWORD --header "Content-Type: application/json"'http://localhost:8081/service/rest/v1/script' -d @/tmp/repository.json |
|  |  |
|  | echo"Execute it" |
|  | curl -v -X POST -u $NEXUS_USERNAME:$NEXUS_PASSWORD --header "Content-Type: text/plain"'http://localhost:8081/service/rest/v1/script/docker-repository/run' |

[view raw](https://gist.github.com/mlabouardy/c4edff9687cde1491e34a1bbc8d29b59/raw/a8af46c43e4032bfc90fba2543d72607fb2d60e4/setup.sh) [setup.sh](https://gist.github.com/mlabouardy/c4edff9687cde1491e34a1bbc8d29b59#file-setup-sh)
hosted with ❤ by [GitHub](https://github.com/)

The script will create a Docker private registry listening on port 5000:

[Show hidden characters](/content/blog/deploy-private-docker-registry-on-google-cloud-platform-with-nexus/index.html)

|     |     |
| --- | --- |
|  | importorg.sonatype.nexus.blobstore.api.BlobStoreManager; |
|  | importorg.sonatype.nexus.repository.storage.WritePolicy; |
|  |  |
|  | repository.createDockerHosted('mlabouardy', 5000, 443, BlobStoreManager.DEFAULT_BLOBSTORE_NAME, true, true, WritePolicy.ALLOW) |

[view raw](https://gist.github.com/mlabouardy/4f7925ff7906e90fc25aff6078b8d204/raw/4bc61d0bad9ca580bcca37d63b99864619abf028/repository.groovy) [repository.groovy](https://gist.github.com/mlabouardy/4f7925ff7906e90fc25aff6078b8d204#file-repository-groovy)
hosted with ❤ by [GitHub](https://github.com/)

Once the template files are defined, issue packer build command to bake our machine image:

If you head back to **Images** section from **Compute Engine** dashboard, a new image called Nexus should be created:

Now that we are ready to deploy Nexus, we will create a Nexus server based on the machine image we baked with Packer. The template file is self-explanatory, it creates a set of firewall rules to allow inbound traffic on port 8081 (Nexus GUI) and 22 (SSH) from anywhere, and creates a Google compute instance based on the Nexus image:

[Show hidden characters](/content/blog/deploy-private-docker-registry-on-google-cloud-platform-with-nexus/index.html)

|     |     |
| --- | --- |
|  | provider"google" { |
|  | credentials="${file("${var.credentials}")}" |
|  | project="${var.project}" |
|  | region="${var.region}" |
|  | } |
|  |  |
|  | resource"google_compute_firewall""nexus" { |
|  | name="nexus-firewall" |
|  | network="${google_compute_network.nexus.name}" |
|  |  |
|  | allow { |
|  | protocol="tcp" |
|  | ports=["22", "8081"] |
|  | } |
|  |  |
|  | source_ranges=["0.0.0.0/0"] |
|  | } |
|  |  |
|  | resource"google_compute_network""nexus" { |
|  | name="nexus-network" |
|  | } |
|  |  |
|  | resource"google_compute_instance""nexus" { |
|  | name="nexus" |
|  | machine_type="${var.instance_type}" |
|  | zone="${var.zone}" |
|  |  |
|  | boot_disk { |
|  | initialize_params { |
|  | image="${var.image_name}" |
|  | size=100 |
|  | } |
|  | } |
|  |  |
|  | metadata { |
|  | sshKeys="${var.ssh_user}:${file(var.ssh_pub_key_file)}" |
|  | } |
|  |  |
|  | network_interface { |
|  | network="${google_compute_network.nexus.name}" |
|  | access_config={} |
|  | } |
|  | } |

[view raw](https://gist.github.com/mlabouardy/a496ff0e389b3d38e73985ade0e38991/raw/71c5f6b126747b397ae3221c7b21a24d474dd8d8/main.tf) [main.tf](https://gist.github.com/mlabouardy/a496ff0e389b3d38e73985ade0e38991#file-main-tf)
hosted with ❤ by [GitHub](https://github.com/)

On the terminal, run the terraform init command to download and install the Google provider, shown as follows:

Create an execution plan (dry run) with the terraform plan command. It shows you things that will be created in advance, which is good for debugging and ensuring you're not doing anything wrong, as shown in the next screenshot:

When you're ready, apply the changes by issuing Terraform apply:

Terraform will create the needed resources and display the public IP address of the Nexus instance on the output section. Jump back to GCP Console, your Nexus instance should be created:

If you point your favorite browser to http://instance_ip:8081, you should see the Sonatype Nexus Repository interface:

Click the " **Sign in"** button in the upper right corner, and use the username " **admin"** and the password " **admin123**." Then, click on the cogwheel to go to the server administration and configuration section. Navigate to " **Repositories**," our private Docker repository should be created as follows:

The docker repository is published as expected on port 5000:

Hence, we need to allow inbound traffic on that port, so update the firewall rules accordingly:

[Show hidden characters](/content/blog/deploy-private-docker-registry-on-google-cloud-platform-with-nexus/index.html)

|     |     |
| --- | --- |
|  | resource"google_compute_firewall""nexus" { |
|  | name="nexus-firewall" |
|  | network="${google_compute_network.nexus.name}" |
|  |  |
|  | allow { |
|  | protocol="tcp" |
|  | ports=["22", "8081", "5000"] |
|  | } |
|  |  |
|  | source_ranges=["0.0.0.0/0"] |
|  | } |
|  |  |
|  | resource"google_compute_network""nexus" { |
|  | name="nexus-network" |
|  | } |

[view raw](https://gist.github.com/mlabouardy/d05beceba953474984670523aea10088/raw/9b1ae59685640efdfa046e36837b406017eb0fa5/network.tf) [network.tf](https://gist.github.com/mlabouardy/d05beceba953474984670523aea10088#file-network-tf)
hosted with ❤ by [GitHub](https://github.com/)

Issue Terraform apply command to apply the changes:

Your private docker registry is ready to work at instance_ip:5000, let's test it by pushing a docker image.

Since we have exposed the private Docker registry on a plain HTTP endpoint, we need to configure the Docker daemon that acts as client to the private Docker registry to allow for insecure connections.

_On Windows or Mac OS X_: Click on the **Docker icon** in the tray to open **Preferences**. Click on the Daemon tab and add the IP address on which the Nexus GUI is exposed, along with the port number 5000 in **Insecure registries** section. Don't forget to **Apply & Restart** for the changes to take effect, and you're ready to go.

_Other OS_: Follow the [official guide](https://docs.docker.com/registry/insecure/).

You should now log in to your private Docker registry using the following command:

And push your docker images to the registry with the docker push command:

If you head back to Nexus Dashboard, your docker image should be stored with the latest tag:

Written by **Mohamed Labouardy**  
Mohamed is Software Engineer/DevOps at InterCloud. Interested in AWS, Docker, Android, Go & ChatOps. A contributor to numerous open-source projects including Telegraf, DialogFlow, Docker ... He is currently writing a book on Serverless architecture in AWS, blogs at labouardy.com. You can reach him on Twitter @mlabouardy

Tags

Nexus OSSDockerNexus RepositoryNexus 3.0docker cloudPackergoogle cloud platformTerraformProduct
