Skip to main content
Redhat Developers  Logo
  • Products

    Featured

    • Red Hat Enterprise Linux
      Red Hat Enterprise Linux Icon
    • Red Hat OpenShift AI
      Red Hat OpenShift AI
    • Red Hat Enterprise Linux AI
      Linux icon inside of a brain
    • Image mode for Red Hat Enterprise Linux
      RHEL image mode
    • Red Hat OpenShift
      Openshift icon
    • Red Hat Ansible Automation Platform
      Ansible icon
    • Red Hat Developer Hub
      Developer Hub
    • View All Red Hat Products
    • Linux

      • Red Hat Enterprise Linux
      • Image mode for Red Hat Enterprise Linux
      • Red Hat Universal Base Images (UBI)
    • Java runtimes & frameworks

      • JBoss Enterprise Application Platform
      • Red Hat build of OpenJDK
    • Kubernetes

      • Red Hat OpenShift
      • Microsoft Azure Red Hat OpenShift
      • Red Hat OpenShift Virtualization
      • Red Hat OpenShift Lightspeed
    • Integration & App Connectivity

      • Red Hat Build of Apache Camel
      • Red Hat Service Interconnect
      • Red Hat Connectivity Link
    • AI/ML

      • Red Hat OpenShift AI
      • Red Hat Enterprise Linux AI
    • Automation

      • Red Hat Ansible Automation Platform
      • Red Hat Ansible Lightspeed
    • Developer tools

      • Red Hat Trusted Software Supply Chain
      • Podman Desktop
      • Red Hat OpenShift Dev Spaces
    • Developer Sandbox

      Developer Sandbox
      Try Red Hat products and technologies without setup or configuration fees for 30 days with this shared Openshift and Kubernetes cluster.
    • Try at no cost
  • Technologies

    Featured

    • AI/ML
      AI/ML Icon
    • Linux
      Linux Icon
    • Kubernetes
      Cloud icon
    • Automation
      Automation Icon showing arrows moving in a circle around a gear
    • View All Technologies
    • Programming Languages & Frameworks

      • Java
      • Python
      • JavaScript
    • System Design & Architecture

      • Red Hat architecture and design patterns
      • Microservices
      • Event-Driven Architecture
      • Databases
    • Developer Productivity

      • Developer productivity
      • Developer Tools
      • GitOps
    • Secure Development & Architectures

      • Security
      • Secure coding
    • Platform Engineering

      • DevOps
      • DevSecOps
      • Ansible automation for applications and services
    • Automated Data Processing

      • AI/ML
      • Data Science
      • Apache Kafka on Kubernetes
      • View All Technologies
    • Start exploring in the Developer Sandbox for free

      sandbox graphic
      Try Red Hat's products and technologies without setup or configuration.
    • Try at no cost
  • Learn

    Featured

    • Kubernetes & Cloud Native
      Openshift icon
    • Linux
      Rhel icon
    • Automation
      Ansible cloud icon
    • Java
      Java icon
    • AI/ML
      AI/ML Icon
    • View All Learning Resources

    E-Books

    • GitOps Cookbook
    • Podman in Action
    • Kubernetes Operators
    • The Path to GitOps
    • View All E-books

    Cheat Sheets

    • Linux Commands
    • Bash Commands
    • Git
    • systemd Commands
    • View All Cheat Sheets

    Documentation

    • API Catalog
    • Product Documentation
    • Legacy Documentation
    • Red Hat Learning

      Learning image
      Boost your technical skills to expert-level with the help of interactive lessons offered by various Red Hat Learning programs.
    • Explore Red Hat Learning
  • Developer Sandbox

    Developer Sandbox

    • Access Red Hat’s products and technologies without setup or configuration, and start developing quicker than ever before with our new, no-cost sandbox environments.
    • Explore Developer Sandbox

    Featured Developer Sandbox activities

    • Get started with your Developer Sandbox
    • OpenShift virtualization and application modernization using the Developer Sandbox
    • Explore all Developer Sandbox activities

    Ready to start developing apps?

    • Try at no cost
  • Blog
  • Events
  • Videos

The journey to enable UBI with the Paketo Buildpacks ecosystem

March 17, 2025
Ozzy Osborne Michael Dawson
Related topics:
Developer ToolsJavaNode.jsOpen sourceProgramming languages & frameworksQuarkusRuntimes
Related products:
Red Hat build of Node.jsRed Hat build of OpenJDKRed Hat build of QuarkusRed Hat Enterprise LinuxRHEL UBI

Share:

    With the growth in the use of containers, the need to bundle your application into a container has never been stronger. Many Red Hat customers will be familiar with Source-to-Image (S2I) as an easy way to build container images from application source code. While S2I is a convenient way to build images on Red Hat OpenShift, Red Hat works to support our customers when using a variety of approaches, and we’ve recently seen an increasing interest in building applications using Cloud Native Computing Foundation (CNCF) Buildpacks.  

    With the growth in the use of containers, the need to bundle your application into a container has never been stronger. Many Red Hat customers will be familiar with Source-to-Image (S2I) as an easy way to build container images from application source code. While S2I is a convenient way to build images on Red Hat OpenShift, Red Hat works to support our customers when using a variety of approaches, and we’ve recently seen an increasing interest in building applications using Cloud Native Computing Foundation (CNCF) Buildpacks.  This blog post covers the journey to enable UBI with the Paketo buildpacks ecosystem
     

    This is the third in a 5-part series of articles on building your applications with CNCF  Buildpacks and UBI. The series will include:

    • Building applications with Paketo Buildpacks and Red Hat UBI container images 
    • Running applications with Paketo Buildpacks and Red Hat UBI container images in OpenShift.
    • The journey to enable UBI with the Paketo Buildpacks ecosystem (this post).
    • Building applications with UBI and Paketo Buildpacks in CI/CD

    A Little History..

    Buildpacks have fast become an interesting technology to build cloud applications, with the idea originally being credited to Heroku as far back as 2011. However it wasn’t until 2018 that Heroku & Pivotal created the CNCF Project that represents the approach known as “CNCF Buildpacks” today. As envisaged, buildpacks provided a modular mechanism to allow a way for application developers to delegate the act of building their application to a set of buildpacks. 

    This approach allows for a separation of buildpack authors and application authors, where buildpack authors can focus on the challenges of correctly building and packaging the application to best run in a container, freeing the application developer from caring about Dockerfiles, or similar tooling. 

    Buildpacks are not alone in offering a solution that aids developers in this manner, there are a variety of other tools that have similar goals, including S2I, Jib and the late Appsody project. Buildpacks however represent a modular approach to the problem, allowing for builder images that can cope with multiple runtimes and application types, prioritizing keeping the business logic small and relevant to each part of the solution. 

    By 2020, buildpacks were gaining in popularity, and came to the attention of Red Hat. Internally various teams independently started looking into how to provide a Builder image that could work for their scenario, and various small prototypes were created.

    This blog post covers some of the history of how those early prototypes led to the contribution of a UBI based stack to Paketo, and how the first Paketo UBI builder image came to be.

    Where do your runtimes come from?

    Within Red Hat, there are dedicated teams that look after runtimes such as Java and Node.js. They spend countless hours building, testing and patching the runtimes to ensure they work as expected when running in RHEL/UBI. They then package them for distribution as rpms. 

    When we began looking at adding UBI support to buildpacks we hit an early snag. Buildpacks would not allow rpm distributed runtimes to be installed from a buildpack. While you could create a builder image for each runtime and version, this would quickly lead to an unmaintainable forest of builders. In addition, the forest of builders would shift the responsibility to the user to select the appropriate builder image for each and every project. That in turn would negate one of the main advantages of buildpacks, having a single builder that figures out what to do based on the project being built.

    Another alternative would have been to create a single builder/run image pair with every runtime (at every version) pre-installed, and then use configuration to enable the correct one at runtime. Unfortunately, it’s not difficult to see that the resulting image would be too large to be generally acceptable. It would also need to be updated every time any version of any runtime had an update, resulting in an update frequency which would be onerous for users to manage.

    Why no rpms?

    Why didn’t we just use a buildpack to install rpms? This would have offered a nice solution, except it went against the goals of the CNCF Buildpack project.

    Buildpacks in 2020 had a goal of not allowing modifications to the builder, or run images. The intent was that buildpacks would limit all modifications to the images to directories under a single path, and that the system would receive no modifications. This allows for ‘rebasing’, a feature of buildpack built application containers that allows buildpacks to switch out the image underneath an application with an updated one, allowing for easy security updates to already built application images.

    If buildpacks were allowed to modify the builder/run images, it could break rebasing. Taking UBI as an example, if the run image was based on the UBI minimal image and a buildpack installed Java, then after the rebase operation Java would be missing, and the application would fail to function. 

    What then?

    The buildpacks community were not unaware of this limitation and in 2020 were looking at a solution that would allow special buildpacks to manipulate the stack, and then those actions would be replayed during a rebase operation. These ‘stackpacks’ would have to be packaged with the application into the run image, but there still could be occasions when the replay would fail. Stackpacks didn’t get much past the early discussion phase, and were quickly superseded by another suggestion.

    The suggested alternative would allow ‘extensions’ to direct modification to the builder and run images via generated Dockerfiles. (Indeed for a while, this was known as ‘the dockerfile rfc’ within the buildpacks community). Since the Dockerfiles would be allowed to run instructions with higher privileges, this allowed for the installation of rpms. The rebasing concern was addressed, by allowing the extension to either disable the capability, or set which layers would be retained. Additionally extensions could opt to ‘switch’ the run image to an entirely different one, rather than extending a base run image.

    With this capability, an extension could use rpm to install a runtime during the build, and then switch the run image to an appropriate one that had the runtime already installed. Conveniently there are a whole set of these runtime images already published for UBI! By using these existing run images, we are able to take advantage of the significant testing that has already been performed against them.

    Why Paketo?

    Although the addition of extensions to buildpacks was a game changer for rpm installed runtimes, having an extension that could install Node, or Java, is only a tiny part of building and packaging an application in a container. After the runtime is available, there still remains the tasks of performing the build itself, using whatever build system the project is using, and arranging and selecting the runtime components from the built application. Additionally, there may be other components blended after build to provide cloud functionality, or to update security via custom certificates etc.

    Thankfully, Paketo have been doing this a while, and have a mature buildpacks ecosystem consisting of many buildpacks that can harmoniously co-exist within builder images. Even better, by 2021, Paketo had a roadmap goal of adding a UBI based stack. 

    The choice became clear, to assist Paketo in delivering a UBI based stack, that would use extensions to supply the runtimes. 

    How Paketo?

    A buildpack build is a coordination of one or more buildpacks that have opted to participate in the building of the current application project. The buildpacks can coordinate via a feature of buildpacks called the ‘build plan’, this allows buildpacks to state that they ‘provide’ or ‘require’ things, eg. it allows the maven buildpack to ‘require’ java, and the java buildpack to ‘provide’ it. 

    That’s a pretty simple example, but it also means that multiple buildpacks could claim to ‘provide’ something, and before actually providing the thing, each buildpack checks the plan to see if the thing is still “in-plan” (if it is still required), once any buildpack has provided a thing, the thing will no longer be in the plan, and subsequent buildpacks can observe this and act appropriately. 

    Paketo is a whole ecosystem of buildpacks that have a shared understanding and vocabulary around the entries in the buildplan. This allows the buildpacks to act as replaceable modules within a build, where it doesn’t matter which buildpack provides something, as long as any buildpack provides it, under the right build plan entry, the build will succeed.

    If it were possible for buildpacks to use rpms, we could just add a UBI-Runtime buildpack to Paketo, and it would install the appropriate version of the appropriate runtime, and claim it ‘provided’ the appropriate thing to the buildplan. This would then allow the rest of Paketo to proceed as if the UBI Runtime were any other Paketo supplied runtime, and complete the build. Because of the image modification restrictions with buildpacks, we can’t do this with a buildpack, however, thanks to the new image extension specification, an extension can! 

    We created extensions (Node.js, Java) that were able to install Java & NodeJS runtimes via their rpm packages, while appearing to Paketo in the same manner as existing buildpacks that did those tasks. The UBI Builder image includes these new extensions, and builds performed with it will use runtimes from the UBI 8 package repository due to the use of the newly introduced ubi-base-stack.

    Much of the work to enable this was not in the creation of the extensions themselves, but in the upgrading of Paketo tooling, and libraries to understand the new extensions specification. This presented significant challenges, not only from a technical perspective of the code itself, but also from a Go ecosystem perspective, related to Go and Paketo version handling. 

    To create the UBI Builder image required updates to many contributing projects, and much cooperation with the Paketo community. Red Hat continues to work with Paketo, being particularly involved in the Java and Node.js sub teams.

    What's next?

    Being part of the Paketo community means being aware of the goals, and trying to adopt those for the UBI Builder. Multi-arch support is slowly rolling out, and Java recently updated its default version. We hope to reflect these within the UBI stack as soon as possible along with Red Hat Specific additions like support for UBI 9.

    We hope you found this article interesting and that we have motivated you to try out the new Paketo UBI Builder Image. In the follow-up posts we will provide more detail on running applications with Paketo Buildpacks in OpenShift, using buildpacks in CI/CD, and using CNCF Buildpacks with Quarkus.

     

     

    Last updated: March 19, 2025
    Disclaimer: Please note the content in this blog post has not been thoroughly reviewed by the Red Hat Developer editorial team. Any opinions expressed in this post are the author's own and do not necessarily reflect the policies or positions of Red Hat.

    Recent Posts

    • Integrate vLLM inference on macOS/iOS with Llama Stack APIs

    • Optimize model serving at the edge with RawDeployment mode

    • Introducing Red Hat build of Cryostat 4.0

    • How we improved AI inference on macOS Podman containers

    • How OpenShift Virtualization supports VM live migration

    Red Hat Developers logo LinkedIn YouTube Twitter Facebook

    Products

    • Red Hat Enterprise Linux
    • Red Hat OpenShift
    • Red Hat Ansible Automation Platform

    Build

    • Developer Sandbox
    • Developer Tools
    • Interactive Tutorials
    • API Catalog

    Quicklinks

    • Learning Resources
    • E-books
    • Cheat Sheets
    • Blog
    • Events
    • Newsletter

    Communicate

    • About us
    • Contact sales
    • Find a partner
    • Report a website issue
    • Site Status Dashboard
    • Report a security problem

    RED HAT DEVELOPER

    Build here. Go anywhere.

    We serve the builders. The problem solvers who create careers with code.

    Join us if you’re a developer, software engineer, web designer, front-end designer, UX designer, computer scientist, architect, tester, product manager, project manager or team lead.

    Sign me up

    Red Hat legal and privacy links

    • About Red Hat
    • Jobs
    • Events
    • Locations
    • Contact Red Hat
    • Red Hat Blog
    • Inclusion at Red Hat
    • Cool Stuff Store
    • Red Hat Summit

    Red Hat legal and privacy links

    • Privacy statement
    • Terms of use
    • All policies and guidelines
    • Digital accessibility

    Report a website issue