Как унифицировать задачи по установке пакетов в 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"

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


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

Ответы:


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 .


В 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 также работает над тем, что вы хотите в будущем модуле .


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

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


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. Аналогично с огромным списком других системных и вспомогательных библиотек.

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


Это более или менее то, что я ожидал (к сожалению :)), поэтому мне интересно, как saltудается объединить оба менеджера пакетов. В любом случае, я прибегну к двойной конфигурации.
— WoJ

Или не управляйте зоопарком дистрибутива ;-) переходите на инфраструктуру одного дистрибутива и живите счастливой жизнью.
— Mxx

В зоопарке, к счастью, всего два животных, но это самое
— маленькое

1
@Mxx это хорошая логика для системного администратора, но как насчет поставщика программного обеспечения или консультанта, который поддерживает несколько платформ?
— Дэвид Х. Беннетт

@ Давид, тогда это нужно обсудить с поставщиками дистрибутивов, чтобы они имели унифицированные имена пакетов и инструменты для установки. Реально не существует способа, чтобы Ansible мог иметь унифицированное отображение ВСЕХ пакетов из всех поддерживаемых дистрибутивов всех версий.
— Mxx
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.