Understand Ansible's evolution from a monolithic package to ansible-core and community collections. Learn namespace, FQCN, how to find and install collections from Ansible Galaxy, and managing dependencies with requirements.yml.

After episode 12, where we covered Ansible Roles and how to package automation into standardized units, in this episode we'll cover the next layer of the Ansible ecosystem: Ansible Collections and Ansible Galaxy.
If you've ever installed Ansible and seen warnings about "deprecated" modules, or searched for a module to manage AWS EC2 or Kubernetes but couldn't find it in the standard Ansible package, that's because the Ansible ecosystem has changed fundamentally. Ansible is now split into two: a lean core engine (ansible-core) and a collection of community modules distributed in packages called collections. Understanding this distribution model is very important because in the real working world, almost all cloud and k8s automation will need collections installed from Galaxy.
A fitting analogy: think of ansible-core like the Linux kernel, and collections like the distributions/software packages on top of it. The kernel alone is useless without applications, and good applications are built on a stable kernel. Similarly, ansible-core provides the execution engine and basic built-in modules, while collections provide thousands of modules for specific platforms that you can pick as needed, without having to carry them all.
In this episode, we'll cover the evolution from classic Ansible to collections, the split between ansible-core and ansible-community, the namespace and FQCN concepts, a table of commonly used collections, working with Ansible Galaxy (searching, installing, creating requirements.yml), and FQCN usage practice in playbooks.
Before Ansible 2.10, Ansible was shipped as one big package called ansible containing the engine plus thousands of modules inside. This model looked practical, but it had real problems:
Starting from Ansible 2.10, Red Hat separated the two:
ansible-core — a small package containing the execution engine (executor, inventory, playbook parser), ansible.builtin (basic modules), and command-line tools like ansible, ansible-playbook, ansible-galaxy, and ansible-vault.ansible-community — a meta package that installs ansible-core plus a tested collection of community collections, so the user experience stays a "single install command".Note
If you run pip install ansible, you're actually installing the ansible-community package, which automatically pulls in ansible-core and dozens of popular collections at once. Meanwhile pip install ansible-core only installs the minimal engine. In production, many teams choose ansible-core + requirements.yml so the installed collections are truly controlled and can be version-pinned.
Every collection has an identity called FQCN (Fully Qualified Collection Name) with a three-part format:
<namespace>.<collection>.<resource>Examples are ansible.builtin.apt, community.docker.docker_container, and amazon.aws.ec2_instance. Let's break them down:
ansible, community, amazon, kubernetes, cisco, google.builtin, general, aws, core, ios.apt, docker_container, ec2_instance, k8s.Every resource in a collection has two forms of invocation: the full FQCN and the short name. Here's the comparison:
| FQCN (Recommended) | Short Name (Legacy) |
|---|---|
ansible.builtin.apt | apt |
ansible.builtin.copy | copy |
community.docker.docker_container | docker_container |
amazon.aws.ec2_instance | ec2_instance |
kubernetes.core.k8s | k8s |
Warning
Since Ansible 2.10, the short name (without namespace) is considered deprecated for modules that aren't part of ansible.builtin. Using docker_container without community.docker. will trigger a warning, and in future versions it could become an error. Use FQCN consistently from the start; ansible-lint will even flag short names as a violation.
To give you a picture of the ecosystem, here's a table of the collections most often seen in production:
| Collection | Functionality | Example Modules |
|---|---|---|
ansible.builtin | Core modules always available (included by ansible-core) | apt, copy, template, command, file |
ansible.posix | Basic POSIX/Linux utilities | firewalld, selinux, synchronize, mount |
community.general | Large general collection from the community | apache2_module, cron, ufw, parted |
community.docker | Docker & container management | docker_container, docker_image, docker_network |
community.mysql / community.postgresql | Database management | mysql_db, postgresql_db, mysql_user |
amazon.aws | AWS services | ec2_instance, s3_bucket, iam_user, rds_instance |
google.gcp | Google Cloud services | gcp_compute_instance, gcp_storage_bucket |
azure.azcollection | Microsoft Azure services | azure_rm_virtualmachine, azure_rm_storageaccount |
kubernetes.core | Kubernetes management | k8s, helm, kubectl |
cisco.ios, arista.eos, junipernetworks.junos | Network device automation | ios_config, eos_config, junos_config |
ansible.windows / community.windows | Windows management | win_service, win_package, win_updates |
Tip
A practical rule for choosing collections: use the official vendor collection when one exists (e.g., amazon.aws for AWS, kubernetes.core for Kubernetes), then fall back to community.* only if there's no official alternative. Official collections are better maintained, release faster when cloud APIs have breaking changes, and usually already follow security best practices.
Ansible Galaxy (galaxy.ansible.com) is the public registry for Ansible content: collections and roles. Its function is similar to npm for JavaScript, PyPI for Python, or Docker Hub for container images. Galaxy also provides a CLI already bundled inside ansible-galaxy.
There are two ways to search for collections: through the Galaxy website, or directly from the CLI using the search sub-command:
ansible-galaxy collection search kubernetes --author kubernetes
ansible-galaxy collection search "amazon.aws" --platforms amazonThe output will display a list of matching collections complete with descriptions and popularity scores:
NAME DESCRIPTION
kubernetes.core Ansible Collection for managing Kubernetes
kubernetes.core.helm Helm integration for AnsibleNote
The search command requires an internet connection to the Galaxy API. In an isolated (air-gapped) environment, the alternative is installing collections offline from a tarball, which we'll cover at the end of this episode.
Collection installation is done with ansible-galaxy collection install followed by the collection's FQCN:
ansible-galaxy collection install community.dockerThe output that appears:
Starting galaxy collection install process
Process install dependency map
Starting collection install process
Installing 'community.docker:3.4.8' to '.../ansible/collections/ansible_collections/community/docker'You can also install a specific version using ==:
ansible-galaxy collection install community.docker:==3.4.8Or install several collections at once, including from a tarball file:
ansible-galaxy collection install amazon.aws kubernetes.core community.dockerTip
By default, collections are installed to the ~/.ansible/collections/ansible_collections/ directory. To keep collections with the project (so all team members use the same version), install to the project's ./collections directory by adding the -p ./collections flag, then run Ansible with the env var ANSIBLE_COLLECTIONS_PATH=./collections or set collections_path in ansible.cfg.
To verify which collections are installed and their versions, use the list sub-command:
ansible-galaxy collection listIts output looks like this:
# .../.ansible/collections/ansible_collections
Collection Version
---------------------- -------
ansible.posix 1.5.4
ansible.utils 3.0.0
community.docker 3.4.8
kubernetes.core 2.4.0requirements.ymlInstalling collections one by one with CLI commands is practical for experimentation, but in production we need reproducibility: teams must be able to install collections with the exact same versions everywhere. The solution is the requirements.yml file.
The requirements.yml file can hold both collections and roles at once. For collections, the syntax is:
---
collections:
- name: community.docker
version: ">=3.4.0,<4.0.0"
- name: amazon.aws
version: "8.1.0"
- name: kubernetes.core
version: "2.4.0"
- name: community.general
- name: ansible.posix
- name: cisco.ios
source: https://galaxy.ansible.comNotice the following points:
version can be an exact version (8.1.0), a range (>=3.4.0,<4.0.0), or left empty to take the latest version.source allows pointing the installation to a specific Galaxy server (e.g., a company's private Galaxy/Artifactory).requirements.yml can also hold roles with the roles: syntax (used by ansible-galaxy role install -r).After the file is prepared, install all dependencies at once using the -r flag:
ansible-galaxy collection install -r requirements.ymlImportant
Pin collection versions in requirements.yml and commit that file to Git. Collections are updated very frequently, and a module whose behavior changes between versions can break a playbook that was previously running smoothly. By pinning versions, all team members and CI/CD pipelines use identical collections — this is the same reproducible builds principle as lockfiles in npm.
Now let's see how collections are used inside a playbook. The principle: write the module name with the full FQCN.
---
- name: Kelola container dengan collection community.docker
hosts: dockerhosts
become: true
tasks:
- name: Pastikan image nginx ter-pull
community.docker.docker_image:
name: nginx:1.27
source: pull
- name: Jalankan container nginx
community.docker.docker_container:
name: webapp
image: nginx:1.27
ports:
- "8080:80"
state: startedBesides modules, collections also carry roles. To use a role from a collection, the format is <namespace>.<collection>.<role_name>:
---
- name: Pakai role dari collection community.general
hosts: all
roles:
- community.general.apache2You can also limit the scope of collection usage per play using the collections: keyword at the play level. This lets you write short names within that play without warnings:
---
- name: Play dengan collections scope
hosts: webservers
become: true
collections:
- community.docker
- ansible.posix
tasks:
- name: Pull image
docker_image:
name: nginx:1.27
source: pullWarning
Use the collections: keyword at the play level carefully. Although it makes writing shorter, it makes module provenance implicit, so playbooks become harder to read and audit. Many teams choose explicit FQCN on every task as the standard, because it's more self-documenting and unambiguous.
A frequently asked question: "A collection also contains roles, so what's the difference from a regular role?" The answer is distribution. A regular role is stored in the project's roles/ directory or shared via Galaxy as a standalone role. A collection is a distribution container that can hold modules, plugins, and roles at once — grouped per namespace.
The comparison:
| Aspect | Standalone Role | Collection |
|---|---|---|
| Contents | Tasks, handlers, vars, templates, files | Modules + plugins + roles + docs |
| Identity | <role_name> | <namespace>.<collection>.<resource> |
| Installation | ansible-galaxy role install | ansible-galaxy collection install |
| When to use | Logic related to one component | Complete vendor/platform package |
| Real example | Custom roles/nginx | community.docker (Docker modules + role) |
Common best practice: roles for your internal business logic (deploying your own applications, company-specific configuration), collections for external platform integrations (cloud, network, database vendors).
1. Forgetting to install the collection before using its module
The most common error in the field is couldn't resolve module/action 'community.docker.docker_container'. This is almost always because the collection isn't installed. Solution: run ansible-galaxy collection install -r requirements.yml first, and make sure collections_path points to the same directory used during playbook execution.
2. Using short names without the collections: keyword
Writing docker_container directly in a playbook will trigger a deprecation warning and could fail in new versions. Use FQCN.
3. Not pinning collection versions
A playbook that "suddenly breaks" without any code change is often caused by a collection that auto-upgraded. Always pin versions in requirements.yml.
4. Assuming ansible and ansible-core are the same
pip install ansible installs the meta package (ansible-community), while pip install ansible-core is only the engine. In CI/CD, this difference matters: install what's needed and pin both versions.
5. Installing collections to the default path on a shared server
On a shared server, collections installed in ~/.ansible/collections are only visible to that user. Make sure ANSIBLE_COLLECTIONS_PATH or collections_path is configured so the whole pipeline uses the same location.
In episode 13, we learned that the modern Ansible ecosystem is split into ansible-core (the lean engine) and collections (packages of modules/plugins/roles per namespace), with ansible-community as the meta package combining the two. We understood the namespace and FQCN concept (<namespace>.<collection>.<resource>), got to know popular collections like ansible.builtin, community.docker, amazon.aws, and kubernetes.core, worked with Ansible Galaxy to search for and install collections, managed dependencies with requirements.yml, verified installations with ansible-galaxy collection list, and used collections in playbooks with FQCN.
Key points to take home:
ansible-core = engine, collection = content; consciously separate the two.requirements.yml + pinned versions is the key to reproducible automation.ansible-galaxy collection list.With the ability to install and use collections, you can build automation that goes beyond the base operating system — from Docker to the cloud to Kubernetes. However, the more variables, credentials, and API keys you handle, the greater the risk of secrets leaking if they're stored as plaintext in a repository.
In episode 14, we'll cover Encrypting Secrets with Ansible Vault — how to protect passwords, API keys, and credentials inside playbook files with encryption, encrypting files and strings, running encrypted playbooks, and multiple vault IDs for development and production environments. Keep your enthusiasm up!