Hạn chế an toàn Playbook Ansible vào một máy duy nhất?


227

Tôi đang sử dụng Ansible cho một số tác vụ quản lý người dùng đơn giản với một nhóm nhỏ máy tính. Hiện tại, tôi có các playbook của mình được đặt hosts: allvà tệp máy chủ của tôi chỉ là một nhóm duy nhất với tất cả các máy được liệt kê:

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

Tôi đã thấy mình thường xuyên phải nhắm mục tiêu vào một máy duy nhất. Các ansible-playbookgiới hạn lệnh có thể đóng vai như thế này:

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

Nhưng điều đó có vẻ mong manh, đặc biệt đối với một vở kịch có khả năng phá hủy. Rời khỏi limitcờ có nghĩa là vở kịch sẽ được chạy ở mọi nơi. Vì các công cụ này chỉ thỉnh thoảng được sử dụng, nên có vẻ đáng thực hiện các bước để phát lại một cách dễ dàng, vì vậy chúng tôi không vô tình làm gì đó từ nhiều tháng nay.

Có cách thực hành tốt nhất để hạn chế playbook chạy vào một máy không? Lý tưởng nhất là các vở kịch nên vô hại nếu một số chi tiết quan trọng bị bỏ qua.

Câu trả lời:


209

Hóa ra có thể nhập tên máy chủ trực tiếp vào playbook, vì vậy chạy playbook với hosts: imac-2.localsẽ hoạt động tốt. Nhưng đó là loại khó chịu.

Một giải pháp tốt hơn có thể là xác định máy chủ của Playbook bằng một biến, sau đó chuyển vào một địa chỉ máy chủ cụ thể thông qua --extra-vars:

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

Chạy vở kịch:

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

Nếu {{ target }}không được xác định, playbook không làm gì cả. Một nhóm từ tệp máy chủ cũng có thể được chuyển qua nếu cần. Nhìn chung, đây có vẻ là một cách an toàn hơn nhiều để xây dựng một playbook có khả năng phá hủy.

Playbook nhắm mục tiêu đến một máy chủ duy nhất:

$ 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 với một nhóm các máy chủ:

$ 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

Quên xác định máy chủ là an toàn!

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

playbook: user.yml

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

52
Điều này có thể giải được trong 1.5.3 với--limit office[0]
NG.

4
Biến cần được trích dẫn - tức là: '{{ target }}'- theo docs.ansible.com/ từ
Limbo Peng

9
Đây là một câu trả lời "không an toàn", không giống như một số câu trả lời khác - nếu bạn để lại một cái gì đó, nó sẽ không làm gì cả. Chạy trên 'chỉ một máy chủ sử dụng Ansible 1.7' run_oncevẫn có thể bị phá hủy vì vậy đó không phải là một ý tưởng hay.
RichVel

4
Nếu bạn muốn một lệnh ngắn hơn, -ethì tương đương với--extra-vars
William Turrell

1
Nếu cấu hình ansible của bạn yêu cầu máy chủ không thể trống hoặc không xác định thì sử dụng biến kết hợp với bộ lọc jinja sẽ hoạt động, chẳng hạn như:hosts: "{{ target | default('no_hosts')}}"
Zach Weg

178

Ngoài ra còn có một mẹo nhỏ dễ thương cho phép bạn chỉ định một máy chủ duy nhất trên dòng lệnh (hoặc nhiều máy chủ, tôi đoán vậy), mà không cần kiểm kê trung gian:

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

Lưu ý dấu phẩy ( , ) ở cuối; điều này báo hiệu rằng đó là một danh sách, không phải là một tập tin.

Bây giờ, điều này sẽ không bảo vệ bạn nếu bạn vô tình chuyển một tệp kiểm kê thực sự, vì vậy nó có thể không phải là một giải pháp tốt cho vấn đề cụ thể này. Nhưng đó là một mẹo hữu ích để biết!


2
Thật ngạc nhiên. Tôi thường xuyên sử dụng cờ -l, hoạt động với etc / ansible / hosts (được điền bằng API khám phá EC2), nhưng đôi khi tôi thực sự chỉ cần một máy duy nhất. Cảm ơn bạn!
Vic

3
Thủ thuật này có nên sử dụng tập tin máy chủ không? Tôi đang sử dụng máy chủ làm kho lưu trữ động cho hệ thống AWS EC2 của chúng tôi và nó trả về : skipping: no hosts matched. Có lẽ thủ thuật này không còn hoạt động kể từ khi --limithoạt động?
hamx0r

1
Thủ thuật này không hiệu quả với tôi. Nhưng điều này đã làm việc : $ ansible-playbook -kK --limit=myhost1 myplaybook.yml. Xem câu trả lời của Marwan.
Donn Lee

2
Cần phải đề cập rằng để làm việc này, các máy chủ phải được đặt alltrong (các) vở kịch - điều này khiến tôi mất một lúc để tìm ra ...
Remigius Stalder

83

Cách tiếp cận này sẽ thoát nếu có nhiều hơn một máy chủ được cung cấp bằng cách kiểm tra biến play_hosts . Các thất bại mô-đun được sử dụng để thoát nếu điều kiện máy chủ duy nhất không được đáp ứng. Các ví dụ dưới đây sử dụng tệp máy chủ có hai máy chủ alice và bob.

user.yml (vở kịch)

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

Chạy playbook không có bộ lọc máy chủ

$ 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

Chạy playbook trên một máy chủ

$ 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
Chắc chắn là tốt nhất, --limitlà con đường để đi
berto

7
play_hostskhông được dùng trong Ansible 2.2 và được thay thế bằng ansible_play_hosts. Để chạy trên một máy chủ mà không yêu cầu --limit, bạn có thể sử dụng when: inventory_hostname == ansible_play_hosts[0].
Trevor Robinson

[WARNING]: conditional statements should not include jinja2 templating delimiters such as {{ }} or {% %}. Found: {{ play_hosts|length }} == ''trên Ansible 2.8.4.
Thomas

32

Có IMHO một cách thuận tiện hơn. Bạn thực sự có thể tương tác nhắc người dùng cho (các) máy mà anh ta muốn áp dụng Playbook để cảm ơn vars_prompt:

---

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

2
Rất tuyệt. Điều này cũng có lợi thế là playbook không dành riêng cho tệp kiểm kê.
Erfan

2
Thx cho chỉnh sửa! Tôi đã thực sự tự hỏi tại sao đầu vào theo mặc định được xử lý "kiểu mật khẩu". Tôi đã bỏ lỡ điều đó trong các tài liệu :)
Buzut

Các var máy chủ có thể được đặt từ dòng lệnh để loại bỏ lời nhắc với playbook này không?
andig

1
@andig với --extra-varsvà một var bình thường trong playbook của bạn
Buzut 23/2/2017

Trên thực tế, tôi không thể làm điều này hoạt động - dường như {{ hosts }}được đánh giá trước khi nhập giá trị - hoặc có một mẹo đặc biệt nào không?
Remigius Stalder

18

Để mở rộng câu trả lời của joemailer, nếu bạn muốn có khả năng khớp mẫu phù hợp với bất kỳ tập hợp con nào của máy từ xa (giống như ansiblelệnh), nhưng vẫn rất khó để vô tình chạy playbook trên tất cả các máy, đây là những gì tôi đã đưa ra:

Playbook tương tự như trong câu trả lời khác:

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

Hãy có các máy chủ sau:

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

Bây giờ, để chạy lệnh trên tất cả các thiết bị, bạn phải khám phá đặt biến mục tiêu thành "tất cả"

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

Và để giới hạn nó xuống một mẫu cụ thể, bạn có thể đặt target=pattern_here

hoặc, thay vào đó, bạn có thể rời khỏi target=allvà nối thêm --limitđối số, ví dụ:

--limit imac-1*

I E. ansible-playbook user.yml --extra-vars "target=all" --limit imac-1* --list-hosts

kết quả là:

playbook: user.yml

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

Đây là mô hình mà tôi đã theo dõi trong ansible-django-postgres-nginx
Ajoy

13

Tôi thực sự không hiểu làm thế nào tất cả các câu trả lời quá phức tạp, cách thực hiện chỉ đơn giản là:

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

Các checkchế độ cho phép bạn chạy ở chế độ khô hạn, mà không thực hiện bất kỳ thay đổi.


7
Có thể vì băn khoăn về câu trả lời, bạn đã bỏ lỡ câu hỏi, yêu cầu một cách để ngăn không cho chạy khi các tham số bị bỏ qua do nhầm lẫn. Bạn đề nghị thêm nhiều tham số đi ngược lại yêu cầu.
techraf

2
ah, chắc chắn, nhưng nếu mọi người ủng hộ tôi, có thể là vì họ là người mới Ansible (giống như khi tôi viết câu trả lời của mình) mà thậm chí không biết về cờ --check, vì vậy tôi đoán đây vẫn là tài liệu hữu ích, như câu hỏi này có thể rất hay
knocte

6

Người dùng AWS sử dụng Tập lệnh kiểm kê bên ngoài EC2 có thể chỉ cần lọc theo id ví dụ:

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

Điều này hoạt động vì tập lệnh kiểm kê tạo các nhóm mặc định .


4
Tùy chọn --limit không giới hạn ở EC2 và có thể được sử dụng để lưu trữ tên nhóm / nhóm hàng tồn kho của bạn. Cảm ơn.
martinezdelariva

5

Chúng tôi có một số vở kịch chung có thể sử dụng được bởi một số lượng lớn các đội. Chúng tôi cũng có các tệp kiểm kê cụ thể về môi trường, có chứa nhiều khai báo nhóm.

Để buộc ai đó gọi một playbook để chỉ định một nhóm chạy tới, chúng tôi gieo một mục giả ở đầu của playbook:

[ansible-dummy-group]
dummy-server

Sau đó, chúng tôi bao gồm kiểm tra sau đây là bước đầu tiên trong Playbook được chia sẻ:

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

Nếu máy chủ giả xuất hiện trong danh sách máy chủ thì playbook này được lên lịch để chạy (ansible_play_batch), thì người gọi đã không chỉ định một nhóm và việc thực thi playbook sẽ thất bại.


ansible_play_batchchỉ liệt kê đợt hiện tại, vì vậy khi sử dụng đợt này vẫn không an toàn. Thay vào đó, tốt hơn là sử dụng ansible_play_hosts.
Thomas

Ngoài ra, thủ thuật này dường như là đơn giản nhất và gần nhất với những gì được hỏi; Tôi đang áp dụng nó!
Thomas

4

Vì phiên bản 1.7 ansible có tùy chọn run_once . Phần này cũng chứa một số thảo luận về các kỹ thuật khác nhau.


4

Điều này cho thấy cách chạy playbooks trên chính máy chủ mục tiêu.

Đây là một chút phức tạp hơn nếu bạn muốn sử dụng kết nối cục bộ. Nhưng điều này sẽ ổn nếu bạn sử dụng một biến cho cài đặt máy chủ và trong tệp máy chủ tạo một mục đặc biệt cho localhost.

Trong (tất cả) playbooks có các máy chủ: dòng được đặt thành:

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

Trong tệp lưu trữ kho lưu trữ, thêm một mục nhập cho localhost, thiết lập kết nối là cục bộ:

[localhost]
127.0.0.1  ansible_connection=local

Sau đó, trên dòng lệnh chạy các lệnh thiết lập rõ ràng mục tiêu - ví dụ:

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

Điều này cũng sẽ hoạt động khi sử dụng ansible-pull:

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

Nếu bạn quên đặt biến trên dòng lệnh, lệnh sẽ báo lỗi một cách an toàn (miễn là bạn chưa tạo nhóm máy chủ có tên 'no_hosts'!) Với cảnh báo:

skipping: no hosts matched

Và như đã đề cập ở trên, bạn có thể nhắm mục tiêu một máy duy nhất (miễn là nó nằm trong tệp máy chủ của bạn) với:

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

hoặc một nhóm với cái gì đó như:

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

0

Tôi có một tập lệnh bao bọc gọi là điều khoản buộc bạn phải chọn mục tiêu, vì vậy tôi không phải xử lý nó ở nơi khác.

Đối với những người tò mò, tôi sử dụng các bình ENV cho các tùy chọn mà vagrantfile của tôi sử dụng (thêm đối số ansible tương ứng cho các hệ thống đám mây) và để phần còn lại của các đối số ansible đi qua. Nơi tôi đang tạo và cung cấp hơn 10 máy chủ cùng một lúc tôi bao gồm thử lại tự động trên các máy chủ bị lỗi (miễn là tiến trình được thực hiện - tôi đã tìm thấy khi tạo 100 máy chủ tại một thời điểm thường sẽ có một vài lần thất bại lần đầu tiên ).

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

Một giải pháp hơi khác là sử dụng biến đặc biệt ansible_limitlà nội dung của --limittùy chọn CLI để thực thi Ansible hiện tại.

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

Không cần xác định một biến phụ ở đây, chỉ cần chạy playbook với --limitcờ.

ansible-playbook --limit imac-2.local user.yml
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.