unit 4 · Playbooks
Modules, plugins & collections
Where the code actually runs
you may want to read 4 · Collections & FQCN first — but nothing is locked
tl;dr
- A module is a unit of work. Ansible ships it to the managed node, runs it, deletes it.
- A plugin extends the engine itself and always runs on the control node — it never leaves home.
- A collection is the shipping container: modules, roles and plugins packaged under one namespace.
why it matters Half of Ansible debugging is knowing which machine a piece of code ran on — read a file on the wrong side of the connection and you chase a ghost.
Three words carry most Ansible conversations: module, plugin, collection. You’ve used all three — every task in lesson 12 called a module , lesson 11’s dynamic inventory came from a plugin, and lesson 4 unpacked collections. What’s left is the sorting rule: where does this code execute?
Modules: shipped out, run remotely
A module is a unit of work — install this package, copy this file, restart that service. When a task runs, Ansible copies the module’s code to the managed node , executes it there, collects the JSON result, and deletes the code. That round trip is lesson 2’s agentless trick: nothing is pre-installed on the target because everything the task needs travels with it. Usually on the managed node, that is. Modules that talk to an API (a cloud provider, say) have no host to land on and run from the controller.
Plugins: the engine’s extension points
A plugin never travels. It extends the engine on the control node — Ansible’s own machinery, made pluggable. The types you’ll actually meet:
- connection — how Ansible reaches hosts: SSH, WinRM, PSRP.
- inventory — builds the host list; lesson 11’s cloud queries.
- callback — formats run output; lesson 6’s
stdout_callbackpicks one. - lookup — pulls external data into a template at run time.
- filter — transforms values inside
{{ }}expressions. - become — implements privilege escalation methods.
Two of those close old loops: lesson 11’s inventory plugins and the
callback behind lesson 6’s stdout_callback were plugins before you had
the word. And where-it-runs is not trivia — it bites:
- name: Install the deploy key
ansible.builtin.copy:
# lookup PLUGIN — reads this file on the CONTROL node
content: "{{ lookup('file', 'files/deploy_key.pub') }}"
# copy MODULE — writes this path on the MANAGED node
dest: /home/deploy/.ssh/authorized_keys
mode: '0600'One task, two machines: the lookup runs at home before anything ships, the module runs on the target afterwards.
Collections: the box both come in
A collection is the distribution format — a versioned
package bundling modules, plugins and roles under one namespace. That’s
why lesson 4’s FQCN matters for more than modules: community.general
ships lookup and filter plugins too, and installing one collection can
extend both sides of the wire at once.
One disambiguation, because it trips beginners in meetings: a role is a reusable unit of tasks; a collection is the package that can contain roles. Box versus contents — structure in lesson 24.
So the taxonomy is one question deep. Code that does work on a host: module.
Code that changes how the engine itself behaves: plugin, and it stays home.
The versioned package either arrives in: collection. Next lesson you put
modules back to work — capturing what they return with register and
reading it with ansible.builtin.debug.
self-check — recall, not a test
1 Where does a module run, and where does a plugin run?
2 A task uses lookup('file', 'deploy_key.pub'). Which machine's filesystem gets read?
3 A colleague says "the role ships in that collection." What is the relationship between the two?