A couple of days ago, I needed to setup Logz.io’s first internal Maven repository. We’re a youngish company in the field of Log Analysis and haven’t needed a Maven repository so far. We rely heavily on open source technologies but the need to fork and patch these technologies arises all too often.
Until the merge takes place, the code’s artifacts need to be hosted somewhere accessible to the build system — internal Maven Repository to the rescue.
Open Source Repository Choices
When trying open source products, especially in Startups, you have a very low threshold of patience for things not working. I think open source products must invest in the onboarding user experience as much as possible.
I am aware of two open source products: Artifactory by JFrog and Nexus Repository Manager by Sonatype. I leaned to Artifactory since I remember it being more feature rich, and being used by many popular open source products.
In this article I describe a case study of how I failed to install Artifactory using Docker following their official guide and compared that 3 min installation of Nexus.
Chapter 1: Artifactory Installation
I searched for “Installing Artifactory using Docker” and got to this official guide.
First thing I created a couple of directories they advised as highly recommended to mount:
mkdir -p /var/artifactory/data mkdir /var/artifactory/logs mkdir /var/artifactory/backup mkdir /var/artifactory/etc
I then continued to run the Docker image:
docker run — name artifactory -p 80:8081 -e “ARTIFACTORY_HOME=/var/opt/jfrog/artifactory” -v /var/artifactory/data:/var/opt/jfrog/artifactory/data -v /var/artifactory/logs:/var/opt/jfrog/artifactory/logs -v /var/artifactory/backup:/var/opt/jfrog/artifactory/backup -v /var/artifactory/etc:/var/opt/jfrog/artifactory/etc jfrog-docker-reg2.bintray.io/jfrog/artifactory-oss:latest
I got this first error message:
Unable to find image ‘jfrog-docker-reg2.bintray.io/jfrog/artifactory-oss:latest’ locally latest: Pulling from jfrog/artifactory-oss a2c33fe967de: Pull complete b527c153b530: Pull complete 63f70f5a23b8: Pull complete 333ee72b10ae: Pull complete 3297c49bbe77: Pull complete e2f19b824bda: Pull complete e907a4f03f92: Pull complete 25981fad9a81: Pull complete 37226b35a736: Pull complete 2d90bd8d7cb9: Pull complete ac1fc7130559: Pull complete 4f43cce3cb41: Pull complete Digest: sha256:d8f0022b19a3f88a01565d970a0cc0d72e851700f6eded920388c016bc1d25dc Status: Downloaded newer image for jfrog-docker-reg2.bintray.io/jfrog/artifactory-oss:latest nginx: unrecognized service grep: /var/opt/jfrog/artifactory/etc/default: No such file or directory
** ERROR: Artifactory pid destination ARTIFACTORY_PID was not set in /etc/opt/jfrog/artifactory/default ! Please add it!
- I don’t understand why NGINX is an unrecognized service
- The script tried to grep a file named default in /var/opt/jfrog/artifactory/etc — the directory I was told to mount and failed. It makes sense it failed since the directory is empty.
The main error is that ARTIFACTORY_PID is missing. At first I was sure I was missing an environment variable in my run command. I googled the error and found a “How can I use own located folders as volumes in docker artifactory container?” StackOverflow question, which explained that inside the Docker container there are files inside the etc folder which get overriden due to the volume of the etc folder. They suggested a fix to run Docker with the command /bin/bash, copy the contents of the folder to my host etc folder, and then continue. That was way too much work for me.
I settled by removing the mount of etc folder and continued. I ran the command again without that mount and got:
nginx: unrecognized service /usr/bin/java Starting Artifactory tomcat as user artifactory… Max number of open files: 524288 Using ARTIFACTORY_HOME: /var/opt/jfrog/artifactory Using ARTIFACTORY_PID: /var/opt/jfrog/run/artifactory.pid Creating directory /var/opt/jfrog/artifactory/logs/catalina mkdir: cannot create directory `/var/opt/jfrog/artifactory/logs/catalina’: Permission denied Creating directory /var/opt/jfrog/artifactory/temp Creating directory /var/opt/jfrog/artifactory/work touch: cannot touch `/opt/jfrog/artifactory/tomcat/logs/catalina.out’: No such file or directory /opt/jfrog/artifactory/tomcat/bin/catalina.sh: line 401: /opt/jfrog/artifactory/tomcat/logs/catalina.out: No such file or directory
** ERROR: Artifactory Tomcat server did not start. Please check the logs
I checked permissions on those directories. I was running as root, and the directories had write access as root — which was the same user I used when I was running the Docker Artifactory image.
I Googled some more to learn about how Docker treats permissions and about this problem in Artifactory and saw that they run their Tomcat application as “artifactory” user, which may be the reason why they can’t write to this directory.
It didn’t make sense to me to change access to a user which doesn’t exists on the host, only by using its internal Unix user id (only residing inside the Docker image). I discarded the idea of giving write access to ALL, which doesn’t sound very secure to me.
At this point, after spending roughly an hour, I gave up and tried a second option: Nexus.
Chapter 2: Sonatype Nexus Repository Manager
Sonatype Nexus Repository Manager is a product I’ve worked with for many years dating back to 2009 when I was working at Cotendo, and also in my time at Akamai. I was very pleased with it, so I tried to use it again.
I got to this installation article. I immediately gave them bonus points for being completely open source about it — a GitHub repo with its Dockerfile and a very good readme. What I love about it is that you can take that Dockerfile and create your own version with your config very easily.
Compare this with Artifactory:
- You can’t find their Dockerfile (Try googling “artifactory docker dockerfile”)
- Their installation guide is inside a wiki which doesn’t allow commenting, so people end up improving this doc using StackOverflow, as opposed to comments or just Pull Request / Issues on the repo hosting the Dockerfile
I ran the following command to create a volume container hosting the persisted files, per the guide suggestion:
docker run -d — name nexus-data sonatype/nexus echo “data-only container for nexus”
Next I ran the Nexus image:
docker run -d -p 80:8081 — name nexus — volumes-from nexus-data sonatype/nexus
Boom! I’m done! 3 minutes and I happily surf to their admin page.
Sonatype did some great work with the UX of installing their open source product using Docker. Artifactory has some way to go to achieve this. Here are suggestions to them:
- Put your Dockerfile as a Git repository
- Open the installation guide to comments or place it as README.MD in the git repo
- Fix all the problems — make it truly 3 minutes installation for first time users.
Originally published by Asaf Mesika.