Bagaimana cara menyatukan tugas-tugas instalasi paket dengan memungkinkan?


68

Saya memulai dengan ansible dan akan menggunakannya, antara lain, untuk menginstal paket pada beberapa distro Linux.

Saya melihat dalam dokumen bahwa perintah yumdan aptdipisahkan - apa cara termudah untuk menyatukan mereka dan menggunakan sesuatu seperti ini:

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

dari pada

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

Saya mengerti bahwa kedua manajer paket berbeda, tetapi mereka masih memiliki satu set penggunaan dasar umum. Orkestator lain ( misalnya garam ) memiliki perintah instal tunggal.


Anda dapat memiliki tiga resep: satu yang diulang pada daftar yang umum dan kemudian masing-masing untuk daftar yang spesifik untuk OS. Yang saya coba cari tahu sekarang adalah bagaimana memberi tahu penangan dengan nama layanan khusus-OS setelah item konfigurasi umum ditetapkan. semoga berhasil!
dannyman

Jawaban:


66

Pembaruan: Pada Ansible 2.0, sekarang ada modul generik & abstrakpackage

Contoh Penggunaan:

Sekarang ketika nama paket sama di berbagai keluarga OS, itu sesederhana:

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

Ketika nama paket berbeda di seluruh keluarga OS, Anda dapat mengatasinya dengan distribusi atau file vars khusus keluarga OS:

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

Kemudian, untuk setiap OS yang harus Anda tangani secara berbeda ... buat file 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



EDIT: Karena Michael DeHaan (pencipta Ansible) telah memilih untuk tidak mencabut modul manajer paket seperti yang dilakukan Chef ,

Jika Anda masih menggunakan versi Ansible yang lebih lama (Ansible <2.0) , sayangnya Anda harus menangani hal ini di semua buku pedoman dan peran Anda. IMHO ini mendorong banyak pekerjaan berulang yang tidak perlu ke playbook & penulis peran ... tapi begitulah adanya. Perhatikan bahwa saya tidak mengatakan kita harus mencoba untuk mengabstraksikan manajer paket pergi sambil tetap mencoba untuk mendukung semua opsi dan perintah khusus mereka, tetapi hanya memiliki cara mudah untuk menginstal paket yang agnostik paket manajer. Saya juga tidak mengatakan bahwa kita semua harus menggunakan Smart Package Managerikut-ikutan, tetapi semacam lapisan abstraksi instalasi paket di alat manajemen konfigurasi Anda sangat berguna untuk menyederhanakan buku pedoman / buku resep lintas platform. Proyek Smart terlihat menarik, tetapi cukup ambisius untuk menyatukan manajemen paket di seluruh distro dan platform tanpa banyak adopsi ... itu akan menarik untuk melihat apakah itu berhasil. Masalah sebenarnya adalah hanya bahwa nama paket kadang-kadang cenderung berbeda di seluruh distro, jadi kita masih harus melakukan pernyataan kasus atau when:pernyataan untuk menangani perbedaan.

Cara saya menghadapinya adalah dengan mengikuti tasksstruktur direktori ini di buku pedoman atau peran:

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

Dan kemudian memilikinya di main.yml:

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

- include: foo.yml tags=foo

Ini dalam foo.yml(untuk paket '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'

Kemudian untuk manajer paket yang berbeda:

Tepat:

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

Perhatikan bahwa ini sangat berulang dan bukan KERING , dan meskipun beberapa hal mungkin berbeda pada platform yang berbeda dan harus ditangani, secara umum saya pikir ini verbose dan berat jika dibandingkan dengan 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

Dan ya, ada argumen bahwa beberapa nama paket berbeda di seluruh distro. Dan meskipun saat ini ada kekurangan data yang mudah diakses , saya berani menebak bahwa sebagian besar nama paket populer adalah umum di seluruh distro dan dapat diinstal melalui modul manajer paket abstrak. Kasus-kasus khusus perlu ditangani, dan sudah membutuhkan kerja ekstra membuat segalanya kurang KERING. Jika ragu, periksa pkgs.org .


Dengan Ansible 2 Anda dapat menggunakan modul paket untuk mengabstraksi semua dokumen ini.ansible.com/ansible/package_module.html
Guido

@ GuidoGarcía: Bagus sekali! Menambahkan catatan tentang ini untuk Ansible 2.0
TrinitronX

Mungkin juga layak disebutkan bahwa Anda dapat menentukan daftar yang dipisahkan koma atau hanya daftar paket.
Wes Turner

13

Anda dapat mengabstraksi manajer paket melalui fakta

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

Yang Anda butuhkan adalah beberapa logika yang menetapkan ansible_pkg_mgruntuk aptatau yumdll

Ansible juga berusaha melakukan apa yang Anda inginkan dalam modul mendatang .


1
Ansible mengatur ansible_pkg_mgrsendiri untuk setiap paket yang diketahuinya. Tidak perlu bagi Anda untuk melakukan apa pun. Saya menggunakan konstruksi khusus ini di mana-mana.
Michael Hampton

Sintaksnya masih cukup berguna bagi mereka yang ingin mengoptimalkan menjalankan buku pedoman mereka. Modul paket generik belum menyediakan optimasi untuk with_items sehingga jauh lebih lambat ketika digunakan untuk menginstal beberapa paket sekaligus.
Danila Vershinin

@DanielV. Perhatikan bahwa masalah github memang memberikan solusi untuk itu.
Michael Hampton


3

Lihat dokumentasi Ansible tentang Impor Bersyarat .

Satu tugas untuk memastikan apache berjalan bahkan jika nama layanan berbeda di setiap OS.

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

Anda tidak ingin melakukan itu karena nama paket tertentu berbeda di antara distro. Misalnya pada distro yang berhubungan dengan RHEL, paket server web populer dinamai httpd, sedangkan pada distro yang berhubungan dengan Debian namanya apache2. Demikian pula dengan daftar besar sistem lain dan perpustakaan pendukung.

Mungkin ada satu set parameter dasar umum, tetapi kemudian ada juga beberapa parameter lebih lanjut yang berbeda antara manajer paket. Dan Anda tidak ingin berada dalam situasi yang ambigu di mana untuk beberapa perintah Anda menggunakan satu sintaks dan untuk perintah lain Anda menggunakan sintaks lain.


Ini kurang lebih seperti yang saya harapkan (sayangnya :)) jadi saya bertanya-tanya bagaimana saltmengelola untuk menyatukan kedua manajer paket. Bagaimanapun, saya akan menggunakan konfigurasi ganda, kalau begitu.
WoJ

Atau jangan mengelola kebun binatang distro ;-) bermigrasi ke infrastruktur satu-distro dan hidup lebih bahagia.
Mxx

Untungnya kebun binatang itu hanya dua hewan besar tetapi ini adalah angka terendah yang bisa saya tuju :)
WoJ

1
@ XXX itu logika yang bagus untuk sysadmin tetapi bagaimana dengan vendor perangkat lunak atau konsultan yang mendukung banyak platform?
David H. Bennett

@ David, maka ini harus diambil dengan vendor distro, agar mereka memiliki nama paket yang sama dan menginstal alat. Secara realistis tidak mungkin Ansible dapat memiliki pemetaan terpadu paket SEMUA dari semua distro yang didukung dari semua versi.
Mxx
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.