Menu
ESC

Nhập từ khóa để tìm kiếm

↑↓ Di chuyển
Enter Mở
ESC Đóng

Đang tải...

Bài 37 — Configuration Management: Ansible, Puppet

Operations Management for Tech Bài 37/60

Mở đầu — vì sao bài này quan trọng

Hãy tưởng tượng bạn là kỹ sư vận hành cho một công ty fintech ở TP.HCM. Ngày thứ Hai, hệ thống chạy trơn tru trên 30 server. Đến thứ Sáu, một trong 30 server đó bắt đầu trả lỗi 500 ngẫu nhiên. Bạn SSH vào từng máy, so sánh thủ công phiên bản Nginx, nội dung file cấu hình, biến môi trường... và phát hiện ra: server số 17 đang chạy phiên bản OpenSSL cũ hơn ba tháng, vì lần patch trước có người quên nó. Cả nhóm mất một buổi chiều chỉ để tìm ra sự khác biệt vô hình đó.

Vấn đề này có một cái tên: configuration drift (trôi dạt cấu hình). Khi bạn quản lý server bằng tay, mỗi máy dần trở thành một "bông tuyết" (snowflake server) — độc nhất, không lặp lại, và không ai dám đụng vào vì sợ vỡ. Configuration Management (Quản lý cấu hình) chính là kỷ luật kỹ thuật sinh ra để giết chết vấn đề này.

Ở Bài 36, bạn đã học cách dùng Terraform để tạo ra hạ tầng — server, network, load balancer. Nhưng Terraform dừng lại ở ranh giới "máy đã có". Câu hỏi tiếp theo là: bên trong mỗi máy đó cần cài gói gì, file config chứa nội dung gì, service nào phải chạy? Đó chính xác là địa hạt của Bài 37. Configuration Management biến việc "chăm sóc từng con server như thú cưng" thành "quản lý cả đàn gia súc theo một chuẩn duy nhất, có thể tái tạo".

Khái niệm cốt lõi

Configuration Management giải quyết bài toán gì

Bản chất của Configuration Management là quản lý state (trạng thái) của server một cách khai báo và lặp lại được. Cụ thể, nó trả lời ba câu hỏi:

  • Package nào phải được cài? Ví dụ: Nginx 1.24, PostgreSQL client 15, Python 3.11.
  • File config phải có nội dung gì? Ví dụ: /etc/nginx/nginx.conf phải chứa đúng block cấu hình worker và upstream.
  • Service nào phải đang chạy? Ví dụ: nginxnode-exporter phải ở trạng thái runningenabled (tự khởi động khi reboot).
Điểm mấu chốt nằm ở tư duy desired state (trạng thái mong muốn). Bạn không viết ra các bước phải làm mà mô tả kết quả cuối cùng phải như thế nào. Tool sẽ tự so sánh trạng thái hiện tại với trạng thái mong muốn, rồi chỉ thực hiện những thay đổi cần thiết để lấp khoảng cách.

Idempotency — tính bất biến khi lặp lại

Đây là khái niệm quan trọng nhất trong bài này. Idempotency nghĩa là: bạn chạy cùng một cấu hình một lần hay một trăm lần, kết quả cuối cùng vẫn giống hệt nhau, và không gây tác dụng phụ.

So sánh hai cách viết:

Cách mệnh lệnh (imperative) — KHÔNG idempotent

echo "user vietcos;" >> /etc/nginx/nginx.conf

Chạy 3 lần => dòng này bị thêm 3 lần => file hỏng

Cách khai báo (declarative) — idempotent, dùng Ansible

  • name: Đảm bảo dòng user tồn tại trong nginx.conf
lineinfile: path: /etc/nginx/nginx.conf line: "user vietcos;" regexp: "^user "

Chạy 100 lần => dòng này chỉ có đúng 1 bản

Với công cụ Configuration Management, bạn mô tả "dòng này phải tồn tại". Nếu đã có, tool không làm gì. Nếu chưa có, tool thêm vào. Nếu sai, tool sửa lại. Đây chính là điều khiến bạn có thể chạy lại cấu hình mỗi giờ để chống drift mà không sợ làm hỏng gì.

Push vs Pull — hai triết lý vận hành

Đây là trục phân loại quan trọng khi so sánh các tool, chính là cột "Mode" trong ghi chú gốc của bài.

ToolModeNgôn ngữCần agent?Đặc điểm
AnsiblePush (agentless)YAMLKhông (chỉ cần SSH)Đơn giản, dễ bắt đầu, control node đẩy config qua SSH
PuppetPull (agent-based)Puppet DSLCó (puppet agent)Mạnh cho fleet lớn, agent tự kéo config định kỳ
ChefPull (agent-based)Ruby DSLCó (chef-client)Linh hoạt cao, đường học dốc hơn
SaltStackCả haiYAMLTùy chọnNhanh, dùng message bus, hợp fleet cực lớn
Push model (Ansible): Bạn có một máy điều khiển (control node). Khi muốn thay đổi, bạn chạy lệnh, và control node dùng SSH đẩy cấu hình xuống các máy đích. Ưu điểm: không cần cài gì lên máy đích, dễ hiểu, thời điểm thay đổi nằm trong tay bạn. Nhược điểm: một máy mới bật lên sẽ không tự nhận config cho tới khi bạn chủ động chạy.

Pull model (Puppet, Chef): Mỗi máy đích cài một agent. Agent này định kỳ (thường 30 phút một lần) tự kết nối về server trung tâm, kéo về "catalog" (bản mô tả trạng thái mong muốn của riêng nó) và tự áp dụng. Ưu điểm: chống drift tự động, máy mới tự cấu hình hóa khi agent chạy lần đầu, quản lý tốt fleet hàng nghìn máy. Nhược điểm: phải vận hành thêm hạ tầng master + agent, đường học dốc hơn.

Vị trí trong bức tranh lớn

Configuration Management khác với các công cụ lân cận mà bạn đã hoặc sẽ học:

  • Terraform (Bài 36): provisioning — tạo ra máy/hạ tầng. "Có server chưa?"
  • Configuration Management (Bài này): cấu hình bên trong máy đã có. "Máy có đúng package, config, service chưa?"
  • Container image / Docker (Bài 42): đóng gói ứng dụng thành image bất biến. Trong thế giới container, một phần vai trò của Config Management được thay bằng việc build image.
Một cách nhớ đơn giản: Terraform lo cái vỏ, Ansible/Puppet lo cái ruột.

Tình huống thực tế

Tình huống 1 — Sàn TMĐT ở Hà Nội chuẩn hóa 40 web server bằng Ansible

Một công ty thương mại điện tử tại Hà Nội có 40 web server chạy Nginx + PHP-FPM. Trước đây đội DevOps cài đặt bằng tay và script bash rời rạc. Kết quả: có máy chạy PHP 8.1, có máy PHP 8.2; timeout của Nginx mỗi máy một khác. Mỗi lần đưa tính năng mới lên là một lần hồi hộp vì không chắc môi trường đồng nhất.

Họ chuyển sang Ansible. Toàn bộ mô tả server được đóng gói thành một role tên webserver, gồm: cài PHP 8.2 và Nginx 1.24, đẩy file nginx.conf từ template (với các biến như số worker tính theo số CPU), đảm bảo service php-fpmnginx đang chạy. Họ định nghĩa inventory 40 máy, và chạy một lệnh duy nhất: ansible-playbook -i production site.yml.

Diễn giải: Lần chạy đầu tiên mất 12 phút cho cả 40 máy chạy song song. Ansible báo cáo có 6 máy bị "changed" (nghĩa là 6 máy trước đó lệch chuẩn, giờ đã được kéo về đúng). Từ đó, mỗi sáng thứ Hai họ chạy lại playbook như một bài kiểm tra sức khỏe — nếu có máy nào bị ai đó sửa tay giữa tuần, lần chạy tiếp theo sẽ tự động khôi phục về chuẩn.

Bài học: Với fleet vừa (vài chục tới vài trăm máy) và đội chưa quen công cụ phức tạp, Ansible là điểm khởi đầu lý tưởng vì agentless — chỉ cần SSH là chạy được, không phải dựng thêm hạ tầng master.

Tình huống 2 — Ngân hàng số ở Singapore chọn Puppet cho fleet 2.000 máy

Một ngân hàng số ở Singapore vận hành hơn 2.000 máy chủ, trong đó nhiều máy nằm trong vùng mạng cô lập vì yêu cầu tuân thủ (compliance). Họ cần đảm bảo mọi máy, mọi lúc đều tuân thủ chuẩn bảo mật: SSH phải tắt đăng nhập bằng mật khẩu, phải cài agent giám sát, phải có đúng cấu hình firewall.

Với quy mô này, mô hình push của Ansible bắt đầu đuối: đẩy SSH tới 2.000 máy tuần tự thì chậm, và không có gì đảm bảo một máy vừa reboot lúc 2 giờ sáng đã đúng chuẩn. Họ chọn Puppet. Mỗi máy chạy puppet agent kéo catalog về mỗi 30 phút. Nếu một quản trị viên lỡ tay bật lại SSH password login lúc 3 giờ chiều, thì chậm nhất 30 phút sau, Puppet agent tự phát hiện lệch và tắt lại — không cần con người can thiệp.

Diễn giải: Điểm quyết định ở đây là compliance liên tục và tự phục hồi. Đội security không muốn phụ thuộc vào việc "ai đó nhớ chạy playbook". Họ muốn hệ thống tự đảm bảo trạng thái đúng 24/7. Pull model của Puppet cho đúng điều đó, đổi lại là chi phí vận hành Puppet master và quản lý chứng chỉ agent.

Bài học: Không có tool "tốt nhất" tuyệt đối. Ở quy mô lớn và ràng buộc compliance chặt, mô hình pull/agent-based như Puppet thắng thế nhờ khả năng tự phục hồi liên tục.

Tình huống 3 — Startup SaaS ở Đà Nẵng và bài học "config như code"

Một startup SaaS ở Đà Nẵng với đội 4 người dùng Ansible nhưng lưu playbook rải rác trên máy cá nhân, không đưa vào Git. Một hôm, kỹ sư chính nghỉ phép, server staging cần cấu hình lại. Không ai tìm được phiên bản playbook mới nhất, cuối cùng dựng lại thủ công và... sai lệch so với production.

Sau sự cố, họ áp dụng nguyên tắc cấu hình là code: mọi playbook/role đưa vào Git, review qua Pull Request, và chạy qua CI/CD. Mỗi khi merge vào nhánh chính, pipeline tự chạy playbook lên staging trước, chạy --check (chế độ dry-run của Ansible) để xem trước thay đổi, rồi mới áp dụng production.

Diễn giải: Giá trị thật của Configuration Management không chỉ nằm ở công cụ, mà ở việc cấu hình trở thành tài sản có phiên bản, review được, tái tạo được. Ai cũng đọc được server "phải như thế nào" chỉ bằng cách đọc Git.

Bài học: Tool chỉ là một nửa. Nửa còn lại là quy trình: đưa mọi thứ vào version control và pipeline.

Hướng dẫn từng bước

Dưới đây là lộ trình dựng một cấu hình Ansible cơ bản để quản lý một fleet web server — cách nhanh nhất để bắt đầu vì không cần agent.

Bước 1 — Cài Ansible trên control node. Chỉ cần một máy có Ansible và SSH tới các máy đích:

sudo apt update && sudo apt install -y ansible
ansible --version

Bước 2 — Khai báo inventory (danh sách máy). Tạo file inventory.ini nhóm các máy theo vai trò:

[webservers]
web01 ansible_host=10.0.1.11
web02 ansible_host=10.0.1.12

[webservers:vars] ansible_user=deploy

Bước 3 — Viết playbook với desired state. Tạo site.yml mô tả trạng thái mong muốn, chú ý mỗi task đều idempotent:

- hosts: webservers
  become: true
  tasks:
    - name: Cài Nginx
      apt:
        name: nginx
        state: present
        update_cache: true

- name: Đẩy file cấu hình từ template template: src: nginx.conf.j2 dest: /etc/nginx/nginx.conf notify: restart nginx

- name: Đảm bảo Nginx đang chạy và tự khởi động service: name: nginx state: started enabled: true

handlers: - name: restart nginx service: name: nginx state: restarted

Bước 4 — Dry-run trước khi áp dụng. Luôn xem trước thay đổi bằng chế độ check:

ansible-playbook -i inventory.ini site.yml --check --diff

Bước 5 — Áp dụng và đọc báo cáo. Chạy thật và đọc dòng tổng kết ok / changed / failed:

ansible-playbook -i inventory.ini site.yml

ok là task đã đúng trạng thái (không đổi), changed là task vừa được sửa để đúng chuẩn. Chạy lại lần hai, lý tưởng là changed=0 — bằng chứng cho tính idempotent.

Bước 6 — Đưa vào Git và CI/CD. Commit toàn bộ playbook, template, inventory vào repo. Cấu hình pipeline chạy --check khi mở PR, và áp dụng thật khi merge.

Lỗi thường gặp & mẹo

  • Viết task không idempotent. Dùng module command/shell để chạy lệnh thô là cạm bẫy phổ biến nhất, vì Ansible không biết trạng thái trước đó nên lần nào cũng chạy lại. Mẹo: ưu tiên các module chuyên dụng (apt, template, lineinfile, service). Nếu buộc phải dùng shell, hãy thêm creates: hoặc changed_when: để nó biết khi nào cần chạy.
  • Không kiểm tra dry-run trước khi áp production. Áp thẳng một thay đổi lớn lên toàn fleet có thể gây sự cố diện rộng. Luôn chạy --check --diff và cân nhắc --limit để thử trên một máy trước.
  • Nhầm vai trò giữa Terraform và Config Management. Đừng cố dùng Ansible để tạo VPC hay đừng cố nhét toàn bộ logic cài đặt package vào Terraform provisioner. Ranh giới rõ ràng: Terraform tạo máy, Config Management cấu hình bên trong.
  • Bỏ quên handler và trạng thái service. Sửa file config mà quên restart service thì thay đổi không có hiệu lực. Dùng notify + handlers để chỉ restart khi config thực sự đổi — tránh restart thừa gây gián đoạn.
  • Hardcode giá trị thay vì dùng biến/template. Cùng một role nên chạy được cho cả staging và production nhờ biến khác nhau. Dùng template Jinja2 (.j2) và group_vars thay vì copy-paste nhiều file.
  • Mẹo chống drift: Với mô hình push như Ansible, đặt một cron/CI chạy playbook định kỳ (ví dụ mỗi đêm) để tự kéo các máy lệch chuẩn về đúng — mô phỏng hành vi tự phục hồi của mô hình pull.
  • Mẹo bảo mật: Đừng để mật khẩu, API key trần trong playbook. Dùng Ansible Vault để mã hóa secret (chi tiết về quản lý secret sẽ được nói ở Bài 33).

Bài tập thực hành

  • Phân biệt push/pull. Cho ba tình huống: (a) fleet 15 máy, đội 2 người mới học; (b) fleet 3.000 máy yêu cầu compliance liên tục; (c) cần máy mới tự cấu hình ngay khi khởi động. Với mỗi tình huống, chọn mô hình push hay pull và giải thích trong 2–3 câu.
  • Chứng minh idempotency. Dựng một playbook Ansible cài Nginx và đẩy một file index.html. Chạy hai lần liên tiếp. Ghi lại số changed ở mỗi lần và giải thích vì sao lần hai phải là changed=0.
  • Sửa task không idempotent. Cho task sau, hãy viết lại cho idempotent:
   - shell: echo "127.0.0.1 app.local" >> /etc/hosts
   
(Gợi ý: dùng module lineinfile.)

  • Thiết kế role tái sử dụng. Phác thảo cấu trúc một Ansible role monitoring-agent cài node-exporter, đẩy file config từ template, và đảm bảo service chạy — sao cho dùng được cho cả môi trường staging và production chỉ bằng cách đổi biến.

Tóm tắt

  • Configuration Management giải quyết configuration driftsnowflake server bằng cách quản lý desired state của server: package nào cài, config chứa gì, service nào chạy.
  • Idempotency là nguyên lý cốt lõi: chạy bao nhiêu lần cũng cho cùng kết quả, cho phép chạy lặp lại để chống drift một cách an toàn.
  • Hai triết lý chính: push/agentless (Ansible — đơn giản, hợp fleet vừa) và pull/agent-based (Puppet, Chef — tự phục hồi, hợp fleet lớn và compliance chặt).
  • Config Management bổ sung cho Terraform: Terraform tạo vỏ (hạ tầng), Config Management lo ruột (bên trong máy).
  • Giá trị thật đến khi cấu hình trở thành code có phiên bản: đưa vào Git, review qua PR, chạy qua CI/CD với dry-run trước khi áp production.