Bối cảnh
Gần đây tôi đã gặp một vấn đề khá đau đầu khi quản lý một nhóm khoảng 75 node chạy hỗn hợp Ubuntu và CentOS. Để tiết kiệm thời gian triển khai—việc thu thập fact (dữ liệu hệ thống) có thể dễ dàng tốn thêm 3 đến 5 giây cho mỗi host—tôi đã đặt rõ ràng gather_facts: no ở đầu playbook của mình. Trên một kho máy chủ (inventory) lớn, tùy chọn đơn giản này có thể giúp bạn tiết kiệm vài phút chờ đợi các bước bắt tay SSH và quét hệ thống hệ thống.
Playbook chạy mượt mà cho đến khi một tác vụ xuất hiện yêu cầu biết hệ điều hành (OS) đang xử lý là gì. Tôi đã sử dụng câu lệnh điều kiện when để áp dụng các cấu hình riêng cho Ubuntu so với CentOS. Đó là lúc việc thực thi bị dừng lại với một thông báo lỗi màu đỏ rực.
fatal: [server-01]: FAILED! => {
"msg": "The conditional check failed. The error was: 'ansible_distribution' is undefined"
}
Quá trình gỡ lỗi
Lỗi này khá rõ ràng. Ansible đang báo cho bạn biết rằng nó không có bản ghi nào về biến có tên ansible_distribution. Trong thế giới Ansible, các biến bắt đầu bằng ansible_ thường là "facts"—các siêu dữ liệu như địa chỉ IP hoặc phiên bản OS mà module setup tự động thu thập khi bắt đầu một play.
Xem nhanh phần đầu của playbook đã tìm ra nguyên nhân chính:
---
- name: Configure Web Servers
hosts: web_servers
gather_facts: no # <-- Đây là nguyên nhân
tasks:
- name: Install Apache on Ubuntu
apt:
name: apache2
state: present
when: ansible_distribution == 'Ubuntu'
Khi bạn đặt gather_facts: no, về cơ bản bạn đang yêu cầu Ansible bỏ qua việc kiểm tra nội bộ host từ xa. Do đó, từ điển fact cục bộ sẽ trống rỗng. Khi tác vụ apt cố gắng đánh giá bản phân phối của host, nó tìm thấy một giá trị null, và toàn bộ play thất bại.
Các giải pháp
Tôi thường dựa vào một trong ba cách sửa lỗi sau, tùy thuộc vào quy mô môi trường và mức độ quan tâm đến hiệu năng.
1. Giải pháp nhanh: Bật lại thu thập Fact toàn cục
Nếu bạn chỉ quản lý một vài máy chủ, chỉ cần chuyển tùy chọn trở lại thành yes. Bạn cũng có thể đơn giản là xóa dòng đó, vì mặc định Ansible vẫn sẽ thu thập fact. Điều này tốn thêm một chút tài nguyên nhưng đảm bảo mọi biến hệ thống đều sẵn sàng để sử dụng.
- name: Configure Web Servers
hosts: web_servers
gather_facts: yes
# ... các tác vụ tiếp theo
2. Cách tiếp cận chính xác: Sử dụng Module Setup
Khi tốc độ là ưu tiên hàng đầu, bạn có thể tiếp tục tắt fact toàn cục và chỉ lấy những gì cần thiết ngay trước một tác vụ có điều kiện. Đây là phương pháp ưa thích của tôi vì nó giữ cho playbook gọn nhẹ và rõ ràng.
- name: Configure Web Servers
hosts: web_servers
gather_facts: no
tasks:
- name: Chỉ lấy fact về bản phân phối (distribution)
setup:
filter: ansible_distribution
- name: Tác vụ cụ thể cho OS
debug:
msg: "Đang chạy trên {{ ansible_distribution }}"
when: ansible_distribution is defined
Tham số filter yêu cầu Ansible bỏ qua hàng trăm fact khác về phần cứng và mạng, giúp cho lệnh gọi cụ thể này cực kỳ nhanh.
3. Sử dụng Fact Caching
Đối với các môi trường production có hàng trăm node, tôi khuyên bạn nên thiết lập bộ nhớ đệm fact (fact cache). Bằng cách sử dụng Redis hoặc các file JSON cục bộ, bạn có thể giữ gather_facts: no trong playbook trong khi vẫn lấy được dữ liệu từ lần chạy trước. Cập nhật file ansible.cfg của bạn như sau:
[defaults]
fact_caching = jsonfile
fact_caching_connection = /tmp/ansible_facts
fact_caching_timeout = 86400 # Fact có hiệu lực trong 24 giờ
Các bước xác minh
Để xác nhận cách sửa lỗi của bạn thực sự hiệu quả mà không cần chạy toàn bộ playbook, hãy thử lệnh ad-hoc này từ terminal của bạn:
ansible <tên_host> -m setup -a "filter=ansible_distribution"
Một lần kiểm tra thành công sẽ trả về một khối JSON sạch sẽ như thế này:
server-01 | SUCCESS => {
"ansible_facts": {
"ansible_distribution": "Ubuntu"
},
"changed": false
}
Bài học kinh nghiệm
- Lưu ý về sự đánh đổi: Tắt fact là một sự tối ưu hóa mạnh mẽ, nhưng nó tạo ra một điểm mù cho logic playbook của bạn. Luôn kiểm tra kỹ các câu lệnh
whencủa bạn trước khi tắt nó. - Xử lý lỗi khéo léo: Khi viết mã cho môi trường production, hãy sử dụng
when: ansible_distribution is defined and ansible_distribution == 'Ubuntu'. Điều này ngăn việc thiếu fact làm hỏng toàn bộ quá trình chạy. - Lọc Fact của bạn: Bạn hiếm khi cần toàn bộ cấu hình hệ thống. Hãy sử dụng module
setupvới các bộ lọc cụ thể để lấy dữ liệu bạn cần mà không bị mất 10 giây chờ đợi hiệu năng.

