Skip to main content

Step-by-step guide to building Ansible collections

Posted By

Rohan Suryawanshi

Date Posted
01-Apr-2025

Managing automation content in Ansible becomes very chaotic as your infrastructure grows. Files are scattered across directories, there are inconsistent naming conventions, and it is difficult to share your work with team members or the wider community. Every time you onboard someone new, it takes them several days to learn your custom automation setup. When you need to reuse modules that you created six months ago, you spend hours browsing folders, trying to remember where you saved them. Working together with other teams is also difficult because it leads to copy-pasting, duplication, and having different versions. Ever wondered if there was something to overcome these challenges?

Ansible collections solve these problems by providing a standardized way to organize and distribute your automation content. Collections package related tasks, roles, modules, plugins, and playbooks into a single, shareable unit that anyone can easily install and use. In this blog, I'll walk you through creating your own Ansible collection from scratch, exploring its structure, and showing you how to test, build, and publish it for maximum reusability.

Why use custom Ansible Collections?

Ansible collections are helpful when you need to extend the platform's capabilities or when built-in modules and roles don't fit your requirements.

Here are the top reasons to build your own Ansible collection:

  • Customization: Tailor automation to fit your organization’s specific needs.
  • Proprietary systems: Integrate with custom software or hardware that isn’t supported by Ansible out-of-the-box.
  • Reusability: Encapsulate functionality in reusable modules and roles.
  • Versioning: Easily manage versions and track changes in your automation code.
  • Clean and modular: Organize automation tasks to make playbooks cleaner and more maintainable.
  • Integration: Connect to external tools, services, or APIs not supported by existing Ansible modules.[node:summary]

Step-by-step guide to create an Ansible collection

Here's the process of Ansible collection creation.

Step 1: Create a directory for your collection

You need to create a directory structure for your collection to get started. The ansible-galaxy command provides an easy way to set this up using the init feature.

ansible-galaxy collection init <namespace>.<collection_name>

​​​​Replace it with your username or organization name (e.g., Rtech) and your collection's name (e.g., RLT). This will generate the basic structure for your collection.

Example command:

ansible-galaxy collection init Rtech.RLT

This command creates a folder structure that looks like this:

Rtech/
└── RLT/
    ├── README.md
    ├── docs/
    ├── galaxy.yml
    ├── meta/
     │   └── runtime.yml
    ├── plugins/
    │   └── README.md
    └── roles/

Step 2: Add content to your collection

Now that you have the basic structure, you can start adding content like roles or modules.

a. Create your custom module:

In the plugins/modules/ directory, create a Python file for your custom module. Let’s assume we're creating a CRUD operation for managing a resource (e.g., a database record).

For example, let’s say you’re managing user records with a custom module.

mkdir –p Rtech/RLT/plugins/modules 
        touch Rtech/RLT/plugins/modules/user.py

Now, edit the user.py file.

#!/usr/bin/python
from ansible.module_utils.basic import AnsibleModule
def create_user(module): 
# Perform the logic to create a user (e.g., write to a database or file) 
    # For example, here we simulate a user being "created". 
    user_name = module.params['name'] 
    user_data = module.params['data']
# Example logic for user creation
    try:
            # Simulating creation process
            # In a real case, you could use APIs or libraries to interact with the system
           module.exit_json(changed=True, msg=f"User {user_name} created.")
    except Exception as e:
            module.fail_json(msg=f"Failed to create user: {str(e)}")
 

 

def update_user(module): 
# Perform the logic to update a user 
    user_name = module.params['name'] 
    user_data = module.params['data']
try:
        # Simulating update process
            # In a real case, you could use APIs or libraries to interact with the system 

            module.exit_json(changed=True, msg=f"User {user_name} updated.")
    except Exception as e:
            module.fail_json(msg=f"Failed to update user: {str(e)}") 

def delete_user(module): 
# Perform the logic to delete a user user_name = module.params['name']
try:
            # Simulating user deletion
            if check if user exist in db:
                    # delete the user
                    module.exit_json(changed=True, msg=f"User {user_name} deleted.")
            else:
                    module.exit_json(changed=False, msg=f"User {user_name} does not exist.")
    except Exception as e:
            module.fail_json(msg=f"Failed to delete user: {str(e)}")
 

def main(): 
    argument_spec = dict( 
        name=dict(type='str', required=True), 
        data=dict(type='dict', required=False), 
        state=dict(type='str', choices=['present', 'absent'], default='present'), 
    )
module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)
    state = module.params['state']
    if state == 'present':
            if module.params['data']:
                    update_user(module)
            else:
                    create_user(module)
    elif state == 'absent':
            delete_user(module) 
if __name__ == 'main': 
    main()
Key points about this module:

Parameters:

  • name: The name of the user/resource to manage.
  • data: The data (e.g., user details) to store for the user.
  • state: Defines whether the user should be present or absent.

CRUD Operations:

  • Create (present): If data is provided, it updates the user, otherwise creates it.
  • Update: If the user exists, it updates the user data.
  • Delete (absent): Deletes the user data.

b.    Create a simple role

To demonstrate how a role is added, navigate to the tasks/ directory inside your collection folder:

cd Rtech/RLT/roles
ansible-galaxy role init firstrole

Add the below contents in main.yml to call your module from the role

---
- name: Ensure a package is installed 
   Rtech.RLT.user: 
    name: "{{ name }}" 
    data: "{{ data }}" 
    state: "{{ state }}"

Step 3: Build the collection

Once you've added content like roles or modules, you need to build the collection. To do this, navigate to the root of your collection directory and run the following command:

ansible-galaxy collection build

This command generates a .tar.gz file, such as Rtech-RLT-1.0.0.tar.gz, which contains the entire collection.

Step 4: Install the collection locally

You can install the collection on your local machine using the following command:

ansible-galaxy collection install Rtech-RLT-1.0.0.tar.gz

This will make your collection available for use in playbooks.

Step 5: Create a playbook to use the collection

Now that you’ve built and installed your collection, you can create a playbook to test it.

Create a playbook.yml outside the collection directory, for example: 

- name: Test create user using collection role 
   hosts: localhost  
   collections: 
    Rtech.RLT 
   roles: 
    firstrole 
   vars: 
    name: "john_doe" 
    data: "Some user data" 
    state: "present"
- name: Test update user using collection role 
   hosts: localhost  
   collections: 
    Rtech.RLT 
   roles: 
    firstrole 
   vars: 
    name: "john_doe" 
    data: "Some user data in dict format" 
    state: "present"
- name: Test delete user using collection role 
   hosts: localhost  
   collections: 
    Rtech.RLT 
   roles: 
    firstrole 
   vars: 
    name: "john_doe" 
    state: "absent"

Step 6: Test the collection locally

To test the collection, run the following command:

ansible-playbook playbook.yml

This will execute the firstrole from the collection Rtech.RLT, allowing you to verify that the role works as expected.

Step 7: Publish the Collection

Once you are satisfied with the collection, you can publish it to Ansible Galaxy.

To publish the collection, you need to be in the directory containing the collection that you want to publish, and the collection must be built and ready for publication.

Now, log in to Ansible Galaxy:

ansible-galaxy login

Then, publish the collection:

ansible-galaxy collection publish <PATH-TO-collection-build>
e.g ansible-galaxy collection publish Rtech-RLT-1.0.0.tar.gz

This will upload your collection to Ansible Galaxy, where others can access it and use it in their own automation workflows.

What does an Ansible collection structure look like?

Here’s a closer look at the folder structure and key files in an Ansible collection:

galaxy.yml: This file contains metadata about the collection, such as its name, version, description, and dependencies.

Example of galaxy.yml:

    namespace: Rtech
    name: RLT
    version: "1.0.0"
    readme: README.md
    dependencies: []
    tags:
      - example

README.md: This file explains the collection's purpose, usage, and provides examples of how to use it in playbooks.

Example of README.md:

# My Collection 

    This collection provides an example role to install packages using Ansible. 

    ## Example Playbook 

    ---
    - name: Test the mycollection role
      hosts: localhost
      collections:
        - Rtech.RLT
      roles:
        - firstrole
### Roles
The roles/ directory contains reusable configurations. Each role typically has a tasks/main.yml file that defines the tasks to be executed.
### Plugins
If you are creating custom modules or plugins, you would add them to the plugins/ directory.

Conclusion

Ansible collections are a major step forward in automating infrastructure. They provide a simple way to organize, share, and reuse your automation tools. Organizations that set up effective collection structures see real benefits like more efficient workflows, better teamwork, and more reliable deployments. Create your own collections to enhance Ansible's features while keeping your code clean, modular, and easy to maintain. After creating your collection, you can share it with others through Ansible Galaxy or use it within your organization. If you want to build your own Ansible collection, Opcito's engineers can help you get the most out of your automation investment. Contact us to discuss your business needs and explore the best steps for your specific environment.

Subscribe to our feed

select webform