Ansible Modules, ansible-doc, and Collections Explained

Learn Ansible modules, FQCN names, ansible-doc options and return values, collections, ansible-galaxy install, requirements.yml, collections_path, and module-not-found fixes.

Published

Updated

Read time 12 min read

Reviewed byDeepak Prasad

Ansible modules, ansible-doc, and collections on Rocky Linux 10

Ansible modules are the building blocks of automation—each module performs one kind of work on a managed host. Collections package modules (and plugins) under a namespace; ansible-doc shows their options on the control node before you write a playbook or ad hoc command.

This guide covers builtin modules, FQCN naming, common module families, ansible-doc, collection install paths, requirements.yml, and module discovery. I ran commands on rocky1 from the EX294 lab with ansible-core 2.16. Read install Ansible and project layout first.

Tested on: Rocky Linux 10.2 (Red Quartz); kernel 6.12.0-211.16.1.el10_2.0.1.x86_64; ansible-core 2.16.16.

NOTE
This chapter is part of the GoLinuxCloud Ansible tutorial (RHCE EX294). Follow along from ~/ansible-project, inventory group lab, and playbooks in playbooks/. Use your own host names and paths if yours differ.

What are Ansible Modules?

A module is a unit of code Ansible runs on a managed host (or locally for some connection: local tasks). You invoke modules from:

  • Ad hoc commands: ansible lab -m ansible.builtin.ping
  • Playbook tasks: - name: Ensure httpd / ansible.builtin.dnf: ...

Each module accepts arguments, performs work, and returns JSON—changed, msg, and module-specific keys. Ansible ships dozens of modules in ansible.builtin; extra modules arrive in collections such as ansible.posix or community.general. When you must run a plain command instead of a state module, see command vs shell vs raw for which executor to pick.


How Ansible Runs a Module

For a normal Linux target, Ansible follows this simplified flow:

  1. The control node reads inventory, variables, and task arguments.
  2. Ansible opens the configured connection, usually SSH.
  3. Module code and arguments are prepared for the target.
  4. The module runs on the managed node, usually through Python.
  5. The module returns JSON to the control node.
  6. Ansible prints ok, changed, failed, or unreachable.

Managed nodes need SSH access and Python for most Linux modules—they do not need ansible-core or installed collections. Collections live on the control node; module code is sent or invoked during the task.


Ansible Modules vs Plugins vs Collections

Piece Runs where Purpose Example
Module Usually on the managed host; some run locally or use action plugins One task action ansible.builtin.copy, ansible.builtin.dnf
Plugin Control node Extend Ansible internals inventory plugins, connection plugins, callbacks
Collection Installed on control node Bundle modules, plugins, roles, docs ansible.posix, community.general

For normal Linux automation, Ansible usually transfers module code to the managed node and executes it there. Some modules have controller-side action plugins or interact with APIs instead of running entirely on the target.

Modules answer “what should this host do?” Plugins answer “how does Ansible connect, parse inventory, or format output?” Collections are how Red Hat and the community ship and version those pieces separately from ansible-core.


Builtin Modules and ansible.builtin

ansible-core includes the ansible.builtin collection—no extra install for modules such as:

  • ping, setup — connectivity and facts
  • command, shell — run programs
  • copy, file, template — files and templates
  • dnf, package, service — packages and services
  • user, group — local accounts

On Rocky Linux 10, dnf install ansible-core provides the engine and builtin modules. Extra collections come from EPEL RPMs or ansible-galaxy collection install (install guide).


Short Module Names vs FQCN

What is FQCN in Ansible?

FQCN (Fully Qualified Collection Name) identifies a module as namespace.collection.module:

text
ansible.builtin.copy
│              │     └── module name
│              └── collection name
└── namespace (Ansible-maintained for builtin)

Another example: ansible.posix.firewalld — the firewalld module from the ansible.posix collection.

  • Removes ambiguity when collections contain similar module names
  • Makes documentation lookup easier: ansible-doc ansible.builtin.copy
  • Works better with linters and production playbooks
  • Avoids surprises from short-name collection search order

Ansible 2.10+ playbook style recommends FQCN so the intended module is selected explicitly. Use FQCN in playbooks and exams: ansible.builtin.dnf, not bare dnf.

When short module names are still commonly used

Short names (ping, copy, dnf) still resolve when the module is unique in configured paths. They appear in older docs and quick ad hoc examples:

bash
cd ~/ansible-project
ansible lab -m ping

Sample output:

output
rocky2 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

The FQCN form is equivalent when ansible.builtin is on the path:

bash
ansible lab -m ansible.builtin.ping

Prefer FQCN in new playbooks; use short names only when you know the module source.


FQCN vs collections Keyword

Playbooks can use the collections: keyword to shorten module names:

yaml
collections:
  - ansible.posix

Then a task may use firewalld instead of ansible.posix.firewalld. For beginner labs and production readability, prefer FQCN anyway:

yaml
- name: Allow http through firewalld
  ansible.posix.firewalld:
    service: http
    state: enabled
    permanent: true

FQCN makes the module source visible in every task and avoids relying on collection search order.


Common Ansible Module Categories

Category Example modules (FQCN) Typical use
Connection and test ansible.builtin.ping, ansible.builtin.setup SSH/Python check, gather facts
Command and shell ansible.builtin.command, ansible.builtin.shell Run programs
Package ansible.builtin.dnf, ansible.builtin.package, ansible.builtin.apt Install or remove packages
Service ansible.builtin.service, ansible.builtin.systemd_service Start, stop, enable units
File and copy ansible.builtin.copy, ansible.builtin.file, ansible.builtin.fetch Push files, directories, permissions
User and group ansible.builtin.user, ansible.builtin.group Local accounts
Template and line editing ansible.builtin.template, ansible.builtin.lineinfile, ansible.builtin.blockinfile Templated configs, one-line edits

Collection modules extend the table—for example ansible.posix.firewalld for firewalld rules when that collection is installed.


How to Find Module Documentation with ansible-doc

ansible-doc reads module documentation installed on the control node. Run it on rocky1 before guessing -a arguments.

List available modules

bash
ansible-doc -l

Sample output:

output
ansible.builtin.add_host               Add a host (and alternatively a grou...
ansible.builtin.apt                    Manages apt-packages
ansible.builtin.apt_key                Add or remove an apt key
ansible.builtin.copy                   Copy files to remote locations

Filter the list:

bash
ansible-doc -l | grep -i firewalld

Sample output:

output
ansible.posix.firewalld                Manage arbitrary ports/services with...
ansible.posix.firewalld_info           Gather information about firewalld

View documentation for one module

bash
ansible-doc ansible.builtin.copy

Sample output:

output
> ANSIBLE.BUILTIN.COPY    (.../ansible/modules/copy.py)

        The [ansible.builtin.copy] module copies a file or a directory
        structure from the local or remote machine to a location on
        the remote machine.

Check module options

The synopsis (-s) shows parameters in playbook shape:

bash
ansible-doc -s ansible.builtin.file

Sample output:

output
- name: Manage files and file properties
  file:
      path:                # Path to the file being managed.
      state:               # absent | directory | file | hard | link | touch
      mode:                # Permissions the resulting filesystem object should have.

Check examples

Scroll the full doc for an EXAMPLES: section, or extract it:

bash
ansible-doc ansible.builtin.dnf | sed -n '/^EXAMPLES:/,/^RETURN VALUES:/p' | head -15

Sample output:

output
EXAMPLES:

- name: Install the latest version of Apache
  ansible.builtin.dnf:
    name: httpd
    state: latest

- name: Install the latest version of Apache and MariaDB
  ansible.builtin.dnf:
    name:
      - httpd
      - mariadb-server
    state: latest

Check return values

Return values appear under RETURN VALUES: at the end of the same doc:

bash
ansible-doc ansible.builtin.copy | sed -n '/^RETURN VALUES:/,/^$/p' | head -12

Sample output:

output
RETURN VALUES:
- backup_file
        Name of backup file created.
        returned: changed and if backup=yes
        sample: /path/to/file.txt.2015-02-12@22:09~
        type: str

Use return values when you register a task and need to know which keys to expect in later tasks.

View plugin documentation

By default, ansible-doc looks for modules. Use -t for other plugin types:

bash
ansible-doc -t inventory ansible.builtin.ini

Sample output:

output
> ANSIBLE.BUILTIN.INI    (.../ansible/plugins/inventory/ini.py)

        INI file based inventory, sections are groups or group related
        with special `:modifiers'.
bash
ansible-doc -t connection ansible.builtin.ssh

Sample output:

output
> ANSIBLE.BUILTIN.SSH    (.../ansible/plugins/connection/ssh.py)

        This connection plugin allows Ansible to communicate to the
        target machines through normal SSH command line.

Connection and lookup plugins use the same -t pattern—for example ansible-doc -t lookup ansible.builtin.file.


Understanding Module Options, State and Return Values

Most modules use key=value arguments:

  • name — package name, service name, file path, or username (module-specific)
  • state — desired end state: present, absent, started, stopped, directory, and so on
  • mode, owner, group — permissions on file modules

Example task shape:

yaml
- name: Install tmux
  ansible.builtin.dnf:
    name: tmux
    state: present

After the module runs, Ansible shows JSON on the CLI or in playbook output. Common keys:

Key Meaning
changed true if the module altered the system
failed Task error (playbook recap)
msg Human-readable message on failure
Module-specific e.g. checksum from copy, results from dnf

Idempotent modules set changed: false when the system already matches state.


Check Module Attributes: Check Mode, Diff Mode, and Idempotency

Not every module supports every Ansible feature. In ansible-doc, check the ATTRIBUTES: section for:

Attribute Meaning
Check mode Whether the module can predict changes with --check
Diff mode Whether the module can show before/after differences with --diff
Idempotency Whether the module can detect current state before changing it
Platform Which operating systems or targets the module supports
bash
ansible-doc ansible.builtin.copy

Sample output:

output
ATTRIBUTES:

        check_mode:
          description: Can run in check_mode and return changed status prediction without
            modifying target
          support: full
        diff_mode:
          description: Will return details on what has changed (or possibly needs changing
            in check_mode), when in diff mode
          support: full

Modules such as copy, file, dnf, and service are usually better for repeatable automation than raw command or shell because they understand desired state.


What are Ansible Collections?

A collection is a distributable package of modules, plugins, roles, and documentation under a namespace. ansible-core ships ansible.builtin; vendors and community publish others (ansible.posix, community.general, amazon.aws, …). For RHEL System Roles and production collection workflows, see collections and RHEL System Roles.

Collections version independently from ansible-core. Pin versions in requirements.yml so teammates and CI install the same content.

On Rocky Linux 10, EPEL provides RPMs such as ansible-collection-ansible-posix—see install Ansible. ansible-galaxy collection install is the portable alternative when you use PyPI ansible-core or need a collection not packaged as an RPM.


Install Ansible Collections with ansible-galaxy

Install collections on the control node as the ansible user (or root for system-wide paths).

Install one collection

bash
ansible-galaxy collection install ansible.posix

When the collection is already present:

output
Starting galaxy collection install process
Nothing to do. All requested collections are already installed. If you want to reinstall them, consider using `--force`.

On this lab, ansible.posix came from the EPEL RPM ansible-collection-ansible-posix.

Install collections into a project directory

Install beside a project so the tree is self-contained:

bash
ansible-galaxy collection install ansible.posix \
  -p ~/ansible-project/collections

When you install with -p ./collections, Ansible expects the collection under collections/ansible_collections/NAMESPACE/NAME/. This layout is commonly used beside a playbook or project root. If Ansible warns that the path is not in collections_path, add the project collection path in ansible.cfg:

ini
[defaults]
collections_path = ./collections:/home/ansible/.ansible/collections:/usr/share/ansible/collections

List installed collections

bash
ansible-galaxy collection list

Sample output:

output
# /usr/share/ansible/collections/ansible_collections
Collection    Version
------------- -------
ansible.posix 2.1.0

Remove or update collections

  • Reinstall: ansible-galaxy collection install NAMESPACE.NAME --force
  • Remove: delete the collection directory under ansible_collections/ in the relevant collections_path, or remove the EPEL RPM on Rocky Linux
  • Upgrade: install with a newer version constraint or update the RPM

Use requirements.yml for Collections

Pin collections in requirements.yml at the project root (project layout). Treat this file as the contract for your control node and CI: commit it to Git, install from it before every pipeline run, and bump versions deliberately after you test—not on every fresh clone.

Why pin collection versions in production

Collections version independently from ansible-core. A playbook that works today can fail tomorrow when ansible-galaxy collection install without a pin pulls a newer release with renamed options or stricter dependencies. For labs, CI, and production:

  • Pin exact versions (version: "2.1.0") for reproducible installs
  • Run ansible-galaxy collection install -r requirements.yml on every control node and in CI before ansible-playbook
  • Keep collection RPM pins on Rocky Linux aligned with the same requirements.yml when you mix EPEL and Galaxy installs

Floating installs are fine for quick experiments; pinned requirements.yml is the best practice for anything you rerun or share.

Basic requirements.yml structure

yaml
---
collections:
  - name: ansible.posix
    version: "2.1.0"
  - name: community.general
    version: ">=8.0.0"

Install collections from requirements.yml

bash
ansible-galaxy collection install -r requirements.yml \
  -p ~/ansible-project/collections

If collections are already satisfied, output matches a single-collection install. When the target path is outside collections_path, Ansible warns—add collections_path under [defaults] in ansible.cfg as shown above.

Pin collection versions

Use exact versions for reproducible labs and CI:

yaml
collections:
  - name: ansible.posix
    version: "2.1.0"

Use ranges only when you intentionally accept upgrades: version: ">=2.0.0,<3.0.0".


Module Discovery and Collection Paths

Ansible searches for modules in:

  1. ansible.builtin (with ansible-core)
  2. Paths in COLLECTIONS_PATHS / collections_path in ansible.cfg
  3. ~/.ansible/collections and /usr/share/ansible/collections by default

Check effective settings:

bash
ansible-config dump | grep -i collection

Sample output:

output
COLLECTIONS_PATHS(default) = ['/home/ansible/.ansible/collections', '/usr/share/ansible/collections']
COLLECTIONS_ON_ANSIBLE_VERSION_MISMATCH(default) = warning

Module names in tasks must resolve to an installed collection on the control node. Managed nodes only need Python and whatever the module executes—they do not run ansible-galaxy.


Troubleshoot Module Not Found Errors

Wrong or missing module:

bash
cd ~/ansible-project
ansible lab -m nonexistent.module

Sample output:

output
rocky2 | FAILED! => {
    "msg": "The module nonexistent.module was not found in configured module paths"
}
Symptom Likely cause Fix
module was not found in configured module paths Typo, missing collection, or wrong FQCN ansible-doc -l | grep KEYWORD; install collection
Short name fails but FQCN works Search order or deprecated redirect Use FQCN in playbooks
Collection installed but unused Path not in collections_path Add path to ansible.cfg or use -p beside project
ansible.posix.* missing Collection not installed EPEL RPM or ansible-galaxy collection install ansible.posix
Works on one host, not another Different control node paths Same requirements.yml and ansible.cfg on every controller
Works as root, fails as ansible user Collection installed under root's home Install as the same user that runs Ansible or use system path
requirements.yml installed but module missing Installed into a path outside collections_path Check ansible-config dump | grep -i collection

Discovery checklist:

bash
ansible-galaxy collection list
bash
ansible-doc -l | grep -i MODULE_KEYWORD

Best Practices for Using Modules and Collections

  • Use FQCN in playbooks and roles (ansible.builtin.copy)
  • Run ansible-doc before new modules—options, examples, and return values
  • Pin collections in requirements.yml and commit it with the project
  • Install collections on the control node only; keep versions aligned across teammates
  • Prefer idempotent modules (dnf, file, service) over raw shell when a module exists
  • On Rocky labs, know both EPEL RPM and ansible-galaxy install paths
  • After adding collections, run ansible-doc NAMESPACE.collection.module to confirm the install

What Not to Cover in This Article

This page stops at modules, ansible-doc, and collections. Deeper topics belong in other guides:

  • Writing custom modules or plugins
  • Full Ansible Vault workflow
  • Role variable precedence inside roles
  • Dynamic inventory plugins
  • Execution environment / navigator internals (ansible-navigator.yml)
  • Full playbook tutorial

What comes next

  1. Ansible ad hoc commands — run modules from the CLI
  2. Ansible playbook examples — tasks and modules in YAML
  3. group_vars, host_vars and patterns — variables and targeting

References


Summary

Ansible modules perform task work—usually on managed hosts after SSH and Python are in place. ansible.builtin ships with ansible-core; other modules live in collections installed on the control node. Use FQCN names (ansible.builtin.dnf), read ATTRIBUTES and options with ansible-doc, and install collections via EPEL RPMs or ansible-galaxy collection install plus requirements.yml. If Ansible cannot find a module, verify the FQCN, run ansible-galaxy collection list, and confirm collections_path includes your install directory.


Frequently Asked Questions

1. What is FQCN in Ansible?

Fully Qualified Collection Name—namespace.collection.module, such as ansible.builtin.copy. It tells Ansible exactly which collection provides the module.

2. What is the difference between an Ansible module and a plugin?

Modules are task units that usually run on managed hosts (copy, dnf, service); some use controller-side action plugins. Plugins extend Ansible on the control node (inventory, connection, callbacks, lookups).

3. Where are Ansible collections installed?

Default paths include ~/.ansible/collections and /usr/share/ansible/collections. ansible.cfg collections_path and project-local collections/ can add more.

4. How do I find Ansible module documentation offline?

Run ansible-doc MODULE_NAME on the control node—for example ansible-doc ansible.builtin.dnf for options, examples, and return values.

5. Why does Ansible say a module was not found?

The collection is missing on the control node, the FQCN is wrong, or collections_path does not include the install directory. Install the collection or fix the module name.
Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with more than 15 years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive …