如何在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"

我知道這兩個套件管理器是不同的,但它們仍然有一組共同的基本用法。其他編曲家(例如鹽)有一個安裝指令。

答案1

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



編輯: 自 Michael DeHaan(Ansible 的創建者)以來選擇不抽像出套件管理器模組喜歡廚師做,

如果您仍在使用舊版的 Ansible(Ansible < 2.0),不幸的是你需要處理這樣做全部你的劇本和角色。 恕我直言這將大量不必要的重複工作推給了劇本和角色作者……但目前就是這樣。請注意,我並不是說我們應該嘗試將套件管理器抽象化出來,同時仍然嘗試支援它們的所有特定選項和命令,而只是有一種簡單的方法來安裝與套件管理器無關的套件。我也不是說我們都該跳上智慧包管理器流行,但組態管理工具中的某種套件安裝抽象層對於簡化跨平台劇本/說明書非常有用。 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

嗯:

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

是的,有這樣的論點:一些不同發行版的套件名稱不同。而且雖然目前有一個缺乏易於取得的數據,我鬥膽猜測一下最多流行的軟體包名稱在發行版中很常見,可以透過抽象的軟體包管理器模組安裝。無論如何,特殊情況都需要處理,並且已經需要額外的工作來使事情變得不那麼乾燥。pkgs.org

答案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。

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

然後您可以像您的提案一樣使用它:

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

您仍然需要考慮名稱差異。

答案4

您不想這樣做,因為某些軟體包名稱在發行版之間有所不同。例如,在 RHEL 相關發行版上,流行的 Web 伺服器套件被命名為httpd,而在 Debian 相關發行版上,它被命名為apache2。同樣,還有大量其他系統和支援庫。

可能有一組常見的基本參數,但也有許多更高級的參數在套件管理器之間有所不同。並且您不希望處於一種不明確的情況,即對於某些命令您使用一種語法,而對於其他命令您使用另一種語法。

相關內容