Tại Sao Tôi Chọn Ansible Thay Vì Các Công Cụ Khác
Sáu tháng trước, tôi đang quản lý ba server Ubuntu bằng tay — SSH vào, chạy script, và cầu trời không có gì hỏng. Khi thêm server thứ tư, tôi mới thực sự chạm tường. Nửa ngày trôi qua vì một server đang chạy nginx 1.18 trong khi các server còn lại dùng 1.24, và directive try_files hoạt động khác nhau giữa các phiên bản. Buổi chiều hôm đó tôi quyết tâm phải dùng configuration management đúng nghĩa.
Các ứng viên: Ansible, Puppet, Chef và SaltStack. Sau một cuối tuần thực sự dựng từng cái lên trên VM test (không chỉ đọc tài liệu), tôi chọn Ansible. Kể từ đó tôi chạy nó trên production mỗi tuần. Đây là những gì sáu tháng đó trông như thế nào.
So Sánh Các Phương Pháp: Ansible và Các Lựa Chọn Khác
Đọc blog chỉ giúp được đến một mức nào đó. Sự khác biệt trở nên rõ ràng ngay khi bạn thử cấu hình thứ gì đó thực tế, đó là lý do tôi dành thời gian thực hành với từng công cụ trước khi quyết định.
Script Bash Thủ Công
Script Bash là điểm xuất phát của hầu hết mọi người. Một server? Ổn thôi. Thêm server thứ hai là vết nứt xuất hiện ngay — không có idempotency, không theo dõi trạng thái, không có rollback sạch sẽ. Một script thất bại ở bước 7 trong số 12 bước sẽ để lại cho bạn một máy cấu hình dở dang không biết đường gỡ. Tôi vẫn dùng bash cho các tác vụ đơn giản một lần, nhưng đó không phải là configuration management.
Puppet và Chef
Cả hai đều là công cụ trưởng thành, đã được kiểm chứng trong thực chiến. Vấn đề nằm ở những gì đi kèm với chúng. Puppet có DSL riêng bạn cần học. Chef yêu cầu Ruby. Cả hai đều cần một master server chuyên dụng chạy 24/7. Với một kỹ sư solo hoặc nhóm hai người quản lý 15 server, dựng hạ tầng Puppet mất cả ngày — rồi sau đó duy trì nó là công việc riêng phải làm liên tục. Tôi thà dành một buổi chiều để viết playbook.
Terraform
Terraform rất tuyệt, chỉ là ở một tầng khác. Nó xử lý việc cung cấp hạ tầng: khởi động VM, tạo database, cấu hình mạng VPC. Những gì xảy ra bên trong các VM đó sau khi boot lên là một vấn đề hoàn toàn khác. Tôi dùng Terraform và Ansible cùng nhau. Cái này tạo server; cái kia cấu hình nó.
Ansible
Không cần cài agent trên các host được quản lý. Không có master server cần duy trì. Các playbook YAML đọc gần như một danh sách kiểm tra. SSH làm phần việc nặng nhọc. Với bất kỳ ai đã quen với Linux và SSH, học Ansible cảm giác như mở rộng những gì bạn đã biết hơn là học một hệ thống xa lạ từ đầu.
Khi đã quen tay, tôi rút ngắn quy trình cài đặt server từ 3 tiếng xuống còn khoảng 12 phút. Tiết kiệm thời gian kiểu này tích lũy rất nhanh khi bạn cung cấp nhiều server mỗi tháng.
Ưu và Nhược Điểm Sau Sáu Tháng
Những Gì Thực Sự Hoạt Động Tốt
- Kiến trúc không cần agent — Không cần cài gì trên các host được quản lý. Chỉ cần SSH là đủ. Triển khai trên mười server hiện có mất chưa đến một tiếng, và không cần thay đổi gì trên bản thân các server đó.
- Idempotency — Chạy cùng một playbook mười lần, kết quả vẫn như nhau. Điều này giúp an toàn khi đưa lần chạy playbook vào pipeline CI/CD mà không lo về tác dụng phụ ở lần thực thi thứ 4 hay thứ 5.
- Playbook dễ đọc — Tôi đưa một playbook cho một sysadmin junior chưa từng dùng Ansible. Anh ấy đọc từ đầu đến cuối mà không cần tôi giải thích. Mô tả YAML ánh xạ gần với ngôn ngữ thông thường theo cách mà Puppet DSL hay Chef recipes đơn giản là không làm được.
- Thư viện module khổng lồ — Cài đặt package, quản lý user, template file, quản lý service, Docker, AWS, GCP — hầu như có module cho mọi thứ. Trong sáu tháng sử dụng hàng ngày, tôi chỉ cần dùng lệnh shell thô có lẽ khoảng năm lần.
- Inventory linh hoạt — File tĩnh hoạt động tốt cho các thiết lập nhỏ cố định. Chuyển sang plugin inventory động trong AWS hoặc GCP và server đến đi mà không cần chỉnh sửa file thủ công.
Những Điểm Yếu Của Ansible
- Tốc độ khi mở rộng quy mô — Mặc định chạy tuần tự. Một playbook trên 50 server mất thời gian đáng chú ý hơn so với các công cụ có khả năng thực thi song song gốc. Cài đặt
forksgiúp ích — tôi dùngforks = 20trên production — nhưng với 200+ server thì đây thực sự trở thành điểm nghẽn. - Thông báo lỗi — Khi một task thất bại, output có thể thực sự khó hiểu. Quy trình thông thường của tôi: thêm
-vvv, pipe output ra file, tìm kiếm “FAILED” hoặc “fatal”. Không thanh lịch, nhưng hiệu quả. - Không có phát hiện drift tích hợp — Ansible không liên tục theo dõi server để phát hiện configuration drift. Nếu ai đó chỉnh sửa thủ công
/etc/nginx/nginx.confgiữa các lần chạy playbook, Ansible sẽ không biết cho đến khi bạn chạy lại. Puppet xử lý điều này natively, đây là một khoảng cách thực sự. - Độ phức tạp của ưu tiên biến — Ansible có 22 cấp độ ưu tiên biến. Khi bạn đang xử lý group vars, host vars, role defaults và extra vars cùng lúc, việc tìm ra giá trị nào thực sự thắng yêu cầu phải tra tài liệu mỗi lần.
Cấu Trúc Được Đề Xuất cho Nhóm Nhỏ và Vừa
Sau sáu tháng thử nghiệm và điều chỉnh, đây là cấu trúc tôi khuyên bắt đầu với. Nó mở rộng gọn gàng từ 3 server lên 30 mà không cần tái tổ chức lớn.
ansible/
├── inventory/
│ ├── production
│ └── staging
├── group_vars/
│ ├── all.yml
│ ├── webservers.yml
│ └── dbservers.yml
├── roles/
│ ├── common/
│ │ ├── tasks/main.yml
│ │ └── templates/
│ ├── nginx/
│ └── docker/
├── playbooks/
│ ├── site.yml
│ ├── webservers.yml
│ └── deploy.yml
└── ansible.cfg
Ba quyết định quan trọng nhất ở đây:
- Tách riêng các file inventory cho production và staging. Lần duy nhất tôi chạy một playbook phá hủy dữ liệu trực tiếp trên production thay vì staging đã dạy tôi bài học này vĩnh viễn.
- Dùng Role cho bất kỳ thứ gì bạn sẽ tái sử dụng — cài đặt nginx, cài đặt Docker, hardening bảo mật chung. Role độc lập, có thể test được, và dễ chia sẻ giữa các dự án.
- Dùng Group vars để tách biệt cấu hình theo môi trường khỏi logic playbook. Production dùng port 443; staging dùng 8443. Sự khác biệt đó thuộc về vars, không nên hardcode trong bản thân playbook.
Một file ansible.cfg tối giản nhưng hợp lý:
[defaults]
inventory = inventory/production
remote_user = ubuntu
private_key_file = ~/.ssh/id_ed25519
host_key_checking = False
forks = 10
callbacks_enabled = profile_tasks
[privilege_escalation]
become = True
become_method = sudo
Hướng Dẫn Triển Khai: Từ Không Đến Playbook Đang Chạy
Bước 1: Cài Đặt Ansible
# Trên máy control Ubuntu/Debian
sudo apt update && sudo apt install -y ansible
# Xác nhận cài đặt thành công
ansible --version
Bước 2: Tạo Inventory
File inventory cho Ansible biết server nào cần quản lý và cách nhóm chúng lại. Hãy giữ đơn giản lúc đầu.
# inventory/production
[webservers]
web01 ansible_host=192.168.1.10
web02 ansible_host=192.168.1.11
[dbservers]
db01 ansible_host=192.168.1.20
[all:vars]
ansible_user=ubuntu
ansible_ssh_private_key_file=~/.ssh/id_ed25519
Trước khi viết một playbook nào, hãy xác nhận kết nối:
ansible all -i inventory/production -m ping
Ba phản hồi pong màu xanh và bạn đã sẵn sàng.
Bước 3: Viết Playbook Đầu Tiên
Bắt đầu cụ thể. Một cấu hình baseline áp dụng cho mọi server là playbook đầu tiên có giá trị cao nhất — nó tự động chạy trên server mới và giữ các server hiện có nhất quán.
# playbooks/site.yml
---
- name: Áp dụng cấu hình chung cho tất cả server
hosts: all
become: true
tasks:
- name: Cập nhật cache apt package
apt:
update_cache: yes
cache_valid_time: 3600
- name: Cài đặt các gói cần thiết
apt:
name:
- vim
- curl
- htop
- ufw
- fail2ban
state: present
- name: Bật tường lửa UFW
ufw:
state: enabled
policy: deny
- name: Cho phép SSH qua tường lửa
ufw:
rule: allow
port: '22'
proto: tcp
- name: Đảm bảo fail2ban đang chạy
service:
name: fail2ban
state: started
enabled: yes
Bước 4: Chạy Playbook
# Chạy thử trước — xem những gì sẽ thay đổi mà không thực sự thực hiện
ansible-playbook playbooks/site.yml --check
# Áp dụng thay đổi
ansible-playbook playbooks/site.yml
# Giới hạn chỉ một số host cụ thể
ansible-playbook playbooks/site.yml --limit web01
# Chạy với output chi tiết để debug
ansible-playbook playbooks/site.yml -v
Bước 5: Tổ Chức Bằng Roles
Playbook phình to rất nhanh. Khi playbook của bạn vượt quá 50 dòng, hãy bắt đầu trích xuất logic lặp lại vào các role.
# Tạo khung cho role
ansible-galaxy init roles/nginx
Một file task role nginx tối giản:
# roles/nginx/tasks/main.yml
---
- name: Cài đặt nginx
apt:
name: nginx
state: present
- name: Sao chép cấu hình nginx
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
owner: root
group: root
mode: '0644'
notify: Restart nginx
- name: Đảm bảo nginx đang chạy
service:
name: nginx
state: started
enabled: yes
Sau đó tham chiếu nó trong playbook của bạn:
- name: Cấu hình web server
hosts: webservers
become: true
roles:
- common
- nginx
Điều Tôi Muốn Nói Với Bản Thân Sáu Tháng Trước
Hãy thiết lập môi trường staging phản chiếu chính xác production, và chạy mọi playbook ở đó trước. Tôi đã học điều này theo cách khó khăn — tôi đã test một playbook tường lửa UFW trực tiếp trên server production, tự khóa mình ra ngoài, và mất bốn mươi phút để phục hồi quyền truy cập qua console VPS. Chế độ --check bắt được hầu hết các vấn đề, nhưng không phải tất cả. Một VM tạm thời đáng để bỏ ra năm phút để khởi động.
Commit code Ansible của bạn lên Git từ ngày đầu. Playbook là infrastructure dưới dạng mã — hãy đối xử với chúng như vậy. git diff trước khi áp dụng thay đổi, git blame khi có gì đó hỏng. Tôi đã phát hiện những lỗi cấu hình theo cách này mà lẽ ra tôi đã hoàn toàn quên mất.
Đường cong học tập ngắn hơn bạn nghĩ. Tuần đầu tiên, tôi đã tự động hóa quy trình cài đặt server mà tôi đã làm thủ công suốt một năm. Đến tuần thứ tư, tôi đã ngừng hoàn toàn việc SSH vào từng server cho các tác vụ định kỳ. Hai tháng sau, onboarding một server mới đã từ công việc nửa ngày xuống còn thời gian uống một ly cà phê.

