Как унифицировать задачи по установке пакетов в ansible?

68

Я начинаю с ansible и буду использовать его, в частности, для установки пакетов в нескольких дистрибутивах Linux.

Я вижу в документации , что yumи aptкоманды разделены - то , что было бы самым простым способом , чтобы объединить их и использовать что - то вроде этого:

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

вместо

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

Я понимаю, что эти два менеджера пакетов различны, но у них все еще есть общий набор основных способов использования. Другие оркестаторы ( например, соль ) имеют одну команду установки.

WOJ
источник
У вас может быть три рецепта: один, который перебирает общий список, а затем по одному для списков, специфичных для ОС. Сейчас я пытаюсь выяснить, как уведомить обработчик с помощью специфичного для ОС имени службы после установки общего элемента конфигурации. удачи!
Дэнниман

Ответы:

66

Обновление: Начиная с Ansible 2.0, теперь есть универсальный и абстрагированный packageмодуль

Примеры использования:

Теперь, когда имя пакета одинаково для разных семейств ОС, это так просто:

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

Если имя пакета в разных семействах ОС различается, вы можете обработать его с помощью файлов vars для дистрибутива или семейства ОС:

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

Затем для каждой ОС, которую вы должны обрабатывать по-разному ... создайте файл 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



РЕДАКТИРОВАТЬ: поскольку Майкл ДеХан (создатель Ansible) решил не абстрагировать модули менеджера пакетов, как это делает Chef ,

Если вы все еще используете более старую версию Ansible (Ansible <2.0) , к сожалению, вам придется справиться с этим во всех своих книгах и ролях. ИМХО, это толкает много ненужных повторяющихся работ на авторов книг и ролей ... но так оно и есть в настоящее время. Обратите внимание, что я не говорю, что мы должны пытаться абстрагировать менеджеров пакетов, все еще пытаясь поддерживать все их специфические опции и команды, а просто иметь простой способ установить пакет, который не зависит от менеджера пакетов. Я также не говорю, что мы все должны перейти на Smart Package Managerно это своего рода уровень абстракции установки пакетов в вашем инструменте управления конфигурацией очень полезен для упрощения кроссплатформенных сборников / поваренных книг. Проект Smart выглядит интересно, но довольно амбициозно объединить управление пакетами на всех дистрибутивах и платформах без особого принятия ... покажем, будет ли он успешным. Реальная проблема заключается в том, что имена пакетов иногда имеют тенденцию быть разными в разных дистрибутивах, поэтому нам по-прежнему приходится делать операторы case или when:операторы для обработки различий.

Способ, которым я имел дело с этим, состоит в том, чтобы следовать этой tasksструктуре каталогов в книге или роли:

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

И тогда есть это в моем main.yml:

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

- include: foo.yml tags=foo

Это в foo.yml(для пакета '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'

Тогда для разных менеджеров пакетов:

Апт:

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

Обратите внимание, что это ужасно повторяющееся и не СУХОЕ , и хотя некоторые вещи могут отличаться на разных платформах и должны быть обработаны, в общем, я думаю, что это многословно и громоздко по сравнению с шеф-поварами:

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

И да, есть аргумент, что некоторые имена пакетов различаются в разных дистрибутивах. И хотя в настоящее время не хватает легко доступных данных , я бы рискнул предположить, что наиболее популярные имена пакетов распространены в дистрибутивах и могут быть установлены через абстрагированный модуль менеджера пакетов. Особые случаи должны быть обработаны в любом случае, и уже потребуют дополнительной работы, чтобы сделать вещи менее сухими . В случае сомнений, проверьте pkgs.org .

TrinitronX
источник
В Ansible 2 вы можете использовать модуль пакета, чтобы абстрагировать все это docs.ansible.com/ansible/package_module.html
Guido,
@ GuidoGarcía: Очень приятно! Добавление примечания об этом для Ansible 2.0
TrinitronX
Возможно также стоит упомянуть, что вы можете указать список через запятую или просто список пакетов.
Уэс Тернер
13

Вы можете абстрагировать менеджеров пакетов через факты

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

Все , что вам нужно , это какая - то логика , которая устанавливает ansible_pkg_mgrдля aptили yumт.п.

Ansible также работает над тем, что вы хотите в будущем модуле .

xddsg
источник
1
Ansible устанавливает ansible_pkg_mgrсебя для любого упаковщика, о котором он знает. Вам не нужно ничего делать. Я использую эту конкретную конструкцию везде.
Майкл Хэмптон
Синтаксис все еще весьма полезен для тех, кто хочет оптимизировать работу своих сборников. Модуль универсального пакета еще не обеспечивает оптимизацию with_items, поэтому он намного медленнее, когда используется для установки нескольких пакетов одновременно.
Данила Вершинин
@DanielV. Обратите внимание, что проблема GitHub предоставляет обходной путь для этого.
Майкл Хэмптон
6

Из Ansible 2.0 есть новый Package-modul.

http://docs.ansible.com/ansible/package_module.html

Затем вы можете использовать его как ваше предложение:

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

Вы все еще должны рассмотреть различия имен.

Tvartom
источник
3

Ознакомьтесь с документацией Ansible об условном импорте .

Одна задача - убедиться, что apache работает, даже если имена служб различны в разных ОС.

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

Вы не хотите этого делать, потому что определенные имена пакетов различаются в разных дистрибутивах. Например, в дистрибутивах, связанных с RHEL, популярный пакет веб-сервера называется так httpd, как в дистрибутивах, связанных с Debian, он называется apache2. Аналогично с огромным списком других системных и вспомогательных библиотек.

Может быть набор общих базовых параметров, но есть также ряд более сложных параметров, которые различаются между менеджерами пакетов. И вы не хотите быть в неоднозначной ситуации, когда для некоторых команд вы используете один синтаксис, а для других команд вы используете другой синтаксис.

Mxx
источник
Это более или менее то, что я ожидал (к сожалению :)), поэтому мне интересно, как saltудается объединить оба менеджера пакетов. В любом случае, я прибегну к двойной конфигурации.
WoJ
Или не управляйте зоопарком дистрибутива ;-) переходите на инфраструктуру одного дистрибутива и живите счастливой жизнью.
Mxx
В зоопарке, к счастью, всего два животных, но это самое
маленькое
1
@Mxx это хорошая логика для системного администратора, но как насчет поставщика программного обеспечения или консультанта, который поддерживает несколько платформ?
Дэвид Х. Беннетт
@ Давид, тогда это нужно обсудить с поставщиками дистрибутивов, чтобы они имели унифицированные имена пакетов и инструменты для установки. Реально не существует способа, чтобы Ansible мог иметь унифицированное отображение ВСЕХ пакетов из всех поддерживаемых дистрибутивов всех версий.
Mxx