Page
Build and run a bootable Flask application disk image in Podman Desktop
Now that you’ve accessed the container registry and have your configuration files, it’s time to create a disk image and set up a virtual machine.
To get the full benefit from taking this lesson, you need:
- A no-cost Red Hat Developer subscription. Register here if you do not already have a subscription.
- Download Podman Desktop for Windows, macOS, or Linux (Fedora or RHEL).
- The configuration files in the
rhel-flask-bootcdirectory from the previous lesson:helloworld.pywsgi.pyflask-app.serviceflask-app.confNginx_connect_flask_sock.tecontainerfile
In this lesson, you will:
- Create a containerfile that will be used for our bootable image
- Create a disk image.
- Build an image from the Containerfile.
- Build a disk image.
- Set up a virtual machine (VM).
Create a Containerfile that will be used for our bootable image
We’re now ready to create a container file that packages up our software as a bootable container. Unlike the Containerfile we previously created in the previous lesson for developing our application, this one will reside in the flask-dev/bootc/ directory.
Starting with the RHEL 10 bootable image, the sample ContainerFile performs the following steps:
- Install the required RPM packages through DNF.
- Copy the files we’ve created into our container from our container directory (
flask-dev/bootc/app). - Use pip to install Gunicorn and Flask modules from the Python community repository.
- Configure NGINX to communicate with Gunicorn.
- Configure SELinux to allow NGINX to communicate with Gunicorn (over UNIX domain sockets).
- Enable and start our application services.
Using the text editor of your choice, create this file and save it locally in the rhel-flask-bootc/ directory where you placed your other files. Later, you will upload this Containerfile to Podman Desktop when you build the image:
# Start with the RHEL 10 bootable base image
FROM registry.redhat.io/rhel10/rhel-bootc
# --- 1. Install System Dependencies ---
# Install necessary packages from RHEL Application Streams using dnf
# This includes default Python 3, pip, and NGINX (which creates the
# 'nginx' user). We also want kernel tuning tools, the SELinux policy
# tools and firewalld
# for host network security.
RUN dnf install -y \
python3 \
python3-pip \
nginx \
tuned \
selinux-policy-devel \
make \
firewalld \
&& dnf clean all
# --- 2. Copy application code and set ownership ---
# Set the working directory and copy the application files.
# The --chown flag ensures all copied files are immediately owned by the
# 'nginx' user, which was created during the nginx package installation.
WORKDIR /app
COPY --chown=nginx:nginx app/helloworld.py /app/
COPY --chown=nginx:nginx app/wsgi.py /app/
COPY app/flask-app.service /etc/systemd/system/
USER root
COPY --chown=nginx:nginx app/flask-app.conf /etc/nginx/conf.d/flask-app.conf
# --- 3. Install Python Dependencies in a Virtual Environment ---
# Switch to the non-root user to create and populate the virtual environment.
# This ensures that the venv is also owned by the correct user.
# Install Flask and Gunicorn via pip
USER nginx
RUN python3 -m venv flask-venv
# Note: The ENV PATH is set for subsequent RUN commands under this USER.
ENV PATH="/app/flask-venv/bin:$PATH"
COPY app/requirements.txt /app
RUN pip install --no-cache-dir -r /app/requirements.txt
# --- 4. Configure SELinux Policy ---
# Switch back to root to make system-level changes.
USER root
# This is the most critical step for bootc images.
# We define the SELinux policy rules here. These rules will persist on the
# final bootable system even if the file labels themselves are reset.
RUN semanage fcontext -a -t httpd_sys_content_t "/app(/.*)?" && \
semanage fcontext -a -t httpd_exec_t "/app/flask-venv/bin(/.*)?"
# --- 5. Create and Install a Custom SELinux Module ---
# This module grants systemd (init_t) permission to read the symbolic links
# in our venv that are labeled as httpd_exec_t.
RUN echo "module gunicorn_init 1.0; \
require { \
type init_t; \
type httpd_exec_t; \
class lnk_file read; \
} \
allow init_t httpd_exec_t:lnk_file read;" > /tmp/gunicorn_init.te && \
cd /tmp && \
make -f /usr/share/selinux/devel/Makefile gunicorn_init.pp && \
semodule -i gunicorn_init.pp
# We're using port 8000 in our example so label this port
# as usuable by for web services.
RUN semanage port -a -t http_port_t -p tcp 8000
# --- 6. Configure system services ---
RUN systemctl enable nginx.service
RUN systemctl enable flask-app.service
# --- 7. Configure Firewall ---
# Use the offline command to open the HTTP port in the firewall for the final
# image.
RUN firewall-offline-cmd --add-port=8000/tcpPull your first disk image
In Lesson 1, we installed the Red Hat Extension Pack, which includes the Bootable Containers extension used for image mode deployments. To pull your first bootable container, follow these steps:
In Podman Desktop, select Bootable Containers from the side menu bar to access the Dashboard section (Figure 1).

Figure 1: Welcome to Bootable Containers dashboard screen. - Within the Bootable Containers section, select Images from the left navigation.
On the Images screen, select the option to pull the example container image from registry.gitlab.com (Figure 2). When you complete this, you will see the example image listed. The file size of the image is over 700MB (compressed) and may take a while to download.

Figure 2: Bootable containers images listing screen with the example image now available.
Build an image from the Containerfile
Next, let’s use the bootc/Containerfile we created above to build an image:
- Open Podman Desktop on your local machine and go to the Images section in the left navigation.
- Select Build to open the Build image from Containerfile screen.
Provide the f
lask-dev/bootc/Containerfilepath,build directory: flask-dev/bootc/,image name: flask-bootc-image, andplatform hardware spec. I chose the Intel and AMD x86_64 image option for my Fedora environment (Figure 3).
Figure 3: The Build image from Containerfile screen in Podman Desktop. Select Build once you have all of the information entered. Observe if any issues or warnings are displayed while building the image. Once you’ve successfully created the image (Figure 4), it will be listed on the Images dashboard (Figure 5).

Figure 4: Successful Containerfile build output in Podman Desktop. 
Figure 5: The container images listing screen with a new entry for the example image.
At this point, our image can run like any other container with Podman. This can be highly beneficial for basic testing and iterating on your application. In the next step, you will install, or write, your container image as a disk image and run it as a Linux system.
Build a disk image
While a traditional application container image is like a self-contained software package that you install onto an existing OS, image mode uses bootc to deliver a complete, bootable OS installation disk, but managed and versioned like a container image. The magic of bootc is that it can install the contents of the container image to disk or file system and provide any format you need to run on virtually any platform. Podman Desktop makes this process simple, and you can target a wide variety of platforms and image types.
To build an image in Podman Desktop:
- Open Podman Desktop on your local machine and go to the Images section from the left navigation. If you just completed the prior steps, you will already be on this screen.
Select the option to Build Disk Image from the ACTIONS kebab (Figure 6).

Figure 6: The Podman Desktop container images screen with the expanded menu under the actions kebab. - Select Build on the Disk Images screen.
Provide the configuration details. Select Output Folder:
flask-dev/bootc/, Disk Image Type: Virtualization Guest Image (qcow2), Filesystem: Default , and Platform: Intel and AMD x86_64 systems (Figure 7).
Figure 7: The completed Build Disk Image configuration. Expand the Interactive build config section towards the bottom of the screen. This is where you will enter your SSH credentials you will need for the next section (Figure 8).

Figure 8: The expanded interactive build config section for building a disk image in Podman Desktop. - Select Build.
Observe if any issues or warnings are displayed while building the disk image. Once you’ve successfully created the image, you will see a success message listed in the Bootable Containers > Disk Images section of Podman Desktop (Figure 9).

Figure 9: A successful disk image build.
Set up a virtual machine
Virtual environments provide a quick and convenient way to test your images. You can test modifications and configurations without impacting your primary operating system or incurring cloud expenditures. Once your image has been validated, and you’re happy with it, we encourage you to create images for all the platforms you’d like to target.
Podman Desktop version 1.8.0 and later makes it easy to launch your built disk image as a virtual machine. After successfully building your disk image, simply select Virtual Machine (Experimental). Before doing so, please ensure you've met the necessary prerequisites, which may include specific hardware or software requirements.
Summary
This learning path has demonstrated how easy it is to add the Red Hat SSO extension to Podman Desktop and access the Red Hat registry to create a Flask-based application container image that is ready to boot and run with image mode. You can easily extend the rudimentary bootable Flask application container you’ve created into a functional application.
As a developer, there are several reasons why you should care about deploying the application in image mode:
- Full stack reproducibility: Image mode allows you to define your app, user space, and the entire OS, ensuring consistency from development to production.
- Simplified OS management: You can now treat OS updates and configurations as image rebuilds, integrating them into your existing container workflows.
- Ideal for appliances and edge: Image mode is perfect for creating specialized software appliances or consistent OS environments for edge devices with tightly coupled OS and application.
- Testing: With image mode it is easy to spin up VMs on your desktop or in the cloud, running the exact OS and application build for testing.
Some next steps you can take to complete your application include:
- Extending the application code beyond the prototype, Hello World.
- Integrating the application with a database front-end, such as SQLLite, MariaDB, MySQL, and PostgreSQL
- Configuring keys and infrastructure to improve the security of the NGINX server component.