NỘI DUNG
Tiếp theo series Ansible. Ở bài hôm nay mình sẽ giới thiệu đến bạn làm quen và sử dụng Key concepts trong Ansible. Đây là phần khá quan trọng vì toàn cấu trúc sẽ nằm ở bài này.
Mời bạn tham khảo nhé.
Nội dung Key concepts trong Ansible
- Inventory
- yaml
- Playbooks-Play
- Tasks
- Modules
- Roles
- Variables
- Templates
- Handlers
- Facts
- Conditionals và loops
- Ansible vauls
1. Inventory
Inventory là một file lưu danh sách các host được quản lý bởi ansible, file này nằm tại đường dẫn /etc/ansible/hosts.
. Các hosts có thể được viết tắt ở dạng parten, hoặc có thể được gom nhóm lại với nhau thành một Group. Ngoài việc lưu các hosts thì file còn lưu một loạt các biến cấu hình cho việc hoạt động của ansible. Và định dạng ini hoặc yaml
Cấu hình ví dụ
#Sample Inventory File Server1.dotrungquan.info Server2.dotrungquan.info [mail] Server3.dotrungquan.info Server4.dotrungquan.info [db] Server5.dotrungquan.info Server6.dotrungquan.info [web] Server7.dotrungquan.info Server8.dotrungquan.info [all_servers:children] mail db web
Trong cấu hình cách khai báo trên với [mail], [db], [web]. Đây là cách khai báo cho 1 group các server với nhau. [mail] là tên group.
Bây giờ mình sẽ chạy test với lệnh ping trê gropu [mail]
Cú pháp: ansible mail -m ping
Còn [all_servers:children] là cách khai báo group các group với nhau.
Bên cạnh đó, Ansible còn cung cấp một số params phục vụ cho việc truy cập vào server mà bạn đã khai báo trong inventory file dễ dàng hơn. Cụ thể như server nào đó muốn truy cập vào cần cung cấp user và password, hay server đó không phải là linux mà là window, thì việc login vào cũng có phần khác. Xem ví dụ để hiểu thêm về các params mà ansible đã cung cấp nhé.
# Windows win_server1 ansible_host=win_server1.dotrungquan.info ansible_connection=winrm ansible_user=administrator ansible_password=Win$Pass win_server2 ansible_host=win_server1.dotrungquan.info ansible_connection=winrm ansible_user=administrator ansible_password=Win$Pass # Linux linux_server1 ansible_host=linux_server1.dotrungquan.info ansible_connection=ssh ansible_user=root ansible_ssh_pass=Nhap_Vao_Mat_khau-root linux_server2 ansible_host=linux_server2.dotrungquan.info ansible_connection=ssh ansible_user=root ansible_ssh_pass=Nhap_Vao_Mat_khau-root
Đối với server window, Ansible cung cấp kiểu connect là winrm. Bên cạnh đó cách khai báo password cũng khác với Linux. Ở window sẽ sử dụng param ansible_ssh_pass, còn linux là ansible_password. Các bạn lưu ý điều này nhé.
2. YAML và làm quen với YAML
YAML là gì?. YAML là một ngôn gnữ cấu hình định dạng dữ liệu. Hầu như tất cả playbooks trong Ansible được viết bằng YAML. Trong ansible thì phần này khá quan trong vì các phần còn lại hầu như phụ thuộc hoàn toàn vào YAML. Playbook Ansible được viết theo định dạng cụ thể được gọi là YAML. Nếu bạn đã làm việc với các định dạng cấu trúc dữ liệu khác như XML hoặc JSON, bạn sẽ có thể dễ dàng học nó. Cũng đừng lo lắng nếu bạn chưa biết gì, ban đầu khi học nó mình cũng khá rối tuy nhiên sau một thời gian mình thấy nó thật sự rất đơn giản. File YAML được dùng để thể hiện dữ liệu. Dưới đây là so sánh nhanh dữ liệu mẫu ở ba định dạng khác nhau.
Trong YAML có 3 kiểu để biểu diễn giá trị như sau:
2.1 Key Value Pair (Cặp khoá vs giá trị):
Dữ liệu được thể hiện bởi kiểu khoá và giá trị (key và value). Trong YAML, khóa và giá trị được phân tách bằng dấu hai chấm (:). Luôn phải có khoảng trắng theo sau dấu hai chấm.
2.2. Mảng trong YAML:
Các phần tử trong mảng sẽ được thể hiện bởi dấu gạch ngang ( – ). Cần có khoảng trắng trước mỗi mục. Số lượng khoảng trắng cần bằng nhau trước các phần tử của một mảng. Chúng ta hãy xem xét kỹ hơn về các dấu khoảng trắng trong YAML.
Ví dụ ở đây ta có một object là Canho. Trong đó có 3 thuộc tính là phongkhach, phongngu và bep đếu ngang hàng với nhau
Canho: Phong khach: 1 Phong ngu: 3 Bep: 1
Lưu ý số lượng khoảng trắng trước mỗi thuộc tính sẽ chỉ ra mối quan hệ cha con. Như ở đây, trước 3 thuộc tính đó có cùng số khoảng trắng, nghĩa là 3 thuộc tính đó nằm trong Canho. Nhưng điều gì sẽ xảy ra nếu chúng ta có thêm không gian cho Phong ngu và bep
Canho: Phong khach: 1 Phong ngu: 3 Bep: 1
Theo cấu trúc trên thì lúc này Phong ngu và bep sẽ là con của thuộc tính Phong khach và phong khách là thuộc tính con của canho. Vì vậy, số lượng khoảng trắng trong YAML rất quan trọng. Đôi lúc bạn có thể chạy script bị báo lỗi nếu nhầm khoảng trắng với dấu tab.
2.3.Dạng Dictionary trong YAML:
Dạng này chỉ cần biểu diễn khoảng trắng trước các thuộc tính của object. Điểm khác biệt của dạng Dictionary và Array là các thuộc tính liệt kê dạng Dictionary thì không có thứ tự. Trong khi Array thì ngược lại. Nên là ví dụ bạn khai báo như:
Tasks: - install httpd - start httpd
Sẽ khác với
Tasks: - start httpd - install httpd
Ví dụ trên được viết theo dạng Array, tức ansible sẽ đọc tuần tự từ trên xuống. Như vậy nếu start httpd trước khi install httpd thì sẽ xảy ra lỗi vì hệ thống không tìm thấy service httpd để start.
3. Playbook
Playbook là gì?. Playbook giống như một kịch bản cho các con server. Playbooks sẽ được viết bằng định dạng YAML
Trong playbooks, chúng ta sẽ xác định những gì cần phải làm. Vì vậy phần YAML và làm quen với YAML các bạn cần nắm được nội dung và cách viết nhé.
Trong playbooks sẽ chứa một tập hợn các activities (hoạt động) hay các tasks (nhiệm vụ) sẽ được chạy trên một hay một nhóm servers. Trong đó task là một hành động duy nhất được thực hiện trên server, ví dụ như cài gói service nào đó, hay bật tắt service.
Ví dụ về một Playbook mẫu
# Simple Ansible Playbook1.yml - name: Play 1 hosts: node1 tasks: - name: Execute command "date" command: date - name: Execute script on server script: test_script.sh - name: Install nginx service yum: name: nginx state: present - name: Start web server service: name: nginx state: started
Trên đây là một playbook đơn giản chứa một kịch bản có tên Play 1 (name: Play 1).
Kịch bản này sẽ được chạy trên server (hosts: node1). Nếu bạn muốn thực hiện cùng các nhiệm vụ đó trên nhiều con server thì bạn chỉ cần liệt kê tên server hay tên group server. Khai báo tên server hay group server sẽ nằm trong phần 1 inventory
Có tổng cộng 4 nhiệm vụ cần được chạy cho server. Nhiệm vụ lần lượt là:
- chạy lệnh date
- chạy file test_script.sh
- cài đặt dịch vụ nginx
- start dịch vụ nginx vừa cài trên
Các tasks trong playbooks được liệt kê dạng array. Phần trên đã có nói đến, nếu đổi chỗ thứ tự các tasks thì sẽ gây ảnh hưởng không nhỏ nếu những task đó có mối liên quan với nhau. Như ta thấy task thứ 3 và task thứ 4 có mối liên hệ với nhau. Nếu để task start nginx lên trước task install thì sẽ có lỗi xảy ra nếu server hoàn toàn chưa được cài nginx.
Cuối cùng, khi bạn đã viết xong một playbook, vậy làm cách nào để chạy nó. Rất đơn giản. Ansible cung cấp cho bạn cú pháp như sau:
ansible-playbook
ansible-playbook playbook1.yml
4. Modules
Ansible cung cấp rất nhiều module, không thể trình bày hết các module trong bài viết này, nên mình sẽ giới thiệu một vài module phổ biến thường dùng cho những thao tác đơn giản.
- System: Bao gồm các module như User, Group, Hostname, Systemd, Service, v.v…
- Commands: Thường có module con như Command, Expect, Raw, Script, Shell, v.v…
- Files: Các module làm việc với file như Copy, Find, Lineinfile, Replace, v.v…
- Database: Ansbile cũng support mạnh mẽ những module làm việc với DB như Mongodb, Mssql, Mysql, Postgresql, Proxysql, v.v…
- Cloud: Ansible cũng không quên kết hợp với các dịch vụ clound nổi tiếng như Amazon, Google, Docker, Linode, VMware, Digital Ocean, v.v…
- Windows: Mạnh mẽ với những module như win_copy, win_command, win_domain, win_file, win_shell
Và còn hàng trăm module khác đã được ansible cung cấp sẵn.
Tham khảo các Module của Ansible tại đây: https://docs.ansible.com/ansible/2.8/modules/modules_by_category.html
Ví dụ: Mình sẽ viết một đoạn sử dụng module Commands để lấy IP các host
- name: Play 1 hosts: node1 tasks: - name: Hien thi IP command: cmd: ip a
Ví dụ: Sử dụng System modules để thay đổi timezone
name: Play 1 hosts: node1 tasks: - name: Change time timezone: name: Asia/Ho_Chi_Minh
Thử kiểm tra timezone đã được thay đổi chưa. MÌnh sử dụng nhanh lệnh này để kiểm tra
ansible node1 -a "timedatectl"
5. VARIABLES (Biến)
Tiếp theo mình sẽ hướng dẫn bạn làm quen với biến. Vậy biến là gì? Cũng giống như các ngôn ngữ lập trình khác, biến được sử dụng để lưu trữ các giá trị và có thể thay đổi giá trị được. Nói cách khác biến là một từ khóa biểu diễn cho một giá trị. Sử dụng khi cần áp dụng các thiết lập với các giá trị khác nhau trên các hệ thống, môi trường khác nhau.
Nếu bạn đã từng học lập trình C thì bạn đã từng sử dụng qua khai báo biến như ví dụ:
type variable_list;
int a = 10, b = 20; #Khai báo 2 biến kiểu số nguyên
float = 20,8; # Khai báo 2 biến số thực
char c = 'A'; #khai bái biến kiểu ký tự
- Phân loại biến: (Có 2 loại)
- Build-in: Biến có sẵn của Ansible (Special Variables — Ansible Documentation)
- Custom: Biến do người dùng tự định nghĩa
- Quy ước đặt tên biến (custom): Không trùng các từ khóa của python, ansible
- Biến có thể được định nghĩa tại nhiều vị trí: Trong task nằm trong playbook, trong inventory, trong file riêng
- Kiểu dữ liệu của biến: Strong, array, dictionary
- Truy cập biến sửa dụng cú pháp: {{<tên biến>}}
- Register một biến từ output một task trong ansible
5.1 Định nghĩa biến trong Inventory
Bạn hãy mở file Inventory và định nghĩa tại đây. Bên dưới là một mẫu minh họa
[dc1]
node1
node2
[dc1:vars]
atp_serer=ntp.dotrungquan.info #Biến có tên atp_serer gán với giá trị ntp.dotrungquan.info
proxy=proxy.dotrungquan.info #Biến có tên atp_serer gán với giá trị proxy.dotrungquan.info
5.2. Định nghĩa biến trong Task
Biến này được định nghĩa trong phần task của playbook
- host: webserver
task:
- debug:
var: http_port
vars:
http_port: 80
5.3. Định nghĩa biến trong file riêng
Bạn hãy tạo một file riêng và định nghĩa biến cho nó. Ở đây mình sẽ tạo file có tên là external_vars.yml
trong /etc/ansible/vars
mkdir -p /etc/ansible/vars
touch /etc/ansible/vars/external_vars.yml
- host: webserver
task:
- debug:
var: http_port
vars_files: /etc/ansible/vars/external_vars.yml
5.4. Output của lệnh khác
Ngoài ra biến bạn có thể lấy từ output của lệnh khác với kết quả của lệnh trước cho lệnh sau.
tasks:
- name: init deploy dir
shell: echo ansible-deploy-$(date +%y%m%d-%H%M%S-%N)
# https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html
register: output
- debug:
var: output
Xem ví dụ dưới đây để hiểu rõ cách khai báo biến và sử dụng biến trong ansible như thế nào nhé.
- name: Print car's information hosts: localhost vars: car_model: "BMW M3" country_name: USA title: "Systems Engineer" tasks: - name: Print my car model command: echo "My car's model is {{ car_model }}" - name: Print my country command: echo "I live in the {{ country_name }}"
Để khai báo biến, chúng ta sẽ sử dụng thuộc tính vars mà ansible đã cung cấp. car_model
sẽ là key, “BMW M3” sẽ là value. Bên dưới để sử dụng biến car_model ta sử dụng cặp dấu ngoặc nhọn và tên biến {{ car_model }}
6. CONDITIONS
Ansible cũng cho phép bạn điều hướng lệnh chạy hay giới hạn phạm vi để run câu lệnh nào đó. Nói khác đi là nếu điều kiện thoả thì câu lệnh đó mới được thực thi.
Bây giờ ta thử giải một đề bài toán như sau: Nếu tuổi trên 22 thì in ra màn hình là “Tôi đã tốt nghiệp” và ngược lại nếu tuổi dưới 22 thì in là “Tôi chưa tốt nghiệp”. Lúc này chúng ta sẽ sử dụng thuộc tính when mà ansible cung cấp để giới hạn phạm vi chạy của câu lệnh.
#Simple playbook.yml
-
name: Toi da tot nghiep chưa
hosts: localhost
vars:
age: 25
tasks:
-
command: echo "Toi chua tot nghiep"
when: age < 22
-
command: echo "Toi da tot nghiep"
when: age >= 22
register
Ansible còn cung cấp một thuộc tính khá mạnh mẽ là register. Register giúp nhận kết quả trả về từ một câu lệnh. Sau đó ta có thể dùng kết quá trả về đó cho những câu lệnh chạy sau đó.
Ví dụ ta có bài toán như sau: kiểm tra trạng thái của service httpd, nếu start thất bại thì gửi mail thông báo cho admin.
#Sample ansible playbook.yml
-
name: Check status of service and email if its down
hosts: localhost
tasks:
- command: service httpd status
register: command_output
- mail:
to: Admins
subject: Service Alert
body: "Service is down"
when: command_output.stdout.find("down") != -1
Nhờ vào thuộc tính register, kết quả trả về sẽ được chứa vào biến command_output. Từ đó ta sử dụng tiếp các thuộc tính của biến command_output là stdout.find để tìm chữ “down” có xuất hiện trong nội dung trả về không. Nếu không tìm thấy thì kết quả sẽ là -1.
7. LOOPS
Bạn còn nhớ module yum không. Module yum trong ansible playbook giúp ta cài đặt hay xoá một gói service nào đó. Trong ví dụ ở phần playbook, chúng ta chỉ có cài một gói service. Nhưng nếu server yêu cầu cài thêm nhiều gói service khác như mysql, php thì sao nhĩ. Như bình thường chúng ta sẽ viết như sau:
# Simple Ansible Playbook1.yml
-
name: Install packages
hosts: localhost
tasks:
- name: Install httpd service
yum:
name: httpd
- name: Install mysql service
yum:
name: mysql
- name: Install php service
yum:
name: php
Ở đây mới ví dụ 3 service cần cài mà phải viết lập lại các thuộc tính name, module yum đến 3 lần. Nếu server cần cài lên đến 100 gói service thì việc ngồi copy/paste cũng trở nên vấn đề đấy. Thay vào đó, chúng ta sẽ sử dụng chức năng loops mà ansible đã cung cấp để để viết.
#Simple Ansible Playbook1.yml
-
name: Install packages
hosts: localhost
tasks:
- name: Install all service
yum: name="{{ item }}" state=present
with_items:
- httpd
- mysql
- php
with_items
là một lệnh lặp, thực thi cùng một tác vụ nhiều lần. Mỗi lần chạy, nó lưu giá trị của từng thành phần trong biến item.
8. ROLES
Nếu bạn có nhiều server hay nhiều group server và mỗi server thực thiện những tasks riêng biệt. Và khi này nếu viết tất cả vào cùng một file playbook thì khá là xấu code và khó để quản lý.
Ansible đã cung cấp sẵn chức năng roles, về đơn giản nó sẽ giúp bạn phân chia khu vực với nhiệm vụ riêng biệt.
Ví dụ bạn có một kịch bản như bên dưới:
#Simple Ansible setup_application.yml
-
name: Set firewall configurations
hosts: web
vars:
http_port: 8081
snmp_port: 160-161
inter_ip_range: 192.0.2.0
tasks:
- firewalld:
service: https
permanent: true
state: enabled
- firewalld:
port: "{{ http_port }}"/tcp
permanent: true
state: disabled
- firewalld:
port: "{{ snmp_port }}"/udp
permanent: true
state: disabled
- firewalld:
source: "{{ inter_ip_range }}"/24
zone: internal
state: enabled
Mục tiêu của file playbook setup_application.yml này là cấu hình tường lửa cho group server về web.
Bây giờ chúng ta sẽ cắt nhỏ file playbook này ra thành những file có chức năng riêng biệt như file chỉ chưa định nghĩa biến, hay file chứa định nghĩa tasks. Trước khi cắt file playbook nhỏ gọn lại, ta cần tạo cấu trúc thư mục như sau để ansible nhận biết được các thành phần ta đã khai báo.
Trong bài viết này mình đã chi ra những Key concepts và một số thông tin sử dụng
Hãy tham khảo các bài viết tiếp theo trong series về Ansible nhé.
Xem thêm các bài viết liên quan về Ansible