Create physically bound images by using system roles

You can use system roles to create physically bound images to detect the non-booted environment and adjust their behaviour. The images must not, for example, try to start systemd units or talk to network services; instead, they must defer all of that to the first boot.

Before you begin

  • You have prepared the control node and the managed nodes.
  • You are logged in to the control node as a user who can run playbooks on the managed nodes.
  • The account you use to connect to the managed nodes has sudo permissions for these nodes.
  • You are logged in to the control node as a user who can run playbooks on the managed nodes.

Procedure

  1. Create a playbook file, for example ./setup.yml, with the following content:
    ---
    - name: Configure physically bound images with RHEL system roles
      hosts: all
      vars:
        podman_registries_conf:
          unqualified-search-registries:
            - "registry.access.redhat.com"
            - "docker.io"
            - "my-company-registry.com"
          registry:
            - location: "my-company-registry.com"
            - location: "my-local-registry:5000"
              insecure: true
        podman_quadlet_specs:
          - file_src: my-quadlet.container
            state: started
      tasks:
          - name: Run the podman role
            include_role:
              name: redhat.rhel_system_roles.podman

    The Podman system role in the Ansible Playbook configures the system with registries and a quadlet application.

  2. Validate the playbook syntax:
    $ ansible-playbook --syntax-check ./setup.yml

    This command only validates the syntax and does not protect against a wrong but valid configuration.

  3. Create a quadlet.container file to configures the container application, for example:
    [Install]
    WantedBy=default.target
    
    [Container]
    Image=quay.io/my_org/my_image:20260326
    ContainerName=my-quadlet
  4. Create a Containerfile file with the following content:
    FROM quay.io/centos-bootc/centos-bootc:stream10
    RUN dnf -y install ansible-core rhel-system-roles
    COPY ./setup.yml .
    COPY ./quadlet.container .
    RUN ansible-playbook -c local setup.yml

    You perform every action inside the image build, running the playbooks against localhost. You can use a multi-stage build to keep Ansible and the roles out of your final image. Because this process is entirely self-contained, it works well in your automatic container build pipelines.

    Note

    The images must be copied over before any container or service (for example, Quadlet) depending on such an image is started.

  5. Build the bootc image, for example:
    $ podman build -t quay.io/<namespace>/<image>:<tag> .