Step-by-step guide to building Ansible collections

Posted By
Rohan Suryawanshi

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.
Related Blogs
