Building Images & Deploying With Foreman

One interesting feature of the Anaconda installer is the ability to apply a “traditional” disk image, rather than install packages. In other words, instead of Anaconda installing packages from repositories, it will fetch a disk image over HTTP and write it to the disk.

I recently decided to give this a shot out of curiosity and I have been very impressed with how easily this process can be handled with Foreman.

There already exists great documentation on how this all works, but I thought the community may find it useful to have a tutorial written that covers a few additional points/challenges I ran into.

Before I dive in, here are the two documents I used to walk through this process for your reference:

My tutorial will pretty much reflect the steps in the above documents and honestly maybe not be as detailed, but it will include just a few extra parts in regards to building a working image that may be helpful to you.

So to begin…

Setup Composer

The first step is to setup the Composer image builder. It is available in the RHEL/CentOS7+ BaseOS and AppStream (if using CentOS8) repositories. I used CentOS8 in this example.

Composer works by using a “blueprint”, which is a list of all packages you want to be in your image. You can use a command-line tool or a Cockpit web UI to manage these blueprints and create images based on them in various formats.

One thing to note, Composer obtains the packages to be installed in your image from the build server’s existing Yum/DNF repositories. In my case, I didn’t need to change anything on my CentOS8 system, but if you are using the Red Hat CDN, following the linked guide above for creating local mirrors to build off of.

  1. Install Composer: yum install lorax-composer composer-cli cockpit-composer
  2. Enable the lorax-composer socket: systemctl enable lorax-composer.socket
  3. Enable the cockpit.socket socket: systemctl enable lorax-composer.socket
  4. Configure the system firewall: firewall-cmd --add-service=cockpit && firewall-cmd --add-service=cockpit --permanent
  5. Start the lorax-composer service: systemctl start lorax-composer
  6. Start the cockpit service: systemctl start cockpit
  7. Access cockpit at: https://<composer-server>:9090
  8. Authenticate using your system credentials and navigate to “ImageBuilder” on the left-side pane.

Build Image

Now that you have Composer setup, you can begin to craft a blueprint and create an image based on said blueprint.

You can have a ball adding whatever you like to your image, but it has been my experience that there are a few critical packages that must be installed in order for the CentOS Anaconda installation process to complete and for the OS to be booted post-provisioning.

  1. In the “ImageBuilder” section of Composer, select “Create Image”. Give your image a name.
  2. On the left-hand pane, you can search for packages you’d like to add to your image. Adding a package will also add all of its dependencies, which will be reflected on the right-hand pane.
  3. Add the below packages. I will explain why each is needed below:
    • grub2-common, grub2-pc, grub2-tools-extra - The CentOS setup would fail to install GRUB2 to the MBR without these.
    • authselect - The CentOS setup process would fail without this.
    • lvm2 - If using LVM, you will need this for booting the OS. Otherwise, once GRUB2 loads the kernel and initramfs, it will be unable to find your volumes.
  4. I would also would strongly recommend you add the below packages for a more functioning system:
    • dnf
    • iputils
    • iproute
    • NetworkManager
    • openssh-server
    • sudo
  5. There may be other very important packages, but these worked for me. Add anything else you’d like to be in your image and select “Commit” to commit your changes.
  6. Now select “Create Image” and select an “Image Type” from the drop down menu. I’ve been building simple TAR archives with much success.
  7. To view your image build process and see previous versions, go back to “Blueprints”, select your image and then the “Images” tab. Wait for the image to complete its build.

Setup Foreman

Now you should have your image. The last setup step now is to configure Foreman to instruct the CentOS installer (Anaconda) to deploy your image, rather than install packages.

  1. Download your image from Composer.
  2. In Foreman, create a product (or use an existing one) and create a “File” repository inside of it. Ensure that you are exporting this repository via HTTP.
  3. Upload your file to the new repository.
  4. Navigate to the repository’s exported URL and copy the full path to the image in your repository.
  5. You now will need to create a new parameter which points to this URL. I’d imagine you could do this in any level which supports parameters (subnet, OS, host group). I went with a host group.
  6. Create a new parameter titled kickstart_liveimg of type “string” and paste the full URL path to your image.
  7. Now you can attempt to build a host with Foreman! Any systems that are in build mode that have the kickstart_liveimg parameter should apply your image!

I believe that sums it all up. I’m by no means an expert on this stuff, but I hope it helps someone out there!


Hey @fresh-pie

This is really great, thank you.
I will add your tutorial to the newsletter and see about getting the second part with the Foreman steps added to our docs also!


Thanks, this is great. I’d like to grab to opportunity to talk about this feature because I believe image-based provisioning is very relevant these days, it’s fast and it can be used both for bare-metal and VMs. With Katello content capabilities, this is ideal workflow that can leverage the strengths Katello brings to the table:

  • Content synchronization.
  • Lifecycle environments and content views.
  • Decentralization (syncing to smart proxies).
  • Multi-tenency, RBAC and audit.

Correct me if I am wrong, but for better user experience there are two major gaps we need to solve:

Getting content into Katello/Pulp

Currently this is fully manual step, it can be automated via hammer easily but still user needs to do this. I am assuming that Composer exposes the final image on a URL, if there was a way to specify the upstream url for an image just like an upstream repository for packages, this would allow to use Katello/Pulp sync feature to get bits in with all the goodies (sync plan, UI/CLI, audit).

Integration with provisioning template

Currently, it’s up to the user to make sure that the kickstart_liveimg URL is correctly set, but if Katello was able to determine content type and provide the URL itself, this could be put into provisioning template automatically.

Triggering image rebuilds

The final missing bit is ability to trigger image build in Composer via a schedule or via an event. I am currently working on Foreman Webhooks plugin and this could be an ideal task (e.g. when new content is synced into Library). Another solution could be to use Remote Execution. Building images could be done on a Smart Proxy via a new feature.

I think this all is worth exploring, most of the work is outside of my knowledge domain tho but I would love to cooperate on this feature some day @Marek_Hulan @Justin_Sherrill @Partha_Aji