Je commence par ansible et je l'utiliserai, entre autres, pour installer des packages sur plusieurs distributions Linux.
Je vois dans la documentation que les commandes yum
et apt
sont séparées - quelle serait la façon la plus simple de les unifier et d'utiliser quelque chose comme ceci:
- name: install the latest version of Apache
unified_install: name=httpd state=latest
au lieu de
- name: install the latest version of Apache on CentOS
yum: name=httpd state=latest
when: ansible_os_family == "RedHat"
- name: install the latest version of Apache on Debian
apt: pkg=httpd state=latest
when: ansible_os_family == "Debian"
Je comprends que les deux gestionnaires de packages sont différents, mais ils ont toujours un ensemble d'utilisations de base communes. D'autres orchestrateurs ( sel par exemple ) ont une seule commande d'installation.
package
moduleMaintenant, lorsque le nom du package est le même dans différentes familles de systèmes d'exploitation, c'est aussi simple que:
---
- name: Install foo
package: name=foo state=latest
Lorsque le nom du package diffère selon les familles de systèmes d'exploitation, vous pouvez le gérer avec des fichiers vars spécifiques à la distribution ou à la famille de systèmes d'exploitation:
---
# roles/Apache/apache.yml: Tasks entry point for 'Apache' role. Called by main.yml
# Load a variable file based on the OS type, or a default if not found.
- include_vars: "{{ item }}"
with_first_found:
- "../vars/{{ ansible_distribution }}-{{ ansible_distribution_major_version | int}}.yml"
- "../vars/{{ ansible_distribution }}.yml"
- "../vars/{{ ansible_os_family }}.yml"
- "../vars/default.yml"
when: Apache_package_name is not defined or Apache_service_name is not defined
- name: Install Apache
package: >
name={{ Apache_package_name }}
state=latest
- name: Enable Apache service
service: >
name={{ Apache_service_name }}
state=started
enabled=yes
tags: packages
Ensuite, pour chaque OS que vous devez gérer différemment ... créez un fichier vars:
---
# roles/Apache/vars/default.yml
Apache_package_name: Apache2
Apache_service_name: Apache2
---
# roles/Apache/vars/RedHat.yml
Apache_package_name: httpd
Apache_service_name: httpd
---
# roles/Apache/vars/SLES.yml
Apache_package_name: Apache2
Apache_service_name: Apache2
---
# roles/Apache/vars/Debian.yml
Apache_package_name: Apache2
Apache_service_name: Apache2
---
# roles/Apache/vars/Archlinux.yml
Apache_package_name: Apache
apache_service_name: httpd
MODIFIER: Depuis Michael DeHaan (créateur d'Ansible) a choisi de ne pas faire abstraction des modules du gestionnaire de paquets comme Chef le fait,
Si vous utilisez toujours une ancienne version d'Ansible (Ansible <2.0), malheureusement, vous devrez gérer faire cela dans tous de vos playbooks et rôles. [~ # ~] imho [~ # ~] cela pousse beaucoup de travaux répétitifs inutiles sur les auteurs de livres et de rôles ... mais c'est comme ça actuellement. Notez que je ne dis pas que nous devrions essayer d'abstraire les gestionnaires de packages tout en essayant de prendre en charge toutes leurs options et commandes spécifiques, mais simplement d'avoir un moyen facile d'installer un package qui est indépendant du gestionnaire de packages. Je ne dis pas non plus que nous devrions tous sauter sur le mouvement Smart Package Manager , mais qu'une sorte de couche d'abstraction d'installation de package dans votre outil de gestion de la configuration est très utile pour simplifier les livres de lecture/livres de recettes multiplateformes. . Le projet Smart semble intéressant, mais il est assez ambitieux d'unifier la gestion des packages sur les distributions et les plates-formes sans beaucoup d'adoption pour le moment ... il sera intéressant de voir s'il réussit. Le vrai problème est simplement que les noms de packages ont parfois tendance à être différents d'une distribution à l'autre, nous devons donc toujours faire des déclarations de cas ou when:
instructions pour gérer les différences.
La façon dont je l'ai traité est de suivre cette structure de répertoire tasks
dans un playbook ou un rôle:
roles/foo
└── tasks
├── apt_package.yml
├── foo.yml
├── homebrew_package.yml
├── main.yml
└── yum_package.yml
Et puis avoir ceci dans mon main.yml
:
---
# foo: entry point for tasks
# Generally only include other file(s) and add tags here.
- include: foo.yml tags=foo
En ce foo.yml
(pour le paquet 'foo'):
---
# foo: Tasks entry point. Called by main.yml
- include: apt_package.yml
when: ansible_pkg_mgr == 'apt'
- include: yum_package.yml
when: ansible_pkg_mgr == 'yum'
- include: homebrew_package.yml
when: ansible_os_family == 'Darwin'
- name: Enable foo service
service: >
name=foo
state=started
enabled=yes
tags: packages
when: ansible_os_family != 'Darwin'
Ensuite pour les différents gestionnaires de packages:
App:
---
# tasks file for installing foo on apt based distros
- name: Install foo package via apt
apt: >
name=foo{% if foo_version is defined %}={{ foo_version }}{% endif %}
state={% if foo_install_latest is defined and foo_version is not defined %}latest{% else %}present{% endif %}
tags: packages
Miam:
---
# tasks file for installing foo on yum based distros
- name: Install EPEL 6.8 repos (...because it's RedHat and foo is in EPEL for example purposes...)
yum: >
name={{ docker_yum_repo_url }}
state=present
tags: packages
when: ansible_os_family == "RedHat" and ansible_distribution_major_version|int == 6
- name: Install foo package via yum
yum: >
name=foo{% if foo_version is defined %}-{{ foo_version }}{% endif %}
state={% if foo_install_latest is defined and foo_version is not defined %}latest{% else %}present{% endif %}
tags: packages
- name: Install RedHat/yum-based distro specific stuff...
yum: >
name=some-other-custom-dependency-on-redhat
state=latest
when: ansible_os_family == "RedHat"
tags: packages
Homebrew:
---
- name: Tap homebrew foobar/foo
homebrew_tap: >
name=foobar/foo
state=present
- homebrew: >
name=foo
state=latest
Notez que cela est terriblement répétitif et non DRY , et bien que certaines choses pourraient être différentes sur les différentes plates-formes et devront être gérées, généralement je pense que c'est verbeux et lourd par rapport à Chef:
package 'foo' do
version node['foo']['version']
end
case node["platform"]
when "debian", "ubuntu"
# do debian/ubuntu things
when "redhat", "centos", "Fedora"
# do redhat/centos/Fedora things
end
Et oui, il y a l'argument selon lequel certains les noms de package sont différents d'une distribution à l'autre. Et bien qu'il existe actuellement un manque de données facilement accessibles , je me risquerais à deviner que la plupart des noms de paquets populaires sont communs à travers les distributions et pourrait être installé via un module de gestionnaire de paquets abstrait. Les cas spéciaux devraient de toute façon être traités et nécessiteraient déjà un travail supplémentaire, ce qui réduirait les risques de D.R.Y. En cas de doute, vérifiez pkgs.org .
Vous pouvez résumer les gestionnaires de packages via des faits
- name: Install packages
with_items: package_list
action: "{{ ansible_pkg_mgr }} state=installed name={{ item }}"
Tout ce dont vous avez besoin est d'une logique qui définit ansible_pkg_mgr
à apt
ou yum
etc.
Ansible travaille également à faire ce que vous voulez dans un futur module .
Depuis Ansible 2.0, il y a le nouveau module Package
-
http://docs.ansible.com/ansible/package_module.html
Vous pouvez ensuite l'utiliser comme votre proposition:
- name: install the latest version of Apache
package: name=httpd state=latest
Vous devez toujours tenir compte des différences de nom.
Consultez la documentation d'Ansible sur Importations conditionnelles .
Une tâche pour vous assurer qu'Apache est en cours d'exécution même si les noms de service sont différents sur chaque système d'exploitation.
---
- hosts: all
remote_user: root
vars_files:
- "vars/common.yml"
- [ "vars/{{ ansible_os_family }}.yml", "vars/os_defaults.yml" ]
tasks:
- name: make sure Apache is running
service: name={{ Apache }} state=running
Vous ne voulez pas le faire car certains noms de packages diffèrent entre les distributions. Par exemple, sur les distributions liées à RHEL, le package de serveur Web populaire est nommé httpd
, tandis que, comme sur les distributions liées à Debian, il est nommé Apache2
. De même avec une énorme liste d'autres systèmes et bibliothèques de support.
Il peut y avoir un ensemble de paramètres de base communs, mais il y a aussi un certain nombre de paramètres plus avancés qui sont différents entre les gestionnaires de packages. Et vous ne voulez pas être dans une situation ambiguë où pour certaines commandes vous utilisez une syntaxe et pour d'autres commandes vous utilisez une autre syntaxe.