Come unificare le attività di installazione del pacchetto in ansible?


68

Sto iniziando con ansible e lo userò, tra gli altri, per installare pacchetti su diverse distribuzioni Linux.

Vedo nei documenti che i comandi yume aptsono separati: quale sarebbe il modo più semplice per unificarli e usare qualcosa del genere:

- name: install the latest version of Apache
  unified_install: name=httpd state=latest

invece di

- 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"

Comprendo che i due gestori di pacchetti sono diversi, ma hanno ancora una serie di usi di base comuni. Altri orchestatori ( ad esempio Salt ) hanno un singolo comando di installazione.


Potresti avere tre ricette: una che scorre su un elenco comune e poi una per elenchi specifici del sistema operativo. Quello che sto cercando di capire in questo momento è come notificare a un gestore con un nome di servizio specifico del sistema operativo dopo aver impostato un elemento di configurazione comune. in bocca al lupo!
dannyman,

Risposte:


66

Aggiornamento: A partire da Ansible 2.0, ora esiste un modulo generico e astrattopackage

Esempi di utilizzo:

Ora, quando il nome del pacchetto è lo stesso in diverse famiglie di sistemi operativi, è semplice come:

---
- name: Install foo
  package: name=foo state=latest

Quando il nome del pacchetto differisce tra le famiglie di sistemi operativi, è possibile gestirlo con file di distribuzione specifici o specifici della famiglia di sistemi operativi:

---
# 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

Quindi, per ciascun sistema operativo che devi gestire in modo diverso ... crea un file VAR:

---
# 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



EDIT: poiché Michael DeHaan (creatore di Ansible) ha scelto di non sottrarre i moduli del gestore pacchetti come fa Chef ,

Se stai ancora utilizzando una versione precedente di Ansible (Ansible <2.0) , sfortunatamente dovrai gestirlo in tutti i tuoi libri di gioco e ruoli. IMHO questo spinge un sacco di lavoro ripetitivo non necessario su playbook e autori di ruoli ... ma è così com'è attualmente. Si noti che non sto dicendo che dovremmo provare a sottrarre gestori di pacchetti mentre proviamo ancora a supportare tutte le loro opzioni e comandi specifici, ma ho solo un modo semplice per installare un pacchetto che è gestore di pacchetti agnostico. Inoltre non sto dicendo che dovremmo saltare tutti su Smart Package Managercarrozzone, ma che una sorta di livello di astrazione dell'installazione del pacchetto nel tuo strumento di gestione della configurazione è molto utile per semplificare i playbook / i libri di cucina multipiattaforma. Il progetto Smart sembra interessante, ma è abbastanza ambizioso unificare la gestione dei pacchetti tra distro e piattaforme senza molta adozione ... sarà interessante vedere se avrà successo. Il vero problema è solo che i nomi dei pacchetti a volte tendono ad essere diversi tra le distribuzioni, quindi dobbiamo ancora fare dichiarazioni di casi o when:dichiarazioni per gestire le differenze.

Il modo in cui ho avuto a che fare è seguire questa tasksstruttura di directory in un playbook o in un ruolo:

roles/foo
└── tasks
    ├── apt_package.yml
    ├── foo.yml
    ├── homebrew_package.yml
    ├── main.yml
    └── yum_package.yml

E poi ho questo nel mio main.yml:

---
# foo: entry point for tasks
#                 Generally only include other file(s) and add tags here.

- include: foo.yml tags=foo

Questo in foo.yml(per il pacchetto 'pippo'):

---
# 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'

Quindi per i diversi gestori di pacchetti:

apt:

---
# 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

yum:

---
# 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

Si noti che questo è terribilmente ripetitivo e non ASCIUTTO , e anche se alcune cose potrebbero essere diverse sulle diverse piattaforme e dovranno essere gestite, generalmente penso che questo sia dettagliato e ingombrante rispetto a quello di 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

E sì, c'è l'argomento che alcuni nomi di pacchetti sono diversi tra le distribuzioni. E anche se al momento mancano dati facilmente accessibili , mi permetto di indovinare che i nomi dei pacchetti più popolari sono comuni in tutte le distribuzioni e potrebbero essere installati tramite un modulo di gestione pacchetti astratto. Casi speciali dovrebbero essere comunque gestiti, e richiederebbero già un lavoro extra per rendere le cose meno ASCIUTTE In caso di dubbi, controllare pkgs.org .


Con Ansible 2 puoi utilizzare il modulo del pacchetto per sottrarre tutto questo docs.ansible.com/ansible/package_module.html
Guido

@ GuidoGarcía: molto bello! Aggiungendo una nota a riguardo per Ansible 2.0
TrinitronX

Forse vale anche la pena ricordare che è possibile specificare un elenco separato da virgole o solo un elenco di pacchetti.
Wes Turner,

13

È possibile estrarre i gestori dei pacchetti tramite i fatti

- name: Install packages
  with_items: package_list
  action: "{{ ansible_pkg_mgr }} state=installed name={{ item }}"

Tutto ciò che serve è una logica impostata ansible_pkg_mgrsu apto yumecc.

Ansible sta anche lavorando per fare quello che vuoi in un modulo futuro .


1
Ansible si imposta ansible_pkg_mgrper qualsiasi packager di cui sia a conoscenza. Non è necessario che tu faccia nulla. Uso questo particolare costrutto ovunque.
Michael Hampton

La sintassi è ancora abbastanza utile per coloro che vogliono ottimizzare la corsa dei loro playbook. Il modulo di pacchetto generico non fornisce ancora l'ottimizzazione per with_items, quindi è molto più lento quando viene utilizzato per installare più pacchetti contemporaneamente.
Danila Vershinin,

@DanielV. Si noti che il problema github fornisce una soluzione alternativa per questo.
Michael Hampton


3

Consulta la documentazione di Ansible sulle importazioni condizionali .

Un'attività per garantire che apache sia in esecuzione anche se i nomi dei servizi sono diversi in ciascun sistema operativo.

---
- 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

2

Non vuoi farlo perché alcuni nomi di pacchetti differiscono tra le distribuzioni. Ad esempio, nelle distribuzioni relative a RHEL viene chiamato il popolare pacchetto del server Web httpd, dove come nelle distribuzioni relative a Debian è chiamato apache2. Allo stesso modo con un vasto elenco di altri sistemi e librerie di supporto.

Potrebbe esserci un insieme di parametri di base comuni, ma poi c'è anche un numero di parametri più avanzati che differiscono tra i gestori di pacchetti. E non vuoi trovarti in una situazione ambigua in cui per alcuni comandi usi una sintassi e per altri comandi usi un'altra sintassi.


Questo è più o meno quello che mi aspettavo (purtroppo :)), quindi mi chiedo come saltriesca a unificare entrambi i gestori di pacchetti. Comunque, farò ricorso a una doppia configurazione, quindi.
WoJ,

O non gestire uno zoo di distribuzione ;-) migrare verso un'infrastruttura a distribuzione singola e vivere una vita più felice.
Mxx

Lo zoo è fortunatamente solo due animali grandi ma questo è il numero più basso a cui posso andare :)
WoJ

1
@Mxx questa è una buona logica per un amministratore di sistema, ma che dire di un fornitore o consulente di software che supporta più piattaforme?
David H. Bennett,

@David, quindi è necessario occuparsene con i distributori distro, affinché abbiano nomi di pacchetti e strumenti di installazione unificati. Realisticamente non è possibile che Ansible possa avere un mapping unificato di TUTTI i pacchetti da tutte le distribuzioni supportate di tutte le versioni.
Mxx,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.