Ansible でパッケージインストールタスクを統合するにはどうすればよいですか?

Ansible でパッケージインストールタスクを統合するにはどうすればよいですか?

私はまずアンシブルそして、これを他のツールとともに、いくつかの Linux ディストリビューションにパッケージをインストールするために使用します。

ドキュメントでは、yumaptコマンドが分離されていることがわかります。これらを統合して、次のようなものを使用する最も簡単な方法は何でしょうか。

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

2つのパッケージマネージャは異なることは理解していますが、それでも共通の基本的な使用法があります。他のオーケストレータ(例えば塩) には、単一のインストール コマンドがあります。

答え1

更新: Ansible 2.0では、汎用的で抽象化されたpackageモジュール

使用例:

パッケージ名が異なる OS ファミリ間で同じである場合は、次のように簡単です。

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

パッケージ名が OS ファミリ間で異なる場合は、ディストリビューションまたは OS ファミリ固有の 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

次に、別々に処理する必要がある OS ごとに、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の作者)以来パッケージマネージャモジュールを抽象化しないことを選択したのようにシェフする、

Ansibleの古いバージョン(Ansible < 2.0)をまだ使用している場合残念ながら、これを処理する必要があります全てプレイブックとロールの詳細。 私見ではこれにより、プレイブックとロールの作成者に多くの不要な反復作業が押し付けられますが、これが現状です。パッケージマネージャーを抽象化して、その特定のオプションとコマンドをすべてサポートしようとするのではなく、パッケージマネージャーに依存しないパッケージを簡単にインストールする方法を用意する必要があると言っているわけではありません。スマートパッケージマネージャー流行に流されるのではなく、構成管理ツールに何らかのパッケージ インストール抽象化レイヤーがあると、クロスプラットフォームのプレイブックやクックブックを簡素化するのに非常に便利です。Smart プロジェクトは興味深いものですが、まだあまり採用されていないディストリビューションやプラットフォーム間でパッケージ管理を統一するという非常に野心的なプロジェクトです...成功するかどうかは興味深いところです。実際の問題は、パッケージ名がディストリビューション間で異なる傾向があるため、when:違いを処理するために case ステートメントやステートメントを実行する必要があることです。

私が対処してきた方法は、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

おいしい:

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

自家製:

---
- name: Tap homebrew foobar/foo
  homebrew_tap: >
    name=foobar/foo
    state=present

- homebrew: >
    name=foo
    state=latest

これは非常に繰り返しが多く、ドライ、そしていくつかのことはかもしれないプラットフォームによって異なるため、処理する必要がありますが、一般的に、これは 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

そして確かに、いくつかのパッケージ名はディストリビューションによって異なります。また、現在は簡単にアクセスできるデータの欠如、私は推測するにほとんど人気のあるパッケージ名はディストリビューション間で共通しており、抽象化されたパッケージマネージャモジュールを介してインストールできます。特殊なケースはいずれにせよ処理する必要があり、余分な作業が必要になるため、DRY性が低下します。疑わしい場合は、翻訳元

答え2

ファクトを介してパッケージマネージャを抽象化できます

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

必要なのは、 またはなどansible_pkg_mgrを設定するロジックだけです。aptyum

アンシブル将来のモジュールでやりたいことをやろうとしている

答え3

Ansible 2.0 からは新しいPackage-modul が追加されました。

パッケージモジュール

これを提案のように使用できます。

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

名前の違いも考慮する必要があります。

答え4

特定のパッケージ名はディストリビューション間で異なるため、これを実行することは望ましくありません。たとえば、RHEL 関連のディストリビューションでは、一般的な Web サーバー パッケージの名前は ですhttpdが、Debian 関連のディストリビューションでは ですapache2。他のシステム ライブラリやサポート ライブラリの膨大なリストについても同様です。

共通の基本パラメータのセットがあるかもしれませんが、パッケージ マネージャー間で異なる、より高度なパラメータも多数あります。また、一部のコマンドでは 1 つの構文を使用し、他のコマンドでは別の構文を使用するというあいまいな状況は避けたいものです。

関連情報