จำกัด Playbooks Ansible ที่ปลอดภัยไปยังเครื่องเดียวหรือไม่


227

ฉันกำลังใช้ Ansible สำหรับงานการจัดการผู้ใช้อย่างง่ายด้วยคอมพิวเตอร์กลุ่มเล็ก ๆ ขณะนี้ฉันตั้ง playbooks ไว้hosts: allและไฟล์โฮสต์ของฉันเป็นเพียงกลุ่มเดียวที่มีรายการเครื่องทั้งหมด:

# file: hosts
[office]
imac-1.local
imac-2.local
imac-3.local

ฉันพบตัวเองบ่อยครั้งที่ต้องกำหนดเป้าหมายเครื่องเดียว ansible-playbookขีด จำกัด ของคำสั่งที่สามารถเล่นเช่นนี้

ansible-playbook --limit imac-2.local user.yml

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

มีวิธีปฏิบัติที่ดีที่สุดสำหรับการ จำกัด playbook ให้ทำงานกับเครื่องเดียวหรือไม่? playbooks ควรจะไม่เป็นอันตรายหากรายละเอียดที่สำคัญบางอย่างถูกปล่อยออกมา

คำตอบ:


209

ปรากฎว่าเป็นไปได้ที่จะป้อนชื่อโฮสต์ลงใน playbook โดยตรงดังนั้นการรัน playbook ด้วยhosts: imac-2.localจะทำงานได้ดี แต่มันก็เป็นชนิดของ clunky

ทางออกที่ดีกว่าอาจกำหนดโฮสต์ของ playbook โดยใช้ตัวแปรจากนั้นส่งผ่านที่อยู่โฮสต์ที่ระบุผ่าน--extra-vars:

# file: user.yml  (playbook)
---
- hosts: '{{ target }}'
  user: ...

ใช้งาน playbook:

ansible-playbook user.yml --extra-vars "target=imac-2.local"

หาก{{ target }}ไม่ได้กำหนด playbook จะไม่ทำอะไรเลย กลุ่มจากไฟล์โฮสต์สามารถส่งผ่านได้หากต้องการ โดยรวมแล้วดูเหมือนว่าจะเป็นวิธีที่ปลอดภัยกว่ามากในการสร้าง playbook ที่อาจทำลายล้าง

Playbook กำหนดเป้าหมายไปที่โฮสต์เดียว:

$ ansible-playbook user.yml --extra-vars "target=imac-2.local" --list-hosts

playbook: user.yml

  play #1 (imac-2.local): host count=1
    imac-2.local

Playbook กับกลุ่มโฮสต์:

$ ansible-playbook user.yml --extra-vars "target=office" --list-hosts

playbook: user.yml

  play #1 (office): host count=3
    imac-1.local
    imac-2.local
    imac-3.local

การลืมกำหนดโฮสต์นั้นปลอดภัย!

$ ansible-playbook user.yml --list-hosts

playbook: user.yml

  play #1 ({{target}}): host count=0

52
สิ่งนี้สามารถแก้ไขได้ใน 1.5.3 ด้วย--limit office[0]
NG

4
ตัวแปรจะต้องมีการอ้างอิง - เช่น: '{{ target }}'- ตามdocs.ansible.com/ ...
Limbo Peng

9
นี่คือคำตอบ "ไม่ปลอดภัย" ซึ่งแตกต่างจากคำตอบอื่น ๆ - ถ้าคุณปล่อยอะไรออกไปมันจะไม่ทำอะไรเลย การเรียกใช้เพียงโฮสต์เดียวที่ใช้ Ansible 1.7 run_onceอาจยังเป็นอันตรายได้ดังนั้นจึงไม่ใช่ความคิดที่ดี
RichVel

4
หากคุณต้องการคำสั่งที่สั้นกว่า-eนี้เทียบเท่ากับ--extra-vars
William Turrell

1
หากการกำหนดค่าที่ไม่สามารถระบุได้ของคุณต้องการให้โฮสต์ไม่สามารถว่างหรือไม่ได้กำหนดให้ใช้ตัวแปรที่รวมกับตัวกรอง jinja เช่น:hosts: "{{ target | default('no_hosts')}}"
Zach Weg

178

นอกจากนี้ยังมีเคล็ดลับเล็ก ๆ น่ารักที่ให้คุณระบุโฮสต์เดียวในบรรทัดคำสั่ง (หรือหลาย ๆ โฮสต์ฉันเดา) โดยไม่มีสินค้าคงคลังตัวกลาง:

ansible-playbook -i "imac1-local," user.yml

สังเกตเครื่องหมายจุลภาค ( , ) ในตอนท้าย; สัญญาณนี้ว่าเป็นรายการไม่ใช่ไฟล์

ตอนนี้สิ่งนี้จะไม่ปกป้องคุณหากคุณส่งไฟล์คลังโฆษณาจริงโดยไม่ตั้งใจดังนั้นจึงอาจไม่ใช่วิธีแก้ปัญหาที่ดีสำหรับปัญหาเฉพาะนี้ แต่มันเป็นกลอุบายที่รู้ได้ง่าย!


2
ที่น่าตื่นตาตื่นใจ. ฉันใช้แฟล็ก -l เป็นประจำซึ่งทำงานกับ etc / ansible / hosts (ซึ่งมีประชากรโดยใช้ EC2 Discovery API) แต่บางครั้งฉันก็ต้องการเครื่องเดียว ขอบคุณ!
Vic

3
เคล็ดลับนี้ควรใช้ประโยชน์จากไฟล์โฮสต์หรือไม่ ฉันใช้เป็นเจ้าภาพสินค้าคงคลังแบบไดนามิกสำหรับระบบ AWS EC2 skipping: no hosts matchedของเราและมันจะส่งกลับ บางทีอาจจะเป็นเคล็ดลับนี้ไม่ทำงานตั้งแต่--limitงาน?
hamx0r

1
เคล็ดลับนี้ไม่ได้ผลสำหรับฉัน แต่สิ่งนี้ได้ผล: $ ansible-playbook -kK --limit=myhost1 myplaybook.yml. ดูคำตอบของ Marwan
Donn Lee

2
มันควรจะกล่าวว่าสำหรับเรื่องนี้ในการทำงานเจ้าภาพจะต้องถูกกำหนดให้allอยู่ในละคร (s) - เอาฉันในขณะที่คิดออก ...
Remigius Stalder

83

วิธีการนี้จะออกหากมีมากกว่าหนึ่งโฮสต์ที่ให้บริการโดยการตรวจสอบตัวแปรplay_hosts โมดูลล้มเหลวถูกนำมาใช้เพื่อออกถ้าสภาพโฮสต์เดียวจะไม่ได้พบกัน ตัวอย่างด้านล่างใช้ไฟล์โฮสต์ที่มีสองโฮสต์อลิซและบ็อบ

user.yml (playbook)

---
- hosts: all
  tasks:
    - name: Check for single host
      fail: msg="Single host check failed."
      when: "{{ play_hosts|length }} != 1"
    - debug: msg='I got executed!'

เรียกใช้ playbook โดยไม่มีตัวกรองโฮสต์

$ ansible-playbook user.yml
PLAY [all] ****************************************************************
TASK: [Check for single host] *********************************************
failed: [alice] => {"failed": true}
msg: Single host check failed.
failed: [bob] => {"failed": true}
msg: Single host check failed.
FATAL: all hosts have already failed -- aborting

เรียกใช้ playbook ในโฮสต์เดียว

$ ansible-playbook user.yml --limit=alice

PLAY [all] ****************************************************************

TASK: [Check for single host] *********************************************
skipping: [alice]

TASK: [debug msg='I got executed!'] ***************************************
ok: [alice] => {
    "msg": "I got executed!"
}

1
หนึ่ง--limitในวิธีที่ดีที่สุดแน่นอนคือวิธีไป
berto

7
play_hostsจะเลิกในเบิ้ล 2.2 ansible_play_hostsและแทนที่ด้วย เพื่อให้ทำงานบนโฮสต์โดยไม่ต้องคุณสามารถใช้--limit when: inventory_hostname == ansible_play_hosts[0]
เทรเวอร์โรบินสัน

[WARNING]: conditional statements should not include jinja2 templating delimiters such as {{ }} or {% %}. Found: {{ play_hosts|length }} == ''บน Ansible 2.8.4
โทมัส

32

IMHO นั้นเป็นวิธีที่สะดวกกว่า คุณสามารถกระตุ้นให้ผู้ใช้โต้ตอบกับเครื่องที่เขาต้องการใช้ playbook เพื่อขอบคุณvars_prompt:

---

- hosts: "{{ setupHosts }}"
  vars_prompt:
    - name: "setupHosts"
      prompt: "Which hosts would you like to setup?"
      private: no
  tasks:
    […]

2
เด็ดมาก นอกจากนี้ยังมีข้อได้เปรียบที่ playbook ไม่เฉพาะเจาะจงกับไฟล์คลังโฆษณา
Erfan

2
ขอบคุณสำหรับการแก้ไข! ฉันสงสัยจริงๆว่าทำไมอินพุตเป็นค่าเริ่มต้น "สไตล์รหัสผ่าน" ฉันได้พลาดว่าในเอกสาร :)
Buzut

สามารถตั้งค่า var var จากบรรทัดคำสั่งเพื่อกำจัดพรอมต์ด้วย playbook นี้ได้หรือไม่?
andig

1
@andig ด้วย--extra-varsและ var ปกติใน playbook ของคุณ ...
Buzut

ที่จริงแล้วฉันไม่สามารถใช้งานได้ - ดูเหมือน{{ hosts }}จะได้รับการประเมินก่อนป้อนค่า - หรือมีเคล็ดลับพิเศษหรือไม่
Remigius Stalder

18

หากต้องการขยายคำตอบของ Joemailer หากคุณต้องการความสามารถในการจับคู่รูปแบบเพื่อจับคู่ชุดย่อยของเครื่องระยะไกล (เช่นเดียวกับansibleคำสั่ง) แต่ก็ยังต้องการทำให้มันยากที่จะเรียกใช้ playbook บนเครื่องทั้งหมดโดยบังเอิญ สิ่งที่ฉันคิดไว้:

Playbook เหมือนกับคำตอบอื่น ๆ :

# file: user.yml  (playbook)
---
- hosts: '{{ target }}'
  user: ...

มามีโฮสต์ต่อไปนี้:

imac-10.local
imac-11.local
imac-22.local

ตอนนี้เพื่อเรียกใช้คำสั่งบนอุปกรณ์ทั้งหมดคุณต้องตั้งค่าตัวแปรเป้าหมายให้เป็น "all"

ansible-playbook user.yml --extra-vars "target=all"

และเพื่อ จำกัด ให้เป็นรูปแบบเฉพาะคุณสามารถตั้งค่า target=pattern_here

หรืออีกวิธีหนึ่งคุณสามารถปล่อยtarget=allและต่อท้าย--limitอาร์กิวเมนต์เช่น:

--limit imac-1*

กล่าวคือ ansible-playbook user.yml --extra-vars "target=all" --limit imac-1* --list-hosts

ซึ่งผลลัพธ์ใน:

playbook: user.yml

  play #1 (office): host count=2
    imac-10.local
    imac-11.local

นี่คือรูปแบบที่ฉันได้ติดตามในansible-django-postgres-nginx
Ajoy

13

ฉันไม่เข้าใจจริงๆว่าคำตอบทั้งหมดนั้นซับซ้อนอย่างไรวิธีการทำคือ:

ansible-playbook user.yml -i hosts/hosts --limit imac-2.local --check

checkโหมดช่วยให้คุณสามารถทำงานในโหมดแห้งทำงานโดยไม่มีการเปลี่ยนแปลงใด ๆ


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

2
อาแน่นอน แต่ถ้ามีคนโหวตฉันก็อาจเป็นเพราะพวกเขาเป็นมือใหม่ Ansible (เหมือนตอนที่ฉันเขียนคำตอบ) ซึ่งไม่รู้เกี่ยวกับธง--checkดังนั้นฉันคิดว่านี่เป็นเอกสารที่มีประโยชน์ คำถามนี้อาจเป็นgooglable
knocte

6

ผู้ใช้ AWS ที่ใช้สคริปต์สินค้าคงคลังภายนอก EC2 สามารถกรองตามรหัสอินสแตนซ์:

ansible-playbook sample-playbook.yml --limit i-c98d5a71 --list-hosts

งานนี้เพราะสคริปต์สินค้าคงคลังสร้างกลุ่มเริ่มต้น


4
ตัวเลือก - จำกัด ไม่ จำกัด เฉพาะ EC2 และสามารถใช้กับชื่อโฮสต์ / กลุ่มของสินค้าคงคลังของคุณ ขอบคุณ
martinezdelariva

5

เรามี playbooks ทั่วไปที่สามารถใช้งานได้โดยทีมจำนวนมาก นอกจากนี้เรายังมีไฟล์สินค้าคงคลังเฉพาะสภาพแวดล้อมที่มีการประกาศหลายกลุ่ม

ในการบังคับให้บางคนเรียก playbook เพื่อระบุกลุ่มที่จะทำการโจมตีเราจะใส่รายการจำลองไว้ที่ด้านบนของ playbook:

[ansible-dummy-group]
dummy-server

จากนั้นเราจะรวมการตรวจสอบต่อไปนี้เป็นขั้นตอนแรกใน playbook ที่แชร์:

- hosts: all
  gather_facts: False
  run_once: true
  tasks:
  - fail:
      msg: "Please specify a group to run this playbook against"
    when: '"dummy-server" in ansible_play_batch'

หากเซิร์ฟเวอร์จำลองปรากฏขึ้นในรายการโฮสต์ playbook นี้ถูกกำหนดเวลาให้ทำงาน (ansible_play_batch) ผู้โทรไม่ได้ระบุกลุ่มและการดำเนินการกับ playbook จะล้มเหลว


ansible_play_batchแสดงรายการแบตช์ปัจจุบันเท่านั้นดังนั้นเมื่อใช้การแบทช์นี้ก็ยังไม่ปลอดภัย มันจะดีกว่าที่จะใช้ansible_play_hostsแทน
โทมัส

นอกจากนั้นเคล็ดลับนี้ดูเหมือนจะง่ายและใกล้เคียงที่สุดกับสิ่งที่ถูกถาม ฉันยอมรับมัน!
โทมัส


4

นี่แสดงวิธีการเรียกใช้ playbooks บนเซิร์ฟเวอร์เป้าหมาย

นี่เป็นเรื่องยากกว่านี้หากคุณต้องการใช้การเชื่อมต่อท้องถิ่น แต่สิ่งนี้ควรจะใช้ได้ถ้าคุณใช้ตัวแปรสำหรับการตั้งค่าโฮสต์และในไฟล์โฮสต์สร้างรายการพิเศษสำหรับ localhost

ใน playbooks (ทั้งหมด) มีโฮสต์: line set เป็น:

- hosts: "{{ target | default('no_hosts')}}"

ในไฟล์โฮสต์โฮสต์เพิ่มรายการสำหรับ localhost ซึ่งตั้งค่าการเชื่อมต่อเป็นแบบโลคัล:

[localhost]
127.0.0.1  ansible_connection=local

จากนั้นในบรรทัดคำสั่งเรียกใช้คำสั่งตั้งเป้าหมายอย่างชัดเจน - ตัวอย่างเช่น:

$ ansible-playbook --extra-vars "target=localhost" test.yml

สิ่งนี้จะทำงานเมื่อใช้ ansible-pull:

$ ansible-pull -U <git-repo-here> -d ~/ansible --extra-vars "target=localhost" test.yml

หากคุณลืมตั้งค่าตัวแปรบนบรรทัดคำสั่งคำสั่งจะเกิดข้อผิดพลาดอย่างปลอดภัย (ตราบใดที่คุณยังไม่ได้สร้างกลุ่มโฮสต์ชื่อ 'no_hosts'!) โดยมีคำเตือน:

skipping: no hosts matched

และตามที่กล่าวไว้ข้างต้นคุณสามารถกำหนดเป้าหมายเครื่องเดียว (ตราบเท่าที่อยู่ในไฟล์โฮสต์ของคุณ) ด้วย:

$ ansible-playbook --extra-vars "target=server.domain" test.yml

หรือกลุ่มที่มีสิ่งต่อไปนี้:

$ ansible-playbook --extra-vars "target=web-servers" test.yml

0

ฉันมีสคริปต์ตัวคลุมที่เรียกว่าบทบัญญัติบังคับให้คุณเลือกเป้าหมายดังนั้นฉันจึงไม่ต้องจัดการกับที่อื่น

สำหรับผู้ที่อยากรู้อยากเห็นฉันใช้ ENV vars สำหรับตัวเลือกที่ vagrantfile ของฉันใช้ (เพิ่ม ARS ansible ที่สอดคล้องกันสำหรับระบบคลาวด์) และปล่อยให้ส่วนที่เหลือของ ansible args ผ่าน ที่ฉันกำลังสร้างและจัดเตรียมเซิร์ฟเวอร์มากกว่า 10 เครื่องในแต่ละครั้งที่ฉันรวมการลองใหม่อัตโนมัติบนเซิร์ฟเวอร์ที่ล้มเหลว (ตราบเท่าที่ยังมีความคืบหน้าอยู่ - ฉันพบเมื่อสร้างเซิร์ฟเวอร์ 100 เครื่องหรือมากกว่านั้นในแต่ละครั้ง )

echo 'Usage: [VAR=value] bin/provision [options] dev|all|TARGET|vagrant'
echo '  bootstrap - Bootstrap servers ssh port and initial security provisioning'
echo '  dev - Provision localhost for development and control'
echo '  TARGET - specify specific host or group of hosts'
echo '  all - provision all servers'
echo '  vagrant - Provision local vagrant machine (environment vars only)'
echo
echo 'Environment VARS'
echo '  BOOTSTRAP - use cloud providers default user settings if set'
echo '  TAGS - if TAGS env variable is set, then only tasks with these tags are run'
echo '  SKIP_TAGS - only run plays and tasks whose tags do not match these values'
echo '  START_AT_TASK - start the playbook at the task matching this name'
echo
ansible-playbook --help | sed -e '1d
    s#=/etc/ansible/hosts# set by bin/provision argument#
    /-k/s/$/ (use for fresh systems)/
    /--tags/s/$/ (use TAGS var instead)/
    /--skip-tags/s/$/ (use SKIP_TAGS var instead)/
    /--start-at-task/s/$/ (use START_AT_TASK var instead)/
'

0

ทางออกที่แตกต่างกันเล็กน้อยคือการใช้ตัวแปรพิเศษansible_limitซึ่งเป็นเนื้อหาของ--limitตัวเลือก CLI สำหรับการดำเนินการปัจจุบันของ Ansible

- hosts: "{{ ansible_limit | default(omit) }}"

ไม่จำเป็นต้องกำหนดตัวแปรเพิ่มเติมที่นี่เพียงแค่เรียกใช้ playbook ด้วยการ--limitตั้งค่าสถานะ

ansible-playbook --limit imac-2.local user.yml
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.