วิธีการรวมงานการติดตั้งแพ็คเกจเข้าด้วยกันได้อย่างไร


68

ฉันเริ่มด้วยansibleและจะใช้มันเพื่อติดตั้งแพ็คเกจบน Linux distros หลาย ๆ ตัว

ฉันเห็นในเอกสารที่มีการแยกคำสั่ง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"

ฉันเข้าใจว่าผู้จัดการแพคเกจทั้งสองนั้นแตกต่างกัน แต่พวกเขายังคงมีวิธีการใช้งานพื้นฐานที่เหมือนกัน orchestators อื่น ๆ ( เช่นเกลือ ) มีคำสั่งติดตั้งเดียว


คุณสามารถมีสามสูตร: สูตรหนึ่งทำซ้ำในรายการทั่วไปและอีกสูตรหนึ่งสำหรับรายการเฉพาะระบบปฏิบัติการ สิ่งที่ฉันพยายามคิดตอนนี้คือวิธีแจ้งผู้จัดการด้วยชื่อบริการเฉพาะระบบปฏิบัติการหลังจากตั้งค่ารายการกำหนดค่าทั่วไป โชคดี!
dannyman

คำตอบ:


66

อัปเดต: ในฐานะของ Ansible 2.0 ขณะนี้มีโมดูลทั่วไปและบทคัดย่อpackage

ตัวอย่างการใช้งาน:

ตอนนี้เมื่อชื่อแพคเกจเหมือนกันในตระกูล OS ต่าง ๆ มันง่ายเหมือน:

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

เมื่อชื่อแพ็กเกจแตกต่างกันในตระกูล OS คุณสามารถจัดการได้ด้วยการแจกจ่ายหรือไฟล์ vars เฉพาะตระกูล OS:

---
# 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) ได้เลือกที่จะไม่สรุปโมดูลการจัดการแพ็กเกจอย่างที่Chefทำ

หากคุณยังคงใช้ Ansible รุ่นเก่า (Ansible <2.0) อยู่แต่น่าเสียดายที่คุณจะต้องจัดการกับมันในplaybooks และบทบาททั้งหมดของคุณ IMHOสิ่งนี้ผลักดันให้เกิดงานซ้ำ ๆ ที่ไม่จำเป็นลงบน Playbook และผู้เขียนบท ... แต่มันเป็นอย่างที่เป็นอยู่ในปัจจุบัน โปรดทราบว่าฉันไม่ได้กำลังบอกว่าเราควรพยายามแยกตัวจัดการแพ็กเกจออกจากกันในขณะที่ยังพยายามสนับสนุนตัวเลือกและคำสั่งเฉพาะทั้งหมดของพวกเขา แต่เพียงแค่มีวิธีที่ง่ายในการติดตั้งแพ็กเกจ ฉันยังไม่ได้บอกว่าเราทุกคนควรข้ามไปที่ Smart Package Managerbandwagon แต่สิ่งที่เป็นนามธรรมของชั้นการติดตั้งแพคเกจบางอย่างในเครื่องมือการจัดการการกำหนดค่าของคุณมีประโยชน์มากในการทำให้ playbooks / cookbooks ข้ามแพลตฟอร์มง่ายขึ้น โครงการสมาร์ทดูน่าสนใจ แต่มันค่อนข้างทะเยอทะยานที่จะรวมการจัดการแพกเกจข้าม distros และแพลทฟอร์มโดยไม่ต้องยอมรับมาก ... มันจะน่าสนใจที่จะเห็นว่ามันประสบความสำเร็จหรือไม่ ปัญหาที่แท้จริงคือเพียงแค่ชื่อแพ็คเกจที่บางครั้งมีแนวโน้มที่จะแตกต่างกันใน distros ดังนั้นเรายังต้องทำคำสั่งกรณีหรือwhen:คำสั่งเพื่อจัดการความแตกต่าง

วิธีที่ฉันจัดการกับมันก็คือการทำตามtasksโครงสร้างไดเรกทอรีนี้ใน playbook หรือบทบาท:

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

Homebrew:

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

และใช่มีข้อโต้แย้งว่าชื่อแพคเกจบางชื่อมีความแตกต่างกันไปในส่วนของ distros และถึงแม้จะมีอยู่ในปัจจุบันคือการขาดข้อมูลสามารถเข้าถึงได้ง่ายผมกล้าที่จะเดาว่าส่วนใหญ่ชื่อแพคเกจที่เป็นที่นิยมทั่วไปทั่ว distros และสามารถติดตั้งผ่านโมดูลผู้จัดการแพคเกจใจลอย กรณีพิเศษจะต้องมีการจัดการอยู่แล้วและแล้วจะต้องมีงานพิเศษทำสิ่งที่แห้งน้อยหากมีข้อสงสัยให้ตรวจสอบpkgs.org


ด้วย Ansible 2 คุณสามารถใช้โมดูลแพ็กเกจเพื่อสร้างเอกสารทั้งหมดdocs.ansible.com/ansible/package_module.html
Guido

@ GuidoGarcía: ดีมาก! การเพิ่มบันทึกเกี่ยวกับสิ่งนี้สำหรับ Ansible 2.0
TrinitronX

อาจเป็นมูลค่าการกล่าวขวัญว่าคุณสามารถระบุรายการคั่นด้วยเครื่องหมายจุลภาคหรือเพียงรายการแพคเกจ
Wes Turner

13

คุณสามารถแยกออกจากผู้จัดการแพคเกจผ่านข้อเท็จจริง

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

ทั้งหมดที่คุณต้องเป็นตรรกะบางที่กำหนดansible_pkg_mgrไปaptหรือyumฯลฯ

เบิ้ลจะยังทำงานในการทำสิ่งที่คุณต้องการในโมดูลอนาคต


1
Ansible กำหนดansible_pkg_mgrตัวเองสำหรับผู้ทำแพ็กเกจที่รู้ คุณไม่จำเป็นต้องทำอะไรเลย ฉันใช้สิ่งก่อสร้างนี้ทุกที่
Michael Hampton

ไวยากรณ์ยังคงมีประโยชน์มากสำหรับผู้ที่ต้องการเพิ่มประสิทธิภาพการทำงานของ playbooks โมดูลแพ็คเกจทั่วไปยังไม่มีการปรับให้เหมาะสมสำหรับ with_itemsดังนั้นจึงช้ากว่ามากเมื่อใช้ในการติดตั้งหลายแพ็คเกจพร้อมกัน
Danila Vershinin

@DanielV โปรดทราบว่าปัญหา GitHub นั้นมีวิธีแก้ปัญหาสำหรับสิ่งนั้น
Michael Hampton

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

ตรวจสอบเอกสารเบิ้ลในการนำเข้าตามเงื่อนไข

ภารกิจหนึ่งเพื่อให้แน่ใจว่า 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

คุณไม่ต้องการที่จะทำเช่นนั้นเพราะชื่อแพคเกจบางอย่างแตกต่างกันระหว่าง distros ยกตัวอย่างเช่นใน distros RHEL ที่เกี่ยวข้องกับแพคเกจเว็บเซิร์ฟเวอร์ที่นิยมเป็นชื่อhttpdที่เป็นใน distros Debian apache2ที่เกี่ยวข้องกับมันชื่อ ในทำนองเดียวกันกับรายการอื่น ๆ ของระบบอื่น ๆ และห้องสมุดที่รองรับ

อาจมีชุดของพารามิเตอร์พื้นฐานทั่วไป แต่ก็มีพารามิเตอร์ขั้นสูงอีกจำนวนหนึ่งที่แตกต่างกันระหว่างตัวจัดการแพคเกจ และคุณไม่ต้องการที่จะอยู่ในสถานการณ์ที่คลุมเครือซึ่งสำหรับบางคำสั่งคุณใช้ไวยากรณ์เดียวและสำหรับคำสั่งอื่น ๆ ที่คุณใช้ไวยากรณ์อื่น


นี่คือสิ่งที่ฉันคาดหวังมากขึ้นหรือน้อยลง (น่าเสียดายที่ :)) ดังนั้นฉันจึงสงสัยว่าsaltจะจัดการตัวจัดการแพคเกจทั้งสองได้อย่างไร อย่างไรก็ตามฉันจะหันไปใช้การกำหนดค่าสองครั้งจากนั้น
WoJ

หรือไม่จัดการสวนสัตว์ distro ;-) ย้ายไปที่โครงสร้างพื้นฐานเดียวและใช้ชีวิตที่มีความสุขกว่า
Mxx

สวนสัตว์เป็นโชคดีเพียงสองสัตว์ใหญ่ แต่นี้เป็นจำนวนต่ำสุดที่ฉันสามารถไป :)
WoJ

1
@Mxx นั้นเป็นตรรกะที่ดีสำหรับระบบดูแลระบบ แต่สิ่งที่เกี่ยวกับผู้จำหน่ายซอฟต์แวร์หรือที่ปรึกษาที่รองรับหลายแพลตฟอร์ม?
David H. Bennett

@ David แล้วจะต้องดำเนินการกับผู้จำหน่าย distro เพื่อให้พวกเขามีชื่อแพคเกจรวมและเครื่องมือในการติดตั้ง ไม่มีเหตุผลที่ Ansible สามารถมีการแมปรวมของแพ็คเกจทั้งหมดจาก distros ที่รองรับทั้งหมดของทุกรุ่น
Mxx
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.