ansibleでパッケージインストールタスクを統合する方法は?


68

私は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つのパッケージマネージャーは異なることを理解していますが、まだ一般的な基本的な使用法のセットがあります。他のオーケストレーター(たとえばsalt)には単一のインストールコマンドがあります。


3つのレシピを用意できます。1つは共通リストを反復処理し、次にOS固有のリストに対して1つです。私が今理解しようとしているのは、共通の構成アイテムが設定された後にOS固有のサービス名でハンドラーに通知する方法です。幸運を!
ダニーマン14年

回答:


66

更新: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



編集: Michael DeHaan(Ansibleの作成者)は、Chefのようにパッケージマネージャーモジュールを抽象化しないことを選択したため

まだ古いバージョンのAnsible(Ansible <2.0)を使用している場合、残念ながらすべてのプレイブックとロールでこれを処理する必要があります。 私見では、これは多くの不必要な反復作業をプレイブックとロールの作者に押し付けます...しかし、それは現在のやり方です。特定のオプションとコマンドのすべてをサポートしようとしながら、パッケージマネージャーを抽象化しようとするのではなく、パッケージマネージャーに依存しないパッケージをインストールする簡単な方法があるだけです。スマートパッケージマネージャーにジャンプする必要があると言っているわけでもありませんただし、構成管理ツールのパッケージインストール抽象化レイヤーは、クロスプラットフォームのプレイブック/クックブックを簡素化するのに非常に役立ちます。スマートプロジェクトは面白そうに見えますが、まだ採用されていないディストリビューションとプラットフォーム間でパッケージ管理を統一することは非常に野心的です...成功するかどうかは興味深いでしょう。本当の問題は、ディストリビューション間でパッケージ名が異なる場合があるため、ケースステートメントまたは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'

次に、さまざまなパッケージマネージャーについて:

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

ヤム:

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

これはDRYではなくひどく反復的であり、プラットフォームによって異なる場合があり、処理する必要があるかもしれませんが、一般的に、これは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を少なくするためにすでに余分な作業が必要になります。疑わしい場合はpkgs.orgを確認してください


Ansible 2を使用すると、抽象的にすべてこのパッケージのモジュールを使用することができますdocs.ansible.com/ansible/package_module.html
グイド

@GuidoGarcía:いいね!Ansible 2.0についてこれに関するメモを追加
TrinitronX

また、コンマ区切りリストまたはパッケージのリストのみを指定できることにも言及する価値があります。
ウェスターナー

13

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

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

必要なのはansible_pkg_mgraptまたはyumなどに設定するロジックです。

Ansible はまた、将来のモジュールであなたが望むことをすることに取り組んでいます


1
Ansibleはansible_pkg_mgr、知っているすべてのパッケージャに対して自身を設定します。何もする必要はありません。どこでもこの特定の構造を使用します。
マイケルハンプトン

シンタックスは、プレイブックの実行を最適化したい人にとってはまだ非常に便利です。汎用パッケージモジュールは、with_itemsの最適化をまだ提供していないため、複数のパッケージを一度にインストールするために使用すると、はるかに遅くなります。
ダニラヴァーシニン

@DanielV。githubの問題はその回避策を提供することに注意してください。
マイケルハンプトン


3

条件付きインポートに関するAnsibleのドキュメントをご覧ください。

サービス名がOSごとに異なる場合でも、Apacheが実行されるようにするための1つのタスク。

---
- 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関連のディストリビューションでは、人気のあるWebサーバーパッケージはという名前でhttpd、Debian関連のディストリビューションでは、という名前apache2です。同様に、他のシステムとサポートライブラリの膨大なリストがあります。

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


これは私が(:)残念ながら)期待していたので、私はどのように思う何より以下のsalt両方のパッケージマネージャを統一するために管理しています。とにかく、私は二重構成に頼ります。
WoJ 14

または、ディストリビューション動物園を管理しないでください;-)単一のディストリビューションインフラストラクチャに移行し、より幸せな生活を送ってください。
Mxx 14

動物園は幸運にも2匹の大型動物ですが、これは私が行くことができる最低の数です:)
WoJ 14

1
@Mxxはシステム管理者にとっては素晴らしいロジックですが、複数のプラットフォームをサポートするソフトウェアベンダーやコンサルタントはどうでしょうか。
デビッドH.ベネット14年

@David、ディストリビューションベンダーがパッケージ名を統一してツールをインストールするためには、これをディストリビューションベンダーに取り込む必要があります。現実的に、Ansibleがすべてのバージョンのサポートされているすべてのディストリビューションからのすべてのパッケージの統一マッピングを持つことはできません。
Mxx 14年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.