Containing Artifactory with Red Hat UBI

Making your container smaller doesn’t always make it a good fit. It has to use and work with the components your organization requires as well.

Artifactory is available for DevOps as a highly configurable, distroless image that offers many benefits, including reduced size and less potential for OS-level vulnerabilities. For some, this is not enough and the need for a specific OS or custom image is an organizational requirement. This is often the case when organizations that rely on Red Hat Enterprise Linux switch from legacy VMs to containerized platforms but still want to maintain the security, reliability, and support provided by their Red Hat subscription. 

We’ll show you how easy it is to create your very own Artifactory Docker images based on the Red Hat Universal Base Image (UBI) and why you may want to do it.

Update: If you want a ready-made image, a Red Hat UBI and Artifactory Pro Docker image is available for download from the Red Hat Container Catalog. If you need a Docker image that contains specific versions and/or additional components, follow the procedures shown here.

Why Red Hat Docker images?

The world is becoming containerized as the need for scalable software rises and software architectures adopt the microservices approach. Docker images are an attractive path forward toward containerization but they bring with them many of the issues of older technologies, such as OS vulnerabilities, untested software packages, etc. The same reasons organizations choose Red Hat with their existing platforms still apply in the containerized world.

The Red Hat Universal Base Image was designed specifically to ease the transition to containerized software capable of running on Red Hat Enterprise Linux. It’s not just for paid subscribers either; Red Hat UBI can be used by software producers under OSS license as well. 

Artifactory on Red Hat UBI

Creating a container image with Red Hat UBI and Artifactory is done through a Dockerfile. We’ll show you what that needs to look like, and explain why.

Before you start

To create your Red Hat UBI-based Artifactory image, you will need the following:

  1. Docker client 17.05 and above (we use 18.09.2)
  2. Internet access

You will also want to know what versions of the different products you want to use, specifically:

  1. The Artifactory version. We use 6.10.6, but you may use any version from 6.9.1 and above.
  2. The Artifactory edition. We use PRO, but you can choose OSS or CE instead
  3. The Red Hat UBI version. We use UBI8, which is based on RHEL 8. The version you choose must be ubi7 or ubi8 based.

Dockerfile best practice

The full example is provided below, but let’s go into more detail as to what each section is doing.

FROM docker.bintray.io/jfrog/artifactory-pro:6.10.6 AS base

This first section specifies the Artifactory Docker image and version we are basing this new image off of. You can change the version (tag) and edition to suit your needs. 

FROM registry.access.redhat.com/ubi8

This section specifies the Red Hat UBI version and sets the OS for our image. You can change the specific version of UBI here. You will notice this is the second FROM in our Dockerfile. We are making use of Docker’s multi-stage build feature.

# Environment needed for Artifactory
ENV ARTIFACTORY_USER_NAME=artifactory \
    ARTIFACTORY_USER_ID=1030 \
    ARTIFACTORY_HOME=/opt/jfrog/artifactory \
    ARTIFACTORY_DATA=/var/opt/jfrog/artifactory \
    ARTIFACTORY_EXTRA_CONF=/artifactory_extra_conf \
    RECOMMENDED_MAX_OPEN_FILES=32000 \
    MIN_MAX_OPEN_FILES=10000 \
    JAVA_HOME=/java/jdk-11.0.2+9 \
    RECOMMENDED_MAX_OPEN_PROCESSES=1024

# Copy needed file system from base (Artifactory image)
COPY --from=base /opt/jfrog /opt/jfrog
COPY --from=base /var/opt/jfrog/artifactory /var/opt/jfrog/artifactory
COPY --from=base /artifactory_extra_conf /artifactory_extra_conf
COPY --from=base /entrypoint-artifactory.sh /entrypoint-artifactory.sh
COPY --from=base /java /java
COPY --from=base /tmp/plugins /tmp/plugins

Here, we prepare the image and copy over the Artifactory application and configuration files. Please note that this imports the Java binaries but this is also customizable.  

RUN useradd -M -s /usr/sbin/nologin \
  --uid ${ARTIFACTORY_USER_ID} \
  --user-group ${ARTIFACTORY_USER_NAME} && \
    chown -R ${ARTIFACTORY_USER_NAME}:${ARTIFACTORY_USER_NAME} ${ARTIFACTORY_HOME} ${ARTIFACTORY_EXTRA_CONF} ${ARTIFACTORY_DATA} /tmp/plugins && \
    yum install -y --disableplugin=subscription-manager wget

USER $ARTIFACTORY_USER_NAME

VOLUME ${ARTIFACTORY_DATA}
VOLUME ${ARTIFACTORY_EXTRA_CONF}

ENTRYPOINT ["/entrypoint-artifactory.sh"]

This final section sets permissions, volumes and the entry point. There is a command where we make use of the Red Hat package manager to install a required tool. Note that we use the package manager with --disableplugin=subscription-manager, this is to avoid a warning when running on a machine without an active subscription. 

Full example

# An example of customizing Artifactory using Red Hat Universal Base Image (UBI).
# Using Docker multi-stage build.
# Taking the Artifactory file system (including Java for Linux x64)

# The Artifactory official Docker image
FROM docker.bintray.io/jfrog/artifactory-pro:6.10.6 AS base

# The new image based on registry.access.redhat.com/ubi
FROM registry.access.redhat.com/ubi8

# Environment needed for Artifactory
ENV ARTIFACTORY_USER_NAME=artifactory \
    ARTIFACTORY_USER_ID=1030 \
    ARTIFACTORY_HOME=/opt/jfrog/artifactory \
    ARTIFACTORY_DATA=/var/opt/jfrog/artifactory \
    ARTIFACTORY_EXTRA_CONF=/artifactory_extra_conf \
    RECOMMENDED_MAX_OPEN_FILES=32000 \
    MIN_MAX_OPEN_FILES=10000 \
    JAVA_HOME=/java/jdk-11.0.2+9 \
    RECOMMENDED_MAX_OPEN_PROCESSES=1024

# Copy needed file system from base (Artifactory image)
COPY --from=base /opt/jfrog /opt/jfrog
COPY --from=base /var/opt/jfrog/artifactory /var/opt/jfrog/artifactory
COPY --from=base /artifactory_extra_conf /artifactory_extra_conf
COPY --from=base /entrypoint-artifactory.sh /entrypoint-artifactory.sh
COPY --from=base /java /java
COPY --from=base /tmp/plugins /tmp/plugins

# Create the user, fix file system ownership and install needed tools with Yum
# NOTE - wget must be installed for Artifactory HA
RUN useradd -M -s /usr/sbin/nologin \
  --uid ${ARTIFACTORY_USER_ID} \
  --user-group ${ARTIFACTORY_USER_NAME} && \
    chown -R ${ARTIFACTORY_USER_NAME}:${ARTIFACTORY_USER_NAME} ${ARTIFACTORY_HOME} ${ARTIFACTORY_EXTRA_CONF} ${ARTIFACTORY_DATA} /tmp/plugins && \
    yum install -y --disableplugin=subscription-manager wget

USER $ARTIFACTORY_USER_NAME

VOLUME ${ARTIFACTORY_DATA}
VOLUME ${ARTIFACTORY_EXTRA_CONF}

ENTRYPOINT ["/entrypoint-artifactory.sh"]

Building the image

Now that you understand the different sections of the Dockerfile, it is time to build it. 

  1. Copy the full example into a file named Dockerfile in an empty directory. You should update the version of Artifactory to your desired version.
  2. From the command line, cd into the directory with the file
  3. From the command line, run docker build -t mynamespace/jfrog/artifactory-pro:6.10.6-ubiChange the name to something that makes sense to you.

That’s it, you are now ready to run your Artifactory image on Red Hat UBI!

What’s next?

Now that you have your image, you will need somewhere to store it and deploy it from. May we suggest Artifactory as your docker registry

You will also need a way of building new versions and securing external dependencies, Artifactory can help with both of these thanks to its build integrations and caching capabilities

When you’re finished, an automated build will kick off with every new version of Artifactory that JFrog publishes and your build will publish the new version of your custom image to your Artifactory registry. This will help you keep all of the components updated and secured on your very own Artifactory image.

That’s all it takes to create and maintain a compact, containerized version of Artifactory running with Red Hat’s proven platform.