Lab Guide: Creating an Execution Environment with ansible-builder

A guide to automating the creation and customization of containerized execution environments using the ansible-builder utility and the integrated Visual Studio Code environment.

Learning objectives

After completing this module, you will be able to:

  • Define an execution environment using execution-environment.yml

  • Package a collection with ansible-galaxy collection build

  • Use ansible-builder create to inspect the generated Containerfile

  • Build and tag a custom execution environment image

  • Test the execution environment with podman and ansible-navigator

Lab briefing

In previous challenges, you authored, tested, and validated your custom Ansible collection.

This final deployment step requires packaging all content (collections, Python dependencies, and system requirements) into a repeatable, version-controlled Execution Environment (EE) container image using ansible-builder.

This exercise focuses on using the Ansible VS Code extension and Ansible Builder 3 features to efficiently define and build a custom EE directly from the VS Code environment.

Enhanced developer experience

ansible-builder is part of the comprehensive Ansible Development Tools (ADT) suite.

The Ansible VS Code extension is actively providing an Enhanced VS Code integration that simplifies interaction with these tools.

Although new features in the roadmap are coming to simplify the EE building experience, specially for operators and deploying in production, this exercise covers the development and testing.

Lab guide: Hands-on tasks

We will define an Execution Environment configuration file by using the Ansible extension wizard in VS Code, then use ansible-galaxy to package our collection, ansible-builder create to inspect the generated Containerfile, and finally ansible-builder build for building the custom EE image, and finish by testing it using Podman (the default container runtime).

Task 1: Define the Execution Environment definition file

The EE configuration is defined in execution-environment.yml. To access the features of modern Ansible tooling, we must explicitly declare version: 3 in the definition file.

  1. Create the Execution environment project in VS Code:

    Open the Ansible extension in the VS Code sidebar and click the Execution environment project option under the "INITIALIZE" menu.

    EE wizard creator in VS Code
  2. Fill out the Execution environment project details. Use the following information:

    • Destination path:

      /home/rhel/myansibleproject
    • Base image: Select the registry.redhat.io option from the dropdown to use the Red Hat supported image.

      This will require to be logged in to the registry before building the image. For the lab this is not required.
    • Additional collections:

      mynamespace.mycollection
    • Additional python packages:

      cowsay
    • Tag:

      mycollection-ee
    • Leave all the other fields as they are

    • Click the blue Build button. You might need to scroll down to find it.

      Creating an EE project
  3. Open the execution-environment.yml file:

    In the VS Code file explorer view, look for and open the newly created file named execution-environment.yml. It should be in the root of the myansibleproject.

  4. Check the EE blueprint content:

    This configuration defines the base image, includes the collection dependencies (as an alternative to pull requirements from requirements.txt and requirements.yml), and explicitly adds the system dependency (cowsay) needed for your custom module. The file should look like the one below:

    ---
    version: 3
    images:
      base_image:
        name: registry.redhat.io/ansible-automation-platform-25/ee-minimal-rhel8:latest
    dependencies:
      ansible_core:
        package_pip: ansible-core
      ansible_runner:
        package_pip: ansible-runner
      galaxy:
        collections:
          - name: mynamespace.mycollection
      python:
        - cowsay
    options:
      tags:
        - mycollection-ee
      package_manager_path: /usr/bin/microdnf
    microdnf requirement

    Because the base image (ee-minimal-rhel8:latest) is built on Universal Base Image (UBI) minimal, which uses microdnf, you must specify package_manager_path: /usr/bin/microdnf in the options section for the build to succeed.

  5. Let’s customize the EE blueprint content:

    We will be making two modifications to the created file, as we are building an EE to test our local developed collection, we need to specify to ansible-builder we will be working with a local tarball, as our collection is not yet available in Ansible Galaxy or Ansible Automation Platform’s (AAP) Automation Hub.

    First we will add a section called additional_build_files, where we will input the source (src) file of the collection and the destination (dest) for the build context

    Second we will modify the collection: section to point to the tarball path, instead of just the collection name, and indicate this by using type: file so ansible-galaxy uses the local file and avoids we copied to the build context in the previous step.

    ---
    version: 3
    images:
      base_image:
        name: registry.redhat.io/ansible-automation-platform-25/ee-minimal-rhel8:latest
    
    dependencies:
      ansible_core:
        package_pip: ansible-core
      ansible_runner:
        package_pip: ansible-runner
      galaxy:
        collections:
          # 2. Tell Galaxy to look inside the local folder we created below
          - name: collection_tarballs/mynamespace-mycollection-1.0.0.tar.gz
            type: file
      python:
        - cowsay
    
    # 1. Copy the file into a dedicated folder named 'collection_tarballs'
    additional_build_files:
      - src: mynamespace-mycollection-1.0.0.tar.gz
        dest: collection_tarballs
    
    options:
      tags:
        - mycollection-ee
      package_manager_path: /usr/bin/microdnf
  6. Save the file:

    Save the execution-environment.yml file.

  7. Make sure you are in mycollection directory:

    Ensure your VS Code terminal is operating in the directory containing your newly created execution-environment.yml

    cd /home/rhel/myansibleproject/collections/ansible_collections/mynamespace/mycollection
  8. Run the ansible-galaxy command in the VS Code Terminal:

    Before we move on to build our Execution Environment, we need to package our collection and clean it of unneeded development files. We will be using ansible-galaxy and ade for this. Before we package the collection in a tarball we will disable the ade editable environment (note the dot at the end for the path).

    ade install .

    Run the following commands in the active terminal to generate the collection tarball.

    ansible-galaxy collection build --output-path /home/rhel/myansibleproject/

    Let’s re-enable ade editable mode now:

    ade install -e .

Task 2: Review the generated Containerfile (dry run)

Before executing the full build, we can use the ansible-builder create command to generate the Containerfile and build context directory (context/). This is helpful for debugging the build steps without spending time on the full image assembly.

  1. Make sure you are in the myansibleproject directory:

    Ensure your VS Code terminal is operating in the directory containing your newly created execution-environment.yml

    cd /home/rhel/myansibleproject
  2. Run the ansible-builder create command in the VS Code Terminal:

    Execute the following command in the active terminal to generate the build context.

    ansible-builder create

    Expected Output: This creates the context/ directory containing the Containerfile and all necessary build artifacts.

  3. Inspect the generated Containerfile:

    In the VS Code file explorer, locate context/Containerfile and open it. Review the sequential stages (Base, Galaxy, Builder, Final) generated by ansible-builder.

Task 3: Build and tag the custom Execution Environment

Now we will execute the full build process and assign a specific tag to the final container image.

  1. Run the ansible-builder build command:

    Use the -t flag to tag your new EE image and the -vvv flag for detailed output.

    ansible-builder build -t mynamespace/mycollection-ee:latest -vvv
    Verbosity Flag

    The -vvv flag specifies the verbosity level of the output and is not related to the version schema defined in your YAML file.

  2. Verify the image creation:

    The build command executes the container build across 4 internal stages: Base, Galaxy, Builder, and Final. After the build completes successfully, you should see a message similar to this one:

    [4/4] STEP 22/22: CMD ["bash"]
    [4/4] COMMIT mynamespace/mycollection-ee:latest
    --> 6492fc97cd31
    Successfully tagged localhost/mynamespace/mycollection-ee:latest
    6492fc97cd316aba11934f050e9ff5b8edf52972c80934ca70e122f1965bf62c
    
    Complete! The build context can be found at: /home/rhel/myansibleproject/context
  3. Verify the container image exists:

    Use your podman container runtime tool to verify the local image exists.

    podman images | grep mynamespace

    You should see mynamespace/mycollection-ee listed.

  4. Test the custom Execution environment contains mycollection:

    With podman we can run an ansible-galaxy command to list all collections in the execution environment:

    podman run mynamespace/mycollection-ee:latest ansible-galaxy collection list

    This command should display mycollection and its dependencies.

    # /usr/share/ansible/collections/ansible_collections
    Collection               Version
    ------------------------ -------
    ansible.netcommon        8.2.0
    ansible.posix            2.1.0
    ansible.utils            6.0.0
    mynamespace.mycollection 1.0.0
  5. Run the mycowsay.yml playbook with your new EE:

    Use ansible-navigator to run your mycowsay.yml playbook with your newly created custom execution environment:

    ansible-navigator run mycowsay.yml --execution-environment-image mycollection-ee --pull-policy never
  6. Test the cowsay module documentation:

    Run a quick test inside the container to verify the custom collection and module dependency were successfully packaged.

    podman run mynamespace/mycollection-ee:latest ansible-doc -t module mynamespace.mycollection.cowsay
    This command should display the documentation for your custom module, but we didn’t add the corresponding metadata blocks! We will leave it to you as an optional task to research and fix this issue if you have time after finishing the lab!

Next steps

You have successfully packaged your automation content into an Execution Environment using ansible-builder and VS Code. This image is now ready for upload to an Automation Hub or deployment via Automation Controller. Please click the Next button below to proceed to the next module.