(Phần 3) Tìm hiểu về Ansible Playbooks
Trong bài viết này, chúng ta sẽ khám phá Ansible Playbooks, về cơ bản là bản thiết kế cho các hành động tự động hóa. Playbooks cho phép chúng ta xác định một công thức với tất cả các bước mà chúng ta muốn tự động hóa theo cách có thể lặp lại, đơn giản và nhất quán. Ansible playbook cung cấp một môi trường thực thi đa máy, đa bước, mạch lạc. Trong hướng dẫn này, chúng tôi sẽ hướng dẫn bạn quy trình tạo Ansible playbook theo cách rất chi tiết.
- Playbook Ansible là gì?
- Cấu trúc của sổ tay hướng dẫn Ansible là gì?
- Làm thế nào để viết một playbook Ansible?
- Làm thế nào để chạy playbook Ansible?
- Ví dụ về playbook Ansible
- Sử dụng biến trong Ansible playbook
- Sử dụng các tác vụ có điều kiện when
- Sử dụng vòng lặp loop
- Tips sử dụng Ansible playbook
Playbook Ansible là gì?
Playbook Ansible là một trong những thành phần cơ bản của Ansible vì chúng ghi lại và thực thi cấu hình của Ansible. Nhìn chung, playbook là cách chính để tự động hóa một tập hợp các tác vụ mà chúng ta muốn thực hiện trên máy từ xa.
Chúng giúp nỗ lực tự động hóa của chúng tôi bằng cách thu thập tất cả các tài nguyên cần thiết để sắp xếp các quy trình theo thứ tự hoặc tránh lặp lại các hành động thủ công. Playbook có thể được sử dụng lại và chia sẻ giữa mọi người và được thiết kế thân thiện với con người và dễ viết bằng YAML.
Sự khác biệt giữa playbook và vai trò trong Ansible là gì?
Ansible playbook có phạm vi rộng hơn và có khả năng sắp xếp nhiều plays và vai trò trên nhiều máy chủ và nhóm khác nhau, trong khi vai trò là các thành phần tập trung hơn, nhắm vào các tác vụ và cấu hình cụ thể.
Khi nói đến cách sử dụng, Playbook thực hiện tự động hóa, trong khi vai trò được sử dụng để cấu trúc và đóng gói tự động hóa theo một hình thức có thể tái sử dụng.
Cấu trúc của sổ tay hướng dẫn Ansible là gì?
Một playbook bao gồm một hoặc nhiều task được chạy theo thứ tự cụ thể. Một plays là danh sách có thứ tự các tác vụ được chạy với nhóm máy chủ mong muốn.
Mỗi tác vụ đều được liên kết với một mô-đun chịu trách nhiệm cho một hành động và các tham số cấu hình của nó. Vì hầu hết các tác vụ đều có tính bất biến, chúng ta có thể chạy lại playbook một cách an toàn mà không có bất kỳ vấn đề nào.
Như đã thảo luận, Ansible được viết bằng YAML sử dụng phần mở rộng chuẩn .yml với cú pháp tối thiểu .
Chúng ta phải sử dụng khoảng trắng để căn chỉnh các phần tử dữ liệu có cùng thứ bậc để thụt lề. Các mục là con của các mục khác phải được thụt lề nhiều hơn các mục cha của chúng. Không có quy tắc nghiêm ngặt nào về số khoảng trắng được sử dụng để thụt lề, nhưng việc sử dụng hai khoảng trắng trong khi không được phép sử dụng ký tự Tab là khá phổ biến.
Dưới đây là một ví dụ về sổ tay hướng dẫn đơn giản chỉ có hai vở kịch, chúng ta có hai nhiệm vụ:
---
- name: Example Simple Playbook
hosts: all
become: yes
tasks:
- name: Copy file example_file to /tmp with permissions
ansible.builtin.copy:
src: ./example_file
dest: /tmp/example_file
mode: '0644'
- name: Add the user 'bob' with a specific uid
ansible.builtin.user:
name: bob
state: present
uid: 1040
- name: Update postgres servers
hosts: databases
become: yes
tasks:
- name: Ensure postgres DB is at the latest version
ansible.builtin.yum:
name: postgresql
state: latest
- name: Ensure that postgresql is started
ansible.builtin.service:
name: postgresql
state: started
Chúng ta định nghĩa rằng các vở kịch này sẽ được thực hiện với tư cách là người dùng root với tùy chọn become được đặt thành yes.
Bạn cũng có thể định nghĩa nhiều Từ khóa Playbook khác ở các cấp độ khác nhau như play, task, playbook để cấu hình hành vi của Ansible. Thậm chí, hầu hết các từ khóa này có thể được thiết lập tại thời gian chạy dưới dạng cờ dòng lệnh trong tệp cấu hình ansible, ansible.cfg hoặc inventory . Kiểm tra các quy tắc ưu tiên để hiểu cách Ansible hoạt động trong những trường hợp này.
Làm thế nào để viết một playbook Ansible?
Viết Ansible playbook bao gồm việc tạo tệp YAML chỉ định các máy chủ cần cấu hình và các tác vụ cần thực hiện trên các máy chủ này. Thông thường, theo cách thực hành tốt nhất, để chỉ định máy chủ của bạn, bạn cần phải xác định Ansible inventory file. Để đơn giản hóa mọi thứ, chúng ta sẽ sử dụng localhost:
[local]
localhost ansible_connection=local
Tiếp theo, chúng ta hãy định nghĩa một tệp play sẽ ping tới máy chủ cục bộ:
- name: Play
hosts: local
tasks:
- name: Ping my hosts
ansible.builtin.ping:
Để chạy lệnh này, chúng ta có thể sử dụng:
ansible-playbook -i inventory.ini play.yaml
PLAY [Play] ******************************************************************************************************************************************
TASK [Gathering Facts] *******************************************************************************************************************************
[WARNING]: Platform darwin on host localhost is using the discovered Python interpreter at /opt/homebrew/bin/python3.12, but future installation of
another Python interpreter could change the meaning of that path. See https://docs.ansible.com/ansible-
core/2.16/reference_appendices/interpreter_discovery.html for more information.
ok: [localhost]
TASK [Ping my hosts] *********************************************************************************************************************************
ok: [localhost]
PLAY RECAP *******************************************************************************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Những điều cần lưu ý khi bạn viết sổ tay Ansible playbook:
- YAML nhạy cảm với thụt lề, thường yêu cầu 2 khoảng trắng cho mỗi cấp độ thụt lề
- Tận dụng các biến trong playbook của bạn để làm cho chúng năng động và linh hoạt hơn.
- Biến có thể được định nghĩa ở nhiều nơi, bao gồm trong chính playbook, trong inventory, trong các tệp riêng biệt hoặc thậm chí được truyền qua dòng lệnh
- Use handlers – đây là các tác vụ đặc biệt chỉ chạy khi được tác vụ khác thông báo. Chúng thường được sử dụng để khởi động lại dịch vụ khi cấu hình thay đổi.
- Tận dụng các template – Ansible có thể sử dụng các template Jinja2 để tạo các tệp động dựa trên các biến
- Tận dụng roles - Đối với các thiết lập phức tạp, hãy cân nhắc việc sắp xếp nhiệm vụ của bạn thành các vai trò. Điều này giúp giữ cho playbook của bạn luôn sạch sẽ và làm cho nhiệm vụ của bạn có thể tái sử dụng nhiều hơn
Chúng ta có thể sử dụng cờ –limit để giới hạn việc thực thi Playbook cho các máy chủ cụ thể. Ví dụ:
ansible-playbook example-simple-playbook.yml --limit host1
Sử dụng các biến trong Ansible playbook
Biến là giá trị mà bạn có thể sử dụng lại trong Playbook hoặc các đối tượng Ansible khác. Chúng chỉ có thể chứa các chữ cái, số và dấu gạch dưới và bắt đầu bằng các chữ cái.
Biến có thể được định nghĩa trong Ansible ở nhiều cấp độ, vì vậy hãy xem thứ tự ưu tiên của biến để hiểu cách chúng được áp dụng. Ví dụ, chúng ta có thể đặt biến ở phạm vi toàn cục cho tất cả các máy chủ, ở phạm vi máy chủ cho một máy chủ cụ thể hoặc ở phạm vi phát cho một lần phát cụ thể.
Để thiết lập biến host và biến nhóm, hãy tạo các thư mục groupvars và hostvars . Ví dụ, để xác định biến cho nhóm cơ sở dữ liệu , hãy tạo tệp groupvars/databases. Thiết lập các biến mặc định chung trong tệp *groupvars/all *.
Ngoài ra, để xác định biến máy chủ cho một máy chủ cụ thể, hãy tạo một tệp có cùng tên với máy chủ trong thư mục hostsvars.
Để thay thế bất kỳ biến nào trong thời gian chạy, hãy sử dụng cờ -e .
Phương pháp trực tiếp nhất để định nghĩa biến là sử dụng khối vars ở đầu play. Chúng được định nghĩa bằng cú pháp YAML chuẩn.
- name: Example Variables Playbook
hosts: all
vars:
username: bob
version: 1.2.3
Một cách khác là định nghĩa các biến trong tệp YAML bên ngoài.
- name: Example Variables Playbook
hosts: all
vars_files:
- vars/example_variables.yml
Để sử dụng chúng trong các tác vụ, chúng ta phải tham chiếu chúng bằng cách đặt tên của chúng bên trong dấu ngoặc kép {{ username }} bằng cú pháp Jinja2 :
- name: Example Variables Playbook
hosts: all
vars:
username: bob
tasks:
- name: Add the user {{ username }}
ansible.builtin.user:
name: "{{ username }}"
state: present
Nếu giá trị của biến bắt đầu bằng dấu ngoặc nhọn, chúng ta phải trích dẫn toàn bộ biểu thức để YAML có thể diễn giải cú pháp một cách chính xác.
Chúng ta cũng có thể định nghĩa các biến có nhiều giá trị dưới dạng danh sách.
package:
- foo1
- foo2
- foo3
Bạn cũng có thể tham chiếu các giá trị riêng lẻ từ danh sách. Ví dụ, để chọn giá trị đầu tiên foo1 :
package: "{{ package[0] }}"
Một lựa chọn khả thi khác là định nghĩa các biến bằng cách sử dụng từ điển YAML. Ví dụ:
dictionary_example:
- foo1: one
- foo2: two
Tương tự như vậy, để lấy trường đầu tiên từ từ điển:
dictionary_example['foo1']
Để tham chiếu các biến lồng nhau, chúng ta phải sử dụng ký hiệu ngoặc hoặc dấu chấm. Ví dụ, để lấy giá trị examplename2 từ cấu trúc này:
vars:
var1:
foo1:
field1: example_name_1
field2: example_name_2
tasks:
- name: Create user for field2 value
user:
name: "{{ var1['foo1']['field2'] }}"
Chúng ta có thể tạo biến bằng cách sử dụng câu lệnh register để ghi lại đầu ra của lệnh hoặc tác vụ, sau đó sử dụng chúng trong các tác vụ khác.
- name: Example-2 Variables Playbook
hosts: all
tasks:
- name: Run a script and register the output as a variable
shell: "find example_file"
args:
chdir: "/tmp"
register: example_script_output
Để debug giá trị của biến:
- name: Use the output variable of the previous task
debug:
var: examplescriptoutput*
Sử dụng các tác vụ có điều kiện trong Ansible playbook
Để kiểm soát luồng thực thi trong Ansible tốt hơn, chúng ta có thể tận dụng các điều kiện. Điều kiện cho phép chúng ta chạy hoặc bỏ qua các tác vụ dựa trên việc các điều kiện nhất định có được đáp ứng hay không. Các biến, sự kiện hoặc kết quả của các tác vụ trước đó cùng với các toán tử có thể được sử dụng để tạo ra các điều kiện như vậy.
Một số ví dụ về trường hợp sử dụng có thể là cập nhật biến dựa trên giá trị của biến khác, bỏ qua tác vụ nếu biến có giá trị cụ thể, chỉ thực hiện tác vụ nếu dữ liệu từ máy chủ trả về giá trị cao hơn ngưỡng.
Để áp dụng một câu lệnh điều kiện đơn giản, chúng ta sử dụng tham số Ansible when trên một tác vụ . Nếu điều kiện được đáp ứng, tác vụ sẽ được thực thi. Nếu không, nó sẽ bị bỏ qua.
- name: Example Simple Conditional
hosts: all
vars:
trigger_task: true
tasks:
- name: Install nginx
apt:
name: "nginx"
state: present
when: trigger_task == true
Trong ví dụ trên, nhiệm vụ được thực thi khi điều kiện được đáp ứng với triggertask: true
Một mô hình phổ biến khác là kiểm soát việc thực hiện tác vụ dựa trên các thuộc tính của máy chủ từ xa mà chúng ta có thể lấy được từ facts . Hãy xem danh sách này với các facts thường dùng để có ý tưởng về tất cả các facts mà chúng ta có thể sử dụng trong các điều kiện.
- name: Example Facts Conditionals
hosts: all
vars:
supported_os:
- RedHat
- Fedora
tasks:
- name: Install nginx
yum:
name: "nginx"
state: present
when: ansible_facts['distribution'] in supported_os
Có thể kết hợp nhiều điều kiện với các toán tử logic và nhóm chúng bằng dấu ngoặc đơn:
when: (colour=="green" or colour=="red") and (size="small" or size="medium")
Sau đó, khi câu lệnh hỗ trợ sử dụng danh sách trong trường hợp chúng ta có nhiều điều kiện mà tất cả đều cần phải đúng:
when:
- ansible_facts['distribution'] == "Ubuntu"
- ansible_facts['distribution_version'] == "20.04"
- ansible_facts['distribution_release'] == "bionic"
Một lựa chọn khác là sử dụng các điều kiện dựa trên các biến đã đăng ký mà chúng ta đã xác định trong các tác vụ trước:
- name: Example Registered Variables Conditionals
hosts: all
tasks:
- name: Register an example variable
ansible.builtin.shell: cat /etc/hosts
register: hosts_contents
- name: Check if hosts file contains "localhost"
ansible.builtin.shell: echo "/etc/hosts contains localhost"
when: hosts_contents.stdout.find(localhost) != -1
Cách sử dụng vòng lặp trong Ansible playbook
Ansible cho phép chúng ta lặp lại một tập hợp các mục trong một tác vụ để thực hiện nó nhiều lần với các tham số khác nhau mà không cần viết lại. Ví dụ, để tạo một số tệp, chúng ta sẽ sử dụng một tác vụ lặp lại danh sách tên thư mục thay vì viết năm tác vụ với cùng một mô-đun.
Đọc thêm về cách sử dụng vòng lặp trong Ansible .
Để lặp lại một danh sách các mục đơn giản, hãy sử dụng từ khóa loop . Chúng ta có thể tham chiếu giá trị hiện tại với biến vòng lặp item .
- name: "Create some files"
ansible.builtin.file:
state: touch
path: /tmp/{{ item }}
loop:
- example_file1
- example_file2
- example_file3
Đầu ra của tác vụ trên sử dụng vòng lặp và mục :
TASK [Create some files] *********************************
changed: [host1] => (item=example_file1)
changed: [host1] => (item=example_file2)
changed: [host1] => (item=example_file3)
Bạn cũng có thể lặp lại các từ điển:
- name: "Create some files with dictionaries"
ansible.builtin.file:
state: touch
path: "/tmp/{{ item.filename }}"
mode: "{{ item.mode }}"
loop:
- { filename: 'example_file1', mode: '755'}
- { filename: 'example_file2', mode: '775'}
- { filename: 'example_file3', mode: '777'}
Một mô hình hữu ích khác là lặp lại một nhóm máy chủ của kho lưu trữ:
- name: Show all the hosts in the inventory
ansible.builtin.debug:
msg: "{{ item }}"
loop: "{{ groups['databases'] }}"
Bằng cách kết hợp các điều kiện và vòng lặp, chúng ta có thể chọn thực hiện tác vụ chỉ trên một số mục trong danh sách và bỏ qua đối với các mục khác:
- name: Execute when values in list are lower than 10
ansible.builtin.command: echo {{ item }}
loop: [ 100, 200, 3, 600, 7, 11 ]
when: item < 10
Cuối cùng, một lựa chọn khác là sử dụng từ khóa until để thử lại tác vụ cho đến khi điều kiện là đúng.
- name: Retry a task until we find the word "success" in the logs
shell: cat /var/log/example_log
register: logoutput
until: logoutput.stdout.find("success") != -1
retries: 10
delay: 15
Trong ví dụ trên, chúng ta kiểm tra tệp examplelog 10 lần, với độ trễ 15 giây giữa mỗi lần kiểm tra cho đến khi chúng ta tìm thấy từ success . Nếu chúng ta để tác vụ chạy và thêm từ success vào tệp examplelog sau một thời gian, chúng ta sẽ thấy tác vụ dừng thành công.
TASK [Retry a task until we find the word “success” in the logs] *********
FAILED - RETRYING: Retry a task until we find the word "success" in the logs (10 retries left).
FAILED - RETRYING: Retry a task until we find the word "success" in the logs (9 retries left).
changed: [host1]
Tips sử dụng Ansible playbook
Ghi nhớ những mẹo và thủ thuật này khi xây dựng playbook chiến lược sẽ giúp bạn làm việc hiệu quả hơn và nâng cao năng suất.
-
Giữ nó đơn giản nhất có thể Cố gắng giữ cho nhiệm vụ của bạn đơn giản. Có nhiều tùy chọn và cấu trúc lồng nhau trong Ansible và bằng cách kết hợp nhiều tính năng, bạn có thể tạo ra các thiết lập khá phức tạp. Dành thời gian để đơn giản hóa các hiện vật Ansible của bạn sẽ có lợi về lâu dài.
-
Đặt các artifacts Ansible của bạn dưới sự kiểm soát phiên bản Người ta cho rằng lưu trữ sổ tay hướng dẫn trong git hoặc bất kỳ hệ thống kiểm soát phiên bản nào khác và tận dụng những lợi ích của nó là tốt nhất.
-
Luôn đặt tên mô tả cho các tasks, plays, and playbooks Chọn những cái tên giúp bạn và những người khác hiểu nhanh chức năng và mục đích của artifacts
-
Cố gắng để dễ đọc Sử dụng thụt lề nhất quán và thêm dòng trống giữa các tác vụ để dễ đọc hơn.
-
Luôn đề cập rõ ràng đến trạng thái của nhiệm vụ Nhiều mô-đun có trạng thái mặc định cho phép chúng ta bỏ qua tham số trạng thái . Luôn tốt hơn là nêu rõ ràng trong những trường hợp này để tránh nhầm lẫn.
-
Sử dụng comment khi cần thiết Sẽ có những lúc định nghĩa nhiệm vụ không đủ để giải thích toàn bộ tình huống, vì vậy bạn có thể thoải mái sử dụng bình luận cho các phần phức tạp hơn của sổ tay hướng dẫn
All rights reserved