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 0: Promote your playbook to the playbook project

Now that your playbook and collection are working, it’s time to prepare them for production. In a real workflow, the collection and the playbook project are distributed separately — the collection is packaged into an Execution Environment, while the playbook project is pushed to a Git repository and pulled by Ansible Automation Platform’s Controller.

Copy your working playbook from the collection into the myplaybook project directory you created in Lab 1.1. In VS Code, expand mynamespace.mycollection > playbooks, right-click on mycowsay.yml and select Copy. Then expand the myplaybook folder in the workspace root, right-click on it and select Paste.

Alternatively, you can use the terminal:

cp /projects/ansible-dev-tools-workspace/mynamespace.mycollection/playbooks/mycowsay.yml /projects/ansible-dev-tools-workspace/myplaybook/

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 destination directory. The VS Code wizard requires the destination directory to exist before creating the project. In the VS Code file explorer sidebar, right-click on the workspace root (ansible-dev-tools-workspace) and select New Folder. Name it mycollection-ee.

  2. 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
  3. Fill out the Execution environment project details. Use the following information:

    • Destination path:

      /projects/ansible-dev-tools-workspace/mycollection-ee
    • Base image: Leave the dropdown as -- Select Base Image --.

    • Custom base image: Enter the following base image:

      image-registry.openshift-image-registry.svc:5000/openshift/ee-minimal-rhel9:latest
      This is the Red Hat supported ee-minimal base image, pre-loaded into the cluster’s internal registry. It is the same image used by Ansible Automation Platform in production.
    • 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
      The CLI equivalent of this wizard is: ansible-creator init execution_env --ee-base-image image-registry.openshift-image-registry.svc:5000/openshift/ee-minimal-rhel9:latest --ee-collections mynamespace.mycollection --ee-python-deps cowsay --ee-name mycollection-ee /projects/ansible-dev-tools-workspace/mycollection-ee
  4. Open the execution-environment.yml file:

    In the VS Code file explorer, expand the mycollection-ee folder and open execution-environment.yml.

  5. Check the EE blueprint content:

    This configuration defines the base image, includes the collection dependencies, and explicitly adds the Python dependency (cowsay) needed for your custom module. The file should look similar to the one below:

    ---
    version: 3
    images:
      base_image:
        name: image-registry.openshift-image-registry.svc:5000/openshift/ee-minimal-rhel9: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
  6. Customize the EE blueprint for local development:

    Since our collection is not yet published to Ansible Galaxy or Automation Hub, we need to customize the EE definition for local development. We will replace the wizard-generated dependencies with an explicit Python interpreter path, add an additional_build_files section to copy the collection tarball into the build context, modify the galaxy section to point to the tarball path using type: file, and set the package manager path to microdnf.

    Replace the contents of execution-environment.yml with:

    ---
    version: 3
    images:
      base_image:
        name: image-registry.openshift-image-registry.svc:5000/openshift/ee-minimal-rhel9:latest
    
    dependencies:
      python_interpreter:
        python_path: /usr/bin/python3.12
    
      galaxy:
        collections:
          # 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
    
    # Copy the tarball 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

    Understanding the customizations:

    • python_interpreter.python_path: Uses /usr/bin/python3.12 to match the Python version shipped in the ee-minimal-rhel9 base image.

    • additional_build_files: Copies the collection tarball into the build context under collection_tarballs/.

    • type: file in the galaxy section: Tells ansible-galaxy to install the collection from the local tarball instead of downloading it from Galaxy.

    • package_manager_path: Uses microdnf, the package manager available in the ee-minimal-rhel9 base image.

  7. Save the file.

  8. Package the collection as a tarball:

    Before building the EE, we need to package the collection. The build_ignore entries you added to galaxy.yml earlier ensure that development directories (.venv, collections, .tox) are excluded from the package.

    cd /projects/ansible-dev-tools-workspace/mynamespace.mycollection
    ansible-galaxy collection build --output-path /projects/ansible-dev-tools-workspace/mycollection-ee/

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. Navigate to the EE project directory:

    cd /projects/ansible-dev-tools-workspace/mycollection-ee
  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: /projects/ansible-dev-tools-workspace/mycollection-ee/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 /projects/ansible-dev-tools-workspace/myplaybook/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. See the Module format and documentation guide for details on how to add DOCUMENTATION, EXAMPLES, and RETURN blocks to your module.

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 Lab 3.2 - Introducing supply chain security with ansible-sign.