Universal Base Images (UBI): Create Your Enterprise-Grade Docker Base Images


Introduction

Universal Base Images (UBIs) are Red Hat’s official container base images, designed to provide a reliable and enterprise-grade foundation for your applications. These images offer a lightweight and secure environment that aligns with Red Hat’s enterprise standards while enabling the flexibility to run anywhere—whether in your on-premises infrastructure, public cloud, or even outside the Red Hat ecosystem. The use of UBIs is especially beneficial for developers who need an image with robust support and guaranteed compatibility with Red Hat ecosystems, yet with the freedom of using the image outside of Red Hat subscriptions.

Why use UBI?
UBIs provide a variety of benefits including:

  • Security and Stability: Being Red Hat-backed, UBIs come with regular updates and security patches.
  • Portability: UBIs allow you to build your containers without needing a Red Hat subscription.
  • Compliance: With UBIs, your base image aligns with enterprise compliance requirements.
  • Easy Integration: Seamlessly integrate with Red Hat’s enterprise-grade products and tools.

This post demonstrates how to create your own base image using UBI 9 with OpenJDK 21 runtime to serve as a solid foundation for Java applications.


Full Example for UBI 9 with OpenJDK 21 Runtime

Here’s a sample Dockerfile that demonstrates how to build a Java application using UBI 9 with OpenJDK 21 runtime:

FROM registry.access.redhat.com/ubi9/openjdk-21-runtime

# Set labels
LABEL name="ubi9-openjdk-21-runtime" \
      vendor="Cihan Cinar" \
      maintainer="[email protected]" \
      description="This is the base image for all Java Applications" \
      version="1.0.0"

# Switch to root user for installation
USER root

# Latest updates
RUN microdnf upgrade -y --refresh --best --nodocs --noplugins --setopt=install_weak_deps=0 && \
    microdnf update -y && rm -rf /var/cache/yum && microdnf clean all

# Switch to non-root user
USER 1001

EXPOSE 8080

ENTRYPOINT [ "sh", "-c", "java ${JAVA_OPTS} -jar /app.jar ${JAVA_ARGS}" ]

Explanation of Dockerfile

  • FROM registry.access.redhat.com/ubi9/openjdk-21-runtime: This line sets the base image to UBI 9 with OpenJDK 21 runtime. This image is pre-configured with Java 21, making it an excellent starting point for Java applications.

  • LABEL: These lines provide metadata about the image. You can customize the labels to include information like the vendor, maintainer, and description of the image.

  • USER root: This switches to the root user for the installation of any necessary packages or updates.

  • microdnf upgrade: This command ensures the base image is up-to-date by upgrading the system’s packages. The --refresh option forces microdnf to refresh its metadata.

  • USER 1001: After performing system updates, the user switches to a non-root user (1001), which is a best practice to avoid running applications with root privileges.

  • EXPOSE 8080: This exposes port 8080 on the container, making it accessible to the outside world when the container is running.

  • ENTRYPOINT: This line defines the command that runs when the container starts. It starts the Java application using the specified JAVA_OPTS and JAVA_ARGS environment variables, making the image flexible and configurable.


Build & Run

Once your Dockerfile is ready, follow these steps to build and run your image.

Build with Docker

To build the image, run the following command in your terminal:

docker build -t your-registry.com/base-images/ubi9-openjdk-21-runtime .

This will build the Docker image based on the Dockerfile in the current directory and tag it as your-registry.com/base-images/ubi9-openjdk-21-runtime.

Check Image Security Report

Before deploying any image, it’s important to check for any security vulnerabilities. Use Docker Scout to generate a CVE report for your image:

docker scout cves your-registry.com/base-images/ubi9-openjdk-21-runtime

This will analyze your image and return a list of known security vulnerabilities associated with it.

Run the Image

Once the image is built, you can run it using the following command:

docker run --rm -it --entrypoint bash your-registry.com/base-images/ubi9-openjdk-21-runtime

This starts the container interactively and allows you to execute commands inside the container, such as testing the application or debugging.


How to Use This Image in a Spring Boot Application

Now that you have a base image, you can easily integrate it into your Spring Boot applications. The Dockerfile for your Spring Boot application could look something like this:

FROM your-registry.com/base-images/ubi9-openjdk-21-runtime

COPY /target/app.jar /app.jar

This Dockerfile uses the ubi9-openjdk-21-runtime image as the base, and then it copies your compiled Spring Boot app.jar file into the container. The result is a clean and secure Spring Boot container image that runs on OpenJDK 21 with the benefits of a Red Hat-backed base image.


Conclusion

By leveraging Red Hat’s Universal Base Images (UBIs), you can create a robust, secure, and portable foundation for your Java applications. Whether you’re building a microservice or a monolithic app, UBIs offer a reliable and compliant environment to run your applications, both on-premises and in the cloud.

With the example provided in this post, you now have the tools to build your own enterprise-grade base images. Remember to regularly update your images, check for security vulnerabilities, and ensure you’re following best practices for running applications in containers.

Happy coding!