Làm thế nào để thống nhất các tác vụ cài đặt gói trong ansible?


68

Tôi đang bắt đầu với ansible và sẽ sử dụng nó, trong số những người khác, để cài đặt các gói trên một số bản phân phối Linux.

Tôi thấy trong các tài liệu rằng các lệnh yumaptlệnh được tách ra - cách dễ nhất để hợp nhất chúng và sử dụng cái gì đó như thế này:

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

thay vì

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

Tôi hiểu rằng hai trình quản lý gói là khác nhau, nhưng chúng vẫn có một tập hợp các cách sử dụng cơ bản phổ biến. Các dàn nhạc khác ( ví dụ muối ) có một lệnh cài đặt duy nhất.


Bạn có thể có ba công thức nấu ăn: một công thức lặp lại qua một danh sách chung và sau đó mỗi công thức cho các danh sách dành riêng cho hệ điều hành. Điều tôi đang cố gắng tìm ra ngay bây giờ là làm thế nào để thông báo cho người xử lý với tên dịch vụ dành riêng cho hệ điều hành sau khi một mục cấu hình chung được đặt. chúc may mắn!
dannyman

Câu trả lời:


66

Cập nhật: Kể từ Ansible 2.0, giờ đây đã có một mô-đun chung & trừu tượngpackage

Ví dụ sử dụng:

Bây giờ khi tên gói giống nhau trên các họ hệ điều hành khác nhau, nó đơn giản như:

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

Khi tên gói khác nhau giữa các họ hệ điều hành, bạn có thể xử lý nó với các tệp vars dành riêng cho họ phân phối hoặc hệ điều hành:

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

Sau đó, đối với mỗi HĐH mà bạn phải xử lý khác nhau ... hãy tạo tệp 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



EDIT: Vì Michael DeHaan (người tạo ra Ansible) đã chọn không trừu tượng hóa các mô-đun quản lý gói như Chef hiện,

Nếu bạn vẫn đang sử dụng phiên bản cũ hơn của Ansible (Ansible <2.0) , thật không may, bạn sẽ cần phải xử lý việc này trong tất cả các sách và vai trò của mình. IMHO điều này thúc đẩy rất nhiều công việc lặp đi lặp lại không cần thiết đối với các tác giả của playbook & vai trò ... nhưng đó là cách nó hiện tại. Lưu ý rằng tôi không nói rằng chúng ta nên cố gắng trừu tượng hóa các trình quản lý gói trong khi vẫn cố gắng hỗ trợ tất cả các tùy chọn và lệnh cụ thể của chúng, nhưng chỉ có một cách dễ dàng để cài đặt một gói là bất khả tri của trình quản lý gói. Tôi cũng không nói rằng tất cả chúng ta nên nhảy vào Trình quản lý gói thông minhbandwagon, nhưng một số loại trừu tượng cài đặt gói trong công cụ quản lý cấu hình của bạn rất hữu ích để đơn giản hóa các sách / sách nấu ăn đa nền tảng. Dự án thông minh có vẻ thú vị, nhưng khá tham vọng khi thống nhất quản lý gói trên các bản phân phối và nền tảng mà không cần áp dụng nhiều ... sẽ rất thú vị để xem liệu nó có thành công hay không. Vấn đề thực sự chỉ là các tên gói đôi khi có xu hướng khác nhau giữa các distro, vì vậy chúng ta vẫn phải thực hiện các báo cáo trường hợp hoặc các when:câu lệnh để xử lý các khác biệt.

Cách tôi đã xử lý là theo taskscấu trúc thư mục này trong một vở kịch hoặc vai trò:

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

Và sau đó có cái này trong tôi main.yml:

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

- include: foo.yml tags=foo

Điều này trong foo.yml(đối với gói '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'

Sau đó, cho các trình quản lý gói khác nhau:

Đúng cách:

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

Lưu ý rằng điều này rất lặp đi lặp lại và không DRY , và mặc dù một số thứ thể khác nhau trên các nền tảng khác nhau và sẽ phải xử lý, nói chung tôi nghĩ rằng điều này dài dòng và khó sử dụng khi so sánh với 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

Và vâng, có lập luận rằng một số tên gói khác nhau trên các bản phát hành. Và mặc dù hiện tại thiếu dữ liệu có thể truy cập dễ dàng , tôi mạo hiểm đoán rằng hầu hết các tên gói phổ biến đều phổ biến trên các bản phát hành và có thể được cài đặt thông qua mô-đun trình quản lý gói trừu tượng. Các trường hợp đặc biệt sẽ cần phải được xử lý bằng mọi cách và sẽ yêu cầu thêm công việc khiến mọi thứ trở nên ít KHÔ hơn nếu nghi ngờ, hãy kiểm tra pkgs.org .


Với Ansible 2, bạn có thể sử dụng mô-đun gói để tóm tắt tất cả docs.ansible.com/ansible/package_module.html
Guido

@ GuidoGarcía: Rất đẹp! Thêm ghi chú về điều này cho Ansible 2.0
TrinitronX

Có lẽ cũng đáng đề cập rằng bạn có thể chỉ định một danh sách được phân tách bằng dấu phẩy hoặc chỉ một danh sách các gói.
Wes Turner

13

Bạn có thể trừu tượng hóa các trình quản lý gói thông qua các sự kiện

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

Tất cả bạn cần là một số logic mà bộ ansible_pkg_mgrđể apthoặc yum, vv

Ansible cũng đang làm việc để làm những gì bạn muốn trong một mô-đun tương lai .


1
Ansible đặt ansible_pkg_mgrchính nó cho bất kỳ packager mà nó biết. Bạn không cần phải làm gì cả. Tôi sử dụng cấu trúc đặc biệt này ở khắp mọi nơi.
Michael Hampton

Cú pháp vẫn khá hữu ích cho những ai muốn tối ưu hóa việc chạy playbook của họ. Mô-đun gói chung chưa cung cấp tối ưu hóa cho with_items nên chậm hơn nhiều khi được sử dụng để cài đặt nhiều gói cùng một lúc.
Danila Vershinin

@DanielV. Lưu ý rằng vấn đề github cung cấp một cách giải quyết cho điều đó.
Michael Hampton


3

Kiểm tra tài liệu của Ansible về Nhập khẩu có điều kiện .

Một nhiệm vụ để đảm bảo rằng apache đang chạy ngay cả khi tên dịch vụ khác nhau trên mỗi HĐH.

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

Bạn không muốn làm điều đó bởi vì tên gói nhất định khác nhau giữa các bản phát hành. Ví dụ: trên các bản phân phối liên quan đến RHEL, gói máy chủ web phổ biến được đặt tên httpd, trong đó trên các bản phân phối liên quan đến Debian có tên apache2. Tương tự như vậy với một danh sách lớn các hệ thống khác và các thư viện hỗ trợ.

Có thể có một tập hợp các tham số cơ bản phổ biến, nhưng sau đó cũng có một số tham số nâng cao khác nhau giữa các trình quản lý gói. Và bạn không muốn ở trong một tình huống mơ hồ trong đó đối với một số lệnh bạn sử dụng một cú pháp và đối với các lệnh khác, bạn sử dụng một cú pháp khác.


Điều này ít nhiều là những gì tôi đã mong đợi (thật không may :)) vì vậy tôi tự hỏi làm thế nào saltđể quản lý để thống nhất cả hai trình quản lý gói. Dù sao, tôi sẽ dùng đến một cấu hình kép, sau đó.
WoJ

Hoặc không quản lý sở thú distro ;-) di chuyển đến cơ sở hạ tầng phân phối duy nhất và sống một cuộc sống hạnh phúc hơn.
Mxx

Sở thú may mắn chỉ có hai con vật lớn nhưng đây là con số thấp nhất tôi có thể đến :)
WoJ

1
@Mxx đó là logic tốt cho một sysadmin nhưng còn nhà cung cấp phần mềm hoặc nhà tư vấn hỗ trợ nhiều nền tảng thì sao?
David H. Bennett

@David, sau đó điều này cần phải được đưa lên với các nhà cung cấp phân phối, để họ có tên gói và công cụ cài đặt thống nhất. Thực tế không có cách nào mà Ansible có thể có một ánh xạ thống nhất TẤT CẢ các gói từ tất cả các bản phát hành được hỗ trợ của tất cả các phiên bản.
Mxx
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.