
Créer sa propre collection est l’aboutissement du parcours collections : packager plusieurs ressources (modules Python custom + rôles + plugins + playbooks) sous un même namespace versionné, distribuable sur Galaxy ou Automation Hub privé. Cette page construit pas à pas une collection minimaliste avec un module Python qui retourne Hello, valide le tout avec ansible-test sanity --docker default, et produit un tarball publiable.
À la fin, vous saurez initialiser une collection conforme, écrire un module Python avec ses 3 sections obligatoires (DOCUMENTATION, EXAMPLES, RETURN), builder un tarball semver, et exécuter la batterie de validations pré-publication.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »ansible-galaxy collection init: générer la structure standard.- Remplir
galaxy.yml: namespace, name, version, dependencies,tags:obligatoires. - Remplir
meta/runtime.yml:requires_ansible:+plugin_routing:. - Écrire un module Python avec
DOCUMENTATION + EXAMPLES + RETURN+AnsibleModule. - Ajouter un rôle dans
roles/<name>/. ansible-galaxy collection build: produire le tarball.ansible-test sanity --docker: validation pré-publication.
Prérequis
Section intitulée « Prérequis »- Avoir lu Découvrir et requirements.yml.
ansible-test --versionretourne au moins2.18.x.- Docker ou Podman pour
--docker.
Étape 1 — Initialiser la structure
Section intitulée « Étape 1 — Initialiser la structure »mkdir -p ansible_collectionsansible-galaxy collection init student.webapp \ --init-path ansible_collections/Sortie :
- Collection student.webapp was created successfullyStructure générée :
Répertoireansible_collections/student/webapp/
- galaxy.yml
- README.md
- LICENSE
Répertoiremeta/
- runtime.yml
Répertoireplugins/
Répertoiremodules/
- …
Répertoirefilter/
- …
Répertoirelookup/
- …
Répertoireinventory/
- …
Répertoiremodule_utils/
- …
Répertoireroles/
- …
Répertoireplaybooks/
- …
Répertoiretests/
- …
Répertoirechangelogs/
- …
Répertoiredocs/
- …
🔍 Observation : init génère toute la structure conforme d’une collection. Pas besoin de tout remplir : ne garder que ce dont on a besoin (les dossiers vides ne posent pas de problème).
Étape 2 — Remplir galaxy.yml
Section intitulée « Étape 2 — Remplir galaxy.yml »namespace: studentname: webappversion: 1.0.0readme: README.mdauthors: - "Apprenant RHCE 2026 <student@example.com>"description: "Collection lab — déploie webapp avec nginx"license: - GPL-3.0-or-latertags: # ← OBLIGATOIRE pour Galaxy - linux - web - nginxdependencies: ansible.posix: ">=2.0.0"repository: https://github.com/student/webappdocumentation: https://github.com/student/webappissues: https://github.com/student/webapp/issuesbuild_ignore: - .github - .venv - tests/output🔍 Observation cruciale : tags: est obligatoire pour publier sur Galaxy. Sans, l’import échoue silencieusement avec un message peu explicite. dependencies: déclare les autres collections requises avec contraintes semver.
Étape 3 — Remplir meta/runtime.yml
Section intitulée « Étape 3 — Remplir meta/runtime.yml »---requires_ansible: ">=2.18.0"
# Optionnel : redirects pour les modules renommés (cf migration role)# plugin_routing:# modules:# old_module:# redirect: student.webapp.new_module🔍 Observation : requires_ansible: est obligatoire dès qu’on a un module Python. Sans, ansible-test sanity échoue avec ERROR! No requires_ansible declared.
Étape 4 — Ajouter un module Python custom
Section intitulée « Étape 4 — Ajouter un module Python custom »plugins/modules/webapp_healthcheck.py :
#!/usr/bin/python# -*- coding: utf-8 -*-
from __future__ import absolute_import, division, print_function
__metaclass__ = type
DOCUMENTATION = r'''---module: webapp_healthcheckshort_description: Health check minimaliste d'une URL HTTPversion_added: "1.0.0"description: - Vérifie qu'une URL HTTP répond avec un code 200.options: url: description: URL à tester. required: true type: strauthor: - "Apprenant RHCE 2026"'''
EXAMPLES = r'''- name: Vérifier que nginx répond student.webapp.webapp_healthcheck: url: "http://localhost:80"'''
RETURN = r'''status_code: description: Code HTTP retourné. type: int returned: always'''
import urllib.requestfrom ansible.module_utils.basic import AnsibleModule
def run_module(): module_args = dict(url=dict(type='str', required=True)) module = AnsibleModule(argument_spec=module_args, supports_check_mode=True)
url = module.params['url'] try: with urllib.request.urlopen(url, timeout=5) as response: code = response.getcode() module.exit_json(changed=False, status_code=code) except Exception as exc: module.fail_json(msg=f"Health check KO: {exc}")
def main(): run_module()
if __name__ == '__main__': main()🔍 Observation : tous les modules Python suivent ce squelette. Les 3 sections DOCUMENTATION, EXAMPLES, RETURN sont obligatoires pour ansible-test sanity. AnsibleModule + argument_spec sécurise les paramètres + supporte check_mode.
Étape 5 — Ajouter un rôle
Section intitulée « Étape 5 — Ajouter un rôle »roles/nginx/tasks/main.yml :
---- name: Installer nginx ansible.builtin.dnf: name: nginx state: present
- name: Activer et démarrer nginx ansible.builtin.systemd_service: name: nginx state: started enabled: true🔍 Observation : un rôle dans une collection suit la même structure qu’un rôle standalone. La différence : on l’utilise avec son FQCN : student.webapp.nginx.
Étape 6 — Ajouter un playbook d’orchestration
Section intitulée « Étape 6 — Ajouter un playbook d’orchestration »playbooks/deploy.yml :
---- name: Déployer la webapp avec la collection student.webapp hosts: webservers become: true tasks: - name: Appliquer le rôle nginx ansible.builtin.import_role: name: student.webapp.nginx # FQCN du rôle
- name: Health check via le module custom student.webapp.webapp_healthcheck: # FQCN du module url: "http://localhost:80" register: hc
- ansible.builtin.debug: var: hc.status_code🔍 Observation : depuis l’extérieur de la collection, on appelle modules et rôles avec leur FQCN complet. À l’intérieur de la collection, on peut utiliser des noms courts (mais déconseillé pour la lisibilité).
Étape 7 — Builder la collection
Section intitulée « Étape 7 — Builder la collection »cd ansible_collections/student/webapp/ansible-galaxy collection build --output-path ../../../build/Sortie :
Created collection for student.webapp at /home/.../build/student-webapp-1.0.0.tar.gz🔍 Observation : le tarball est publiable avec ansible-galaxy collection publish <tarball> --token "$GALAXY_TOKEN". Versions automatiques via CI : tag Git v1.0.0 → workflow build → publish.
Étape 8 — Lancer ansible-test sanity
Section intitulée « Étape 8 — Lancer ansible-test sanity »cd ansible_collections/student/webapp/ansible-test sanity --docker default -vCible attendue :
Running sanity test "ansible-doc"Running sanity test "validate-modules"Running sanity test "yamllint"Running sanity test "pep8"...All sanity tests passed.🔍 Observation : --docker default lance la batterie de validations dans un conteneur Docker : doc YAML cohérente, types Python, FQCN, PEP8, yamllint. Indispensable en CI avant publication. Sans, l’import Galaxy échoue silencieusement.
Publier sur Galaxy
Section intitulée « Publier sur Galaxy »# Token API depuis https://galaxy.ansible.com/me/preferencesansible-galaxy collection publish \ ../../../build/student-webapp-1.0.0.tar.gz \ --token "$GALAXY_TOKEN"Workflow d’import sur Galaxy NG (backend Galaxy v3, 2026) :
- Upload : tarball reçu par Galaxy.
- Unpack : extraction et validation du
MANIFEST.json. - Sanity scan : vérification automatique du
galaxy.yml(tags, version, namespace). - Tests CI :
ansible-test sanityexécuté sur les serveurs Galaxy (Galaxy NG le fait depuis 2024). - Import dans
staging: version visible mais pas listée publique. - Approval (manuel ou auto selon namespace) → publication dans
published.
Lab pratique
Section intitulée « Lab pratique »Le lab collections/creer-custom (labs/collections/creer-custom/) reproduit ce parcours avec 9 tests pytest structurels (galaxy.yml conforme, module avec sections obligatoires, tarball buildé). Le lab jumeau dans student.rhce.webapp ajoute un rôle nginx et un module webapp_healthcheck complet.
À retenir
Section intitulée « À retenir »ansible-galaxy collection init namespace.namegénère la structure conforme.galaxy.yml: namespace, name, version semver,tags:obligatoire, dependencies.meta/runtime.yml:requires_ansible:obligatoire dès qu’on a un module Python.- Module Python :
DOCUMENTATION+EXAMPLES+RETURNen YAML +AnsibleModule. - FQCN depuis l’extérieur :
namespace.collection.plugin. ansible-galaxy collection buildproduit un tarball publiable.ansible-test sanity --docker defaultvalide doc + types + FQCN + PEP8.