Ansible playbook đầu tiên: cài Nginx và tạo user trên nhiều VPS

Hướng dẫn Ansible playbook đầu tiên: tạo inventory, kiểm tra SSH, dùng apt và user, become, idempotence, check mode và cài Nginx an toàn trên nhiều VPS.

NHT
· 8 phút đọc
Ansible playbook đầu tiên: cài Nginx và tạo user trên nhiều VPS

Ansible giúp biến các thao tác lặp lại trên nhiều VPS thành playbook có thể đọc, kiểm tra và chạy lại. Thay vì SSH vào từng máy để cài Nginx và tạo user thủ công, bạn khai báo inventory, quyền become và trạng thái mong muốn; Ansible sẽ gọi module trên các host phù hợp. Bài đầu tiên nên nhỏ, idempotent và dễ rollback, không nên bắt đầu bằng một playbook khổng lồ cài mọi thứ.

Trong hướng dẫn này, control node chạy Ansible, các VPS là managed nodes kết nối qua SSH. Chúng ta tạo inventory, kiểm tra kết nối, cài Nginx trên Ubuntu/Debian, tạo user vận hành, thêm SSH key, chạy check mode và kiểm tra service. Private key, password và host thật chỉ là placeholder, không đưa vào repository.

1. Mô hình control node, inventory và managed node

Ansible không cần cài agent thường trú trên managed node cho các tác vụ SSH phổ biến. Control node đọc playbook và inventory, sau đó kết nối tới từng host để gọi module. Inventory có thể dùng INI hoặc YAML; group giúp bạn áp dụng cùng play cho web, database, staging hoặc production.

Playbook nên mô tả trạng thái cần có, không chỉ danh sách lệnh phải chạy. Đó là nền tảng để chạy lại an toàn và đạt tính idempotent.Diễn giải thực hành dựa trên Ansible Getting Started và module documentation.
all:
  children:
    web:
      hosts:
        web01:
          ansible_host: 203.0.113.10
        web02:
          ansible_host: 203.0.113.11
      vars:
        ansible_user: ansible
        ansible_python_interpreter: /usr/bin/python3

Dải 203.0.113.0/24 trong ví dụ là địa chỉ tài liệu, không phải IP thật. Với production, đặt inventory trong repository riêng hoặc hệ thống quản lý phù hợp, bảo vệ file chứa hostname nội bộ và dùng group_vars/host_vars để tách biến theo môi trường.

2. Chuẩn bị SSH và quyền become

Từ control node, kiểm tra SSH tới từng VPS bằng deploy key hoặc key quản trị đã được cấp đúng. Ansible có thể dùng become để chạy task cần quyền root, nhưng không nên lưu password sudo plaintext trong playbook. Nếu sudo yêu cầu password, dùng vault, prompt hoặc cơ chế secret được bảo vệ.

# Kiểm tra inventory và SSH
ansible-inventory -i inventory.yml --graph
ansible web -i inventory.yml -m ansible.builtin.ping

# Chạy thử một lệnh có become khi đã cấu hình sudo phù hợp
ansible web -i inventory.yml -b -m ansible.builtin.command -a 'id'

Dùng FQCN như ansible.builtin.apt và ansible.builtin.user giúp liên kết tài liệu rõ ràng. Trước khi chạy trên nhiều VPS, hãy thử một host staging, kiểm tra distro và phiên bản Python, rồi mới mở rộng group target.

3. Playbook cài Nginx bằng module apt

Module ansible.builtin.apt quản lý package trên Debian/Ubuntu. Một playbook cơ bản có thể cập nhật apt cache có giới hạn thời gian rồi đảm bảo nginx ở trạng thái present. Không nên gọi apt-get bằng command cho thao tác package thông thường vì module có thể biểu diễn trạng thái và báo changed chính xác hơn.

---
- name: Install Nginx on web servers
  hosts: web
  become: true
  gather_facts: true

  tasks:
    - name: Refresh apt cache when stale
      ansible.builtin.apt:
        update_cache: true
        cache_valid_time: 3600

    - name: Install Nginx
      ansible.builtin.apt:
        name: nginx
        state: present

    - name: Ensure Nginx is enabled and running
      ansible.builtin.service:
        name: nginx
        enabled: true
        state: started

cache_valid_time giúp tránh cập nhật package index ở mọi task khi cache còn mới. Không dùng state: latest một cách tùy tiện trên production vì nó có thể nâng version ngoài cửa sổ thay đổi; nếu cần update, hãy tạo quy trình patch riêng có kiểm thử và snapshot/backup phù hợp.

4. Tạo user vận hành với ansible.builtin.user

Module ansible.builtin.user giúp khai báo user, home directory, shell và group. Khi thêm user vào group hiện có, hiểu rõ append. Nếu append false trong tình huống không phù hợp, danh sách group có thể bị thay thế. User vận hành nên có shell cần thiết, không cần quyền root mặc định và có thể bị giới hạn bằng sudoers nếu phải reload service.

- name: Create an operations user
  hosts: web
  become: true
  tasks:
    - name: Ensure ops user exists
      ansible.builtin.user:
        name: ops
        comment: "Website operations"
        shell: /bin/bash
        create_home: true
        groups: www-data
        append: true
        state: present

    - name: Install the operations public key
      ansible.posix.authorized_key:
        user: ops
        key: "{{ ops_public_key }}"
        state: present

Module authorized_key thuộc collection ansible.posix trong ví dụ; hãy cài collection theo requirements nếu control node chưa có. Public key có thể đặt trong biến được bảo vệ hoặc file vars không chứa private key. Không đặt private key vào inventory, vars hoặc template.

5. Biến, defaults và tách môi trường

Inventory nên chứa host và biến kết nối; playbook nên chứa logic trạng thái. Giá trị như tên user, package list, port và public key nên đặt trong group_vars/web.yml hoặc environment riêng. Dùng defaults để playbook có thể chạy ở staging, sau đó override production bằng biến được review.

# group_vars/web.yml
nginx_package: nginx
ops_user: ops
ops_public_key: "ssh-ed25519 AAAA... placeholder"

# playbook.yml
- name: Configure web hosts
  hosts: web
  become: true
  vars:
    required_packages:
      - nginx
      - curl
  tasks:
    - name: Install required packages
      ansible.builtin.apt:
        name: "{{ required_packages }}"
        state: present

Không hard-code password trong vars. Với secret cần dùng trong template, Ansible Vault hoặc secret backend phù hợp có thể mã hóa giá trị, nhưng vẫn phải kiểm soát quyền truy cập và tránh debug làm lộ nội dung.

6. Idempotence: chạy lại không tạo thay đổi thừa

Một task idempotent kiểm tra trạng thái hiện tại và chỉ thay đổi khi trạng thái mong muốn chưa đạt. apt state present không cài lại package đã có; user state present không tạo user mới nếu user đã tồn tại; service enabled/started không reload vô ích mỗi lần chạy. Tránh shell command có changed_when mặc định nếu command không thực sự thay đổi trạng thái.

TaskTrạng thái mong muốnCách kiểm tra
Packagenginx đã càiansible.builtin.apt state: present
Userops tồn tại và có homeansible.builtin.user state: present
SSH keypublic key có trong authorized_keysansible.posix.authorized_key
Servicenginx enabled và startedansible.builtin.service
Configfile đúng nội dung/quyềnansible.builtin.template hoặc copy

7. Check mode, diff và syntax check

Trước khi áp dụng trên production, chạy ansible-playbook --syntax-check để phát hiện YAML và biến cú pháp cơ bản. Check mode --check mô phỏng thay đổi nhưng không phải module nào cũng dự đoán hoàn hảo. --diff có thể hiển thị khác biệt file, vì vậy không dùng tùy tiện nếu file chứa secret hoặc dữ liệu nhạy cảm.

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

# Chạy giới hạn một host trước
ansible-playbook -i inventory.yml site.yml \
  --limit web01 \
  --ask-become-pass

Sau check mode, đọc các task có changed, failed và skipped. Nếu playbook có handler, template hoặc module ngoài core, hãy test module trong staging. Khi đã chắc chắn, mở rộng --limit theo group web và theo dõi log của Nginx sau khi chạy.

8. Handler và kiểm tra service

Khi thay đổi file cấu hình Nginx, dùng handler để reload chỉ khi file thực sự changed. Reload khác restart: reload thường giữ connection tốt hơn nhưng vẫn cần nginx -t trước khi áp dụng. Một playbook production nên kiểm tra service active và HTTP response sau thay đổi.

- name: Deploy Nginx configuration
  hosts: web
  become: true
  tasks:
    - name: Install site configuration
      ansible.builtin.template:
        src: site.conf.j2
        dest: /etc/nginx/sites-available/example.conf
        owner: root
        group: root
        mode: '0644'
        validate: '/usr/sbin/nginx -t -c %s'
      notify: Reload Nginx

  handlers:
    - name: Reload Nginx
      ansible.builtin.service:
        name: nginx
        state: reloaded

Thuộc tính validate giúp kiểm tra file trước khi thay thế theo cách module hỗ trợ. Với configuration phức tạp, hãy bổ sung smoke test từ control node hoặc monitoring sau playbook. Không coi task service started là bằng chứng website đã trả HTTP đúng.

9. Chạy trên nhiều VPS nhưng vẫn kiểm soát blast radius

Ansible mặc định có thể chạy nhiều host song song. Khi thay đổi có rủi ro, dùng serial để chia batch, chẳng hạn một host trước rồi phần còn lại. Nếu web01 pass health check nhưng web02 fail, bạn có thể dừng trước khi lan rộng. max_fail_percentage cũng hỗ trợ dừng play khi tỷ lệ lỗi vượt ngưỡng.

- name: Roll out Nginx safely
  hosts: web
  become: true
  serial: 1
  max_fail_percentage: 0
  tasks:
    - name: Install Nginx
      ansible.builtin.apt:
        name: nginx
        state: present
    - name: Verify local Nginx response
      ansible.builtin.uri:
        url: http://127.0.0.1
        status_code: 200

serial: 1 làm rollout chậm hơn nhưng giảm blast radius. Với nhiều VPS, có thể tăng lên 25% hoặc một số lượng cố định sau khi đã đo thời gian và chất lượng health check. Ghi log commit, inventory revision và kết quả từng host để phục vụ audit.

10. Các lỗi thường gặp khi viết playbook đầu tiên

  • SSH được trên máy quản trị nhưng Ansible dùng sai user, port hoặc private key.
  • Dùng become nhưng user không có sudo hoặc sudo yêu cầu password chưa được cung cấp.
  • Gọi shell/command thay cho module apt, user, service hoặc template.
  • Không dùng FQCN và thiếu collection cần thiết cho authorized_key.
  • Hard-code password, private key hoặc public host thật trong repository.
  • Không chạy syntax check/check mode trước khi áp dụng nhiều VPS.
  • Reload Nginx mà không validate cấu hình trước.
  • Chạy tất cả host song song dù thay đổi có blast radius lớn.
  • Dùng state: latest khiến patch không có cửa sổ kiểm soát.

Bài quản lý user và sudo trên Linux giúp củng cố mô hình quyền. Nếu Nginx đứng trước nhiều website, tham khảo bài Nginx reverse proxy cho nhiều website trước khi đưa template production vào playbook.

11. Checklist Ansible trước khi chạy production

  1. Tách control node, inventory và managed nodes rõ ràng.
  2. Kiểm tra SSH, Python và quyền become trên một host staging.
  3. Dùng FQCN và module trạng thái thay cho shell khi có thể.
  4. Tách biến môi trường, không lưu private key/password trong repository.
  5. Chạy syntax-check, check mode và diff có kiểm soát.
  6. Dùng handler, validate và health check cho Nginx configuration.
  7. Dùng serial khi rollout nhiều VPS có rủi ro.
  8. Ghi nhận changed/failed/skipped và inventory revision.
  9. Có backup hoặc snapshot trước thay đổi quan trọng.

12. Kết luận

Playbook đầu tiên nên giải quyết một việc rõ ràng: cài Nginx, tạo user và kiểm tra service trên một nhóm VPS. Khi playbook đã idempotent, có check mode, handler, giới hạn quyền và rollout theo batch, bạn mới mở rộng sang firewall, TLS, virtual host hoặc deploy application. Ansible không thay thế runbook; nó biến runbook đã hiểu rõ thành một quy trình có thể lặp lại và audit.

Tài liệu tham khảo

  1. Ansible Docs — Getting started.
  2. Ansible Docs — Inventory guide.
  3. Ansible Docs — ansible.builtin.apt.
  4. Ansible Docs — ansible.builtin.user.
  5. Ansible Docs — Playbooks intro.