0

Lab 4 — Ansible Playbook Fundamentals

Mục tiêu: Chuyển từ việc sử dụng Ansible để chạy các command đơn lẻ sang viết Playbook có cấu trúc, có thể tái sử dụng và version control. Sau Lab này, người học có thể tự viết Playbook để cài đặt package, tạo user, quản lý service và triển khai một cấu hình đơn giản.


1. Bối cảnh

Ở Lab 3, chúng ta đã sử dụng Ad-Hoc Command:

ansible webservers -m ansible.builtin.apt \
  -a "name=nginx state=present" \
  -b

Cách này rất tiện nếu chúng ta chỉ cần thực hiện một thao tác.

Nhưng hãy tưởng tượng yêu cầu trở thành:

1. Cài Nginx
2. Tạo user deploy
3. Tạo thư mục /opt/myapp
4. Copy configuration
5. Start Nginx
6. Enable Nginx
7. Kiểm tra service

Nếu sử dụng Ad-Hoc:

ansible ...
ansible ...
ansible ...
ansible ...
ansible ...
ansible ...
ansible ...

Rất nhanh chóng chúng ta sẽ gặp vấn đề:

  • Khó nhớ đã chạy những gì.
  • Khó review.
  • Khó chia sẻ cho người khác.
  • Khó version control.
  • Khó chạy lại.
  • Dễ chạy sai thứ tự.
  • Khó audit.

Giải pháp là:

                Playbook
                   │
       ┌───────────┼───────────┐
       ▼           ▼           ▼
     Task 1      Task 2      Task 3
       │           │           │
       ▼           ▼           ▼
    Package       User       Service

2. Playbook là gì?

Playbook là file YAML mô tả các automation task mà Ansible cần thực hiện trên Managed Nodes.

Ví dụ đơn giản:

---
- name: Install Nginx
  hosts: webservers
  become: true

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

Có thể đọc Playbook này như sau:

Trên nhóm webservers, sử dụng quyền root và đảm bảo Nginx được cài đặt.


3. Ad-Hoc Command vs Playbook

Ad-Hoc

ansible webservers \
  -b \
  -m ansible.builtin.apt \
  -a "name=nginx state=present"

Playbook

- name: Install Nginx
  hosts: webservers
  become: true

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

Điểm khác biệt quan trọng:

Ad-Hoc
    ↓
Command

Playbook
    ↓
Code
    ↓
Automation
    ↓
Version Control
    ↓
Repeatable

4. Cấu trúc cơ bản của Playbook

Một Playbook thường có cấu trúc:

---
- name: Play name
  hosts: target
  become: true

  vars:
    ...

  tasks:
    - name: Task 1
      module:
        ...

    - name: Task 2
      module:
        ...

Có thể hình dung:

Playbook
│
├── Play
│   │
│   ├── hosts
│   ├── become
│   ├── vars
│   └── tasks
│       ├── Task
│       ├── Task
│       └── Task
│
└── Play
    └── ...

Một Playbook có thể có một hoặc nhiều Play.


5. Tạo project

Tạo project mới:

mkdir ansible-lab-04
cd ansible-lab-04

Cấu trúc:

ansible-lab-04/
├── ansible.cfg
├── inventory.ini
└── playbook.yml

Ví dụ ansible.cfg:

[defaults]
inventory = ./inventory.ini

6. Inventory

Sử dụng Inventory:

[webservers]
web-01 ansible_host=192.168.56.101
web-02 ansible_host=192.168.56.102

[appservers]
app-01 ansible_host=192.168.56.103

[dbservers]
db-01 ansible_host=192.168.56.104

Kiểm tra:

ansible-inventory --graph

7. Play đầu tiên

Tạo:

playbook.yml

Nội dung:

---
- name: My first Ansible Playbook
  hosts: webservers

  tasks:
    - name: Check server uptime
      ansible.builtin.command:
        cmd: uptime

Chạy:

ansible-playbook playbook.yml

Kết quả có thể giống:

PLAY [My first Ansible Playbook] ************************

TASK [Check server uptime] *******************************
changed: [web-01]
changed: [web-02]

PLAY RECAP ***********************************************
web-01 : ok=1 changed=1 unreachable=0 failed=0
web-02 : ok=1 changed=1 unreachable=0 failed=0

8. ansible-playbook là gì?

Đây là command dùng để chạy Playbook:

ansible-playbook playbook.yml

Khác với:

ansible

dùng cho Ad-Hoc Command.

Có thể nhớ:

ansible
   ↓
Ad-Hoc

ansible-playbook
   ↓
Playbook

9. name

Ví dụ:

- name: Install Nginx

và:

- name: Create deploy user

name không quyết định logic.

Nó giúp:

  • Đọc Playbook dễ hơn.
  • Hiểu task đang làm gì.
  • Debug dễ hơn.
  • Log rõ ràng hơn.

Không nên viết:

- name: Task 1

Nên viết:

- name: Install nginx

Tên task nên mô tả ý định của task.


10. hosts

Ví dụ:

- name: Configure web servers
  hosts: webservers

Ansible sẽ tìm group:

[webservers]

trong Inventory.

Có thể sử dụng:

hosts: webservers

hoặc:

hosts: appservers

hoặc:

hosts: all

11. become

Nếu task cần quyền root:

become: true

Ví dụ:

- name: Install nginx
  hosts: webservers
  become: true

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

Thay vì phải thêm:

-b

ở mỗi command, Playbook có thể khai báo một lần:

become: true

12. tasks

Task là đơn vị thực thi cơ bản trong Play.

Ví dụ:

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

  - name: Start nginx
    ansible.builtin.service:
      name: nginx
      state: started

Ở đây có hai task:

Task 1
Install nginx
      ↓
Task 2
Start nginx

Ansible thực hiện task theo thứ tự từ trên xuống dưới.


13. Module trong Playbook

Ở Lab 3 chúng ta viết:

-m ansible.builtin.apt
-a "name=nginx state=present"

Trong Playbook:

ansible.builtin.apt:
  name: nginx
  state: present

Có thể thấy Playbook dễ đọc hơn rất nhiều.

Ad-Hoc

ansible webservers \
  -b \
  -m ansible.builtin.apt \
  -a "name=nginx state=present"

Playbook

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

14. Playbook đầu tiên — Install Nginx

Tạo:

---
- name: Configure web servers
  hosts: webservers
  become: true

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

Chạy:

ansible-playbook playbook.yml

Nếu thành công:

TASK [Install nginx]
changed: [web-01]
changed: [web-02]

15. Chạy lại Playbook

Bây giờ:

ansible-playbook playbook.yml

Lần này có thể thấy:

TASK [Install nginx]
ok: [web-01]
ok: [web-02]

Không còn:

changed

Đây là một trong những điểm quan trọng nhất của Ansible.

First run
    ↓
Resource chưa tồn tại
    ↓
changed

Second run
    ↓
Desired state đã đạt
    ↓
ok

Đó chính là:

Idempotency


16. changedok

Ansible thường trả về các trạng thái:

ok
changed
failed
skipped
unreachable

ok

Task chạy thành công và không cần thay đổi.

ok: [web-01]

changed

Ansible đã thay đổi server.

changed: [web-01]

failed

Task thất bại.

failed: [web-01]

skipped

Task bị bỏ qua.

skipping: [web-01]

unreachable

Không thể kết nối đến server.

UNREACHABLE!

17. Playbook nhiều task

Bây giờ mở rộng:

---
- name: Configure web servers
  hosts: webservers
  become: true

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

    - name: Start nginx
      ansible.builtin.service:
        name: nginx
        state: started

    - name: Enable nginx
      ansible.builtin.service:
        name: nginx
        enabled: true

Có thể gộp stateenabled:

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

Đây là cách viết tốt hơn.


18. Tạo User

Thêm task:

- name: Create deploy user
  ansible.builtin.user:
    name: deploy
    state: present

Full Playbook:

---
- name: Configure web servers
  hosts: webservers
  become: true

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

    - name: Create deploy user
      ansible.builtin.user:
        name: deploy
        state: present

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

19. Tạo Directory

Sử dụng file:

- name: Create application directory
  ansible.builtin.file:
    path: /opt/myapp
    state: directory
    owner: deploy
    group: deploy
    mode: "0755"

Ở đây chúng ta không nói:

"Hãy chạy mkdir."

Mà nói:

"/opt/myapp phải tồn tại, thuộc user deploy, group deploy và có permission 0755."

Đây chính là tư duy declarative.


20. Copy File

Tạo file trên Control Node:

index.html

Nội dung:

<h1>Hello from Ansible</h1>

Playbook:

- name: Deploy index page
  ansible.builtin.copy:
    src: index.html
    dest: /var/www/html/index.html
    owner: root
    group: root
    mode: "0644"

Flow:

Control Node
     │
     │ copy
     ▼
Managed Node
     │
     ▼
/var/www/html/index.html

21. Playbook hoàn chỉnh đầu tiên

Bây giờ:

---
- name: Configure web servers
  hosts: webservers
  become: true

  tasks:
    - name: Install nginx
      ansible.builtin.apt:
        name: nginx
        state: present
        update_cache: true

    - name: Create deploy user
      ansible.builtin.user:
        name: deploy
        state: present

    - name: Create application directory
      ansible.builtin.file:
        path: /opt/myapp
        state: directory
        owner: deploy
        group: deploy
        mode: "0755"

    - name: Deploy index page
      ansible.builtin.copy:
        src: index.html
        dest: /var/www/html/index.html
        owner: root
        group: root
        mode: "0644"

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

Chạy:

ansible-playbook playbook.yml

22. Tư duy quan trọng: Desired State

Đây là điểm người mới cần hiểu thật chắc.

Imperative:

mkdir /opt/myapp
chown deploy:deploy /opt/myapp
chmod 755 /opt/myapp

Bạn đang nói:

Làm những command này.

Declarative:

- name: Create application directory
  ansible.builtin.file:
    path: /opt/myapp
    state: directory
    owner: deploy
    group: deploy
    mode: "0755"

Bạn đang nói:

Tôi muốn hệ thống đạt trạng thái này.

Đây là một trong những nền tảng quan trọng của:

  • Ansible
  • Kubernetes
  • Terraform
  • Configuration Management
  • Infrastructure as Code

23. YAML cơ bản

Ansible Playbook sử dụng YAML.

Ví dụ:

name: nginx
state: present

Tương đương concept:

name → nginx
state → present

YAML sử dụng indentation.

Đúng:

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

Sai:

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

Indentation rất quan trọng.


24. List trong YAML

Ví dụ:

packages:
  - nginx
  - curl
  - git

Ansible có thể sử dụng:

name:
  - nginx
  - curl
  - git

Ví dụ:

- name: Install packages
  ansible.builtin.apt:
    name:
      - nginx
      - curl
      - git
    state: present

25. Một Playbook có nhiều Play

Playbook không nhất thiết chỉ có một Play.

Ví dụ:

---
- name: Configure web servers
  hosts: webservers
  become: true

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

- name: Configure database servers
  hosts: dbservers
  become: true

  tasks:
    - name: Install PostgreSQL
      ansible.builtin.apt:
        name: postgresql
        state: present

Flow:

Playbook
   │
   ├── Play 1
   │     └── webservers
   │
   └── Play 2
         └── dbservers

26. gather_facts

Mặc định, Ansible thường thu thập Facts trước khi chạy tasks.

Ví dụ:

- name: Configure servers
  hosts: webservers

  tasks:
    - name: ...

Ansible sẽ thực hiện bước:

Gathering Facts
       ↓
Tasks

Facts có thể chứa:

OS
CPU
RAM
Architecture
IP
Hostname
Kernel

Chúng ta sẽ khai thác sâu hơn ở Lab 5.


27. Tắt gather_facts

Nếu Playbook không cần Facts:

- name: Simple command
  hosts: webservers
  gather_facts: false

  tasks:
    - name: Check uptime
      ansible.builtin.command:
        cmd: uptime

Điều này có thể giúp giảm thời gian execution khi Playbook chỉ cần thực hiện những task đơn giản.


28. Kiểm tra Syntax

Trước khi chạy:

ansible-playbook --syntax-check playbook.yml

Nếu đúng:

playbook: playbook.yml

Đây nên trở thành thói quen.

Edit
 ↓
Syntax Check
 ↓
Run

29. --check

Có thể thử:

ansible-playbook playbook.yml --check

Ý tưởng:

Normal
   ↓
Apply changes

Check mode
   ↓
Predict changes

Không phải task/module nào cũng mô phỏng chính xác trong check mode, nên cần hiểu giới hạn của nó.


30. --diff

Đặc biệt hữu ích khi quản lý file:

ansible-playbook playbook.yml --diff

Ví dụ khi nội dung file thay đổi:

before
   ↓
after

Ansible có thể hiển thị diff nếu module hỗ trợ.


31. --limit

Không nên ngay lập tức chạy Playbook trên toàn bộ production.

Ví dụ:

ansible-playbook playbook.yml \
  --limit web-01

Flow an toàn:

web-01
  ↓
Verify
  ↓
web-02
  ↓
Verify
  ↓
Remaining

Đặc biệt hữu ích khi deployment.


32. --list-hosts

Trước khi chạy:

ansible-playbook playbook.yml --list-hosts

Ansible sẽ cho biết Playbook sẽ target những host nào.

Đây là một bước kiểm tra rất hữu ích trước production change.


33. --list-tasks

Có thể xem danh sách task:

ansible-playbook playbook.yml --list-tasks

Ví dụ:

playbook: playbook.yml

  play #1
    TASK: Install nginx
    TASK: Create deploy user
    TASK: Create application directory
    TASK: Deploy index page
    TASK: Ensure nginx is running

34. Tags — giới thiệu

Playbook lớn có thể có rất nhiều task.

Ví dụ:

- name: Install nginx
  ansible.builtin.apt:
    name: nginx
    state: present
  tags:
    - nginx
    - packages

Task khác:

- name: Deploy configuration
  ansible.builtin.copy:
    ...
  tags:
    - config

Sau đó:

ansible-playbook playbook.yml --tags nginx

Tags sẽ được học sâu hơn trong các bài nâng cao, nhưng người học nên biết concept từ bây giờ.


35. register — giới thiệu

Một task có thể lưu output:

- name: Check nginx version
  ansible.builtin.command:
    cmd: nginx -v
  register: nginx_version
  changed_when: false

Sau đó:

- name: Show nginx version
  ansible.builtin.debug:
    var: nginx_version

Flow:

Command
   ↓
register
   ↓
Variable
   ↓
Use later

register, when và variables sẽ được khai thác sâu hơn ở các Lab tiếp theo.


36. changed_when

Một vấn đề với:

- name: Check nginx version
  ansible.builtin.command:
    cmd: nginx -v

command có thể được xem là changed.

Nhưng chúng ta chỉ đang kiểm tra.

Có thể viết:

- name: Check nginx version
  ansible.builtin.command:
    cmd: nginx -v
  changed_when: false

Ý nghĩa:

Task này có thể chạy command, nhưng không được xem là thay đổi hệ thống.

Đây là một kỹ thuật quan trọng khi sử dụng command hoặc shell.


37. failed_when

Có thể định nghĩa điều kiện task được xem là failed.

Ví dụ:

- name: Check application health
  ansible.builtin.command:
    cmd: curl -f http://localhost/health
  register: health_check
  failed_when: health_check.rc != 0

Điều này cho phép automation hiểu được:

Command result
      ↓
Business condition
      ↓
Success / Failure

38. Tại sao không dùng shell cho mọi thứ?

Bạn có thể viết:

- name: Install nginx
  ansible.builtin.shell:
    cmd: apt install -y nginx

Nhưng đây không phải cách tốt.

Nên viết:

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

Lý do:

Module
 ├── Idempotency
 ├── Structured arguments
 ├── Better error handling
 ├── Better check mode support
 └── Better intent

Trong khi shell:

Shell
 ├── Flexible
 ├── Powerful
 └── Easier to misuse

Quy tắc:

Prefer Ansible modules over shell commands whenever a suitable module exists.


39. Debug Playbook

Khi cần xem giá trị:

- name: Show message
  ansible.builtin.debug:
    msg: "Hello from Ansible"

Hoặc:

- name: Show hostname
  ansible.builtin.debug:
    var: ansible_hostname

debug sẽ trở thành công cụ rất quan trọng khi chúng ta bắt đầu sử dụng:

  • Variables
  • Facts
  • Templates
  • Conditions
  • Loops

40. Thực hành — Build Web Server

Bây giờ hãy xây dựng một Web Server đơn giản.

Yêu cầu

Playbook phải:

  1. Cài Nginx.
  2. Tạo user deploy.
  3. Tạo /opt/myapp.
  4. Tạo /opt/myapp/index.html.
  5. Deploy HTML vào Nginx.
  6. Start Nginx.
  7. Enable Nginx.

41. Chuẩn bị HTML

Tạo:

files/index.html

Nội dung:

<!DOCTYPE html>
<html>
<head>
    <title>Ansible Lab 4</title>
</head>
<body>
    <h1>Hello from Ansible!</h1>
    <p>This server was configured automatically.</p>
</body>
</html>

Cấu trúc:

ansible-lab-04/
├── ansible.cfg
├── inventory.ini
├── playbook.yml
└── files/
    └── index.html

42. Playbook thực hành

---
- name: Configure web servers
  hosts: webservers
  become: true

  tasks:
    - name: Install nginx
      ansible.builtin.apt:
        name: nginx
        state: present
        update_cache: true

    - name: Create deploy user
      ansible.builtin.user:
        name: deploy
        state: present

    - name: Create application directory
      ansible.builtin.file:
        path: /opt/myapp
        state: directory
        owner: deploy
        group: deploy
        mode: "0755"

    - name: Deploy web page
      ansible.builtin.copy:
        src: files/index.html
        dest: /var/www/html/index.html
        owner: root
        group: root
        mode: "0644"

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

43. Validate

Syntax:

ansible-playbook --syntax-check playbook.yml

Danh sách host:

ansible-playbook playbook.yml --list-hosts

Danh sách task:

ansible-playbook playbook.yml --list-tasks

Check mode:

ansible-playbook playbook.yml --check

Cuối cùng:

ansible-playbook playbook.yml

44. Verify

Kiểm tra Nginx:

ansible webservers \
  -m ansible.builtin.service \
  -a "name=nginx"

Kiểm tra user:

ansible webservers \
  -m ansible.builtin.command \
  -a "id deploy"

Kiểm tra file:

ansible webservers \
  -m ansible.builtin.command \
  -a "cat /var/www/html/index.html"

Nếu có thể truy cập Web Server:

curl http://<server-ip>

Kết quả:

Hello from Ansible!

45. Exercise 1 — Basic Playbook

Viết Playbook:

basic.yml

Yêu cầu:

Target: webservers

Task 1:
    Install curl

Task 2:
    Install git

Task 3:
    Install nginx

Task 4:
    Ensure nginx is running

Không được sử dụng shell.


46. Exercise 2 — User Management

Viết Playbook:

users.yml

Yêu cầu:

Create:
    deploy

Create:
    /opt/myapp

Owner:
    deploy:deploy

Permission:
    0755

Sau đó chạy Playbook hai lần.

Quan sát:

changed

và:

ok

47. Exercise 3 — Static Website

Viết Playbook deploy một website HTML.

Yêu cầu:

Install nginx
        ↓
Copy index.html
        ↓
Start nginx
        ↓
Enable nginx

Verify:

curl http://<server-ip>

48. Exercise 4 — Multi Server

Inventory:

[webservers]
web-01
web-02

[appservers]
app-01

Viết Playbook:

webservers
    ↓
Install nginx

appservers
    ↓
Install curl

Không được viết hai Playbook riêng.

Sử dụng:

2 Plays

trong cùng một Playbook.


49. Exercise 5 — Safe Deployment

Viết Playbook deploy Nginx.

Trước khi chạy toàn bộ:

ansible-playbook deploy.yml \
  --limit web-01

Verify.

Sau đó:

ansible-playbook deploy.yml \
  --limit web-02

Verify.

Cuối cùng mới:

ansible-playbook deploy.yml

Mục tiêu của exercise này không chỉ là syntax.

Bạn đang thực hành:

Controlled production change.


50. Exercise 6 — Debugging

Tạo một Playbook cố tình sai:

- name: Test failure
  hosts: webservers
  become: true

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

    - name: Start invalid service
      ansible.builtin.service:
        name: nginx-invalid
        state: started

Chạy:

ansible-playbook test.yml

Quan sát:

TASK
 ↓
FAILED
 ↓
PLAY RECAP

Xác định:

  • Task nào fail?
  • Host nào fail?
  • Error message là gì?
  • Task trước đó có được thực hiện không?

51. Exercise 7 — Production Challenge

Bạn được giao ticket:

"Provision một Web Server mới."

Yêu cầu:

Server
  ↓
Install nginx
  ↓
Create deploy user
  ↓
Create /opt/myapp
  ↓
Deploy website
  ↓
Start nginx
  ↓
Enable nginx
  ↓
Verify

Constraint:

❌ Không SSH thủ công
❌ Không dùng shell để install/configure nginx
❌ Không chạy từng command bằng tay
✅ Chỉ sử dụng Playbook

Sau khi chạy lần đầu, chạy lại Playbook.

Mục tiêu:

First run
changed > 0

Second run
changed = 0

52. Những lỗi người mới thường gặp

Lỗi 1 — Sai indentation

tasks:
- name: Install nginx
  ansible.builtin.apt:

Mặc dù YAML có thể chấp nhận một số dạng indentation, hãy thống nhất style:

tasks:
  - name: Install nginx
    ansible.builtin.apt:

Lỗi 2 — Quên become

- name: Install nginx
  ansible.builtin.apt:

Có thể gặp:

Permission denied

Nếu cần root:

become: true

Lỗi 3 — Sai module

Ví dụ dùng:

ansible.builtin.apt:

trên hệ điều hành không sử dụng APT.

Cần xác định OS trước.


Lỗi 4 — Dùng shell cho mọi thứ

Không nên:

shell: apt install nginx

nếu có:

ansible.builtin.apt:

Lỗi 5 — Không kiểm tra target

Không nên chạy ngay:

ansible-playbook production.yml

Hãy kiểm tra:

ansible-playbook production.yml --list-hosts

53. Workflow tốt khi viết Playbook

Một workflow thực tế:

Requirement
     ↓
Identify target
     ↓
Choose Ansible module
     ↓
Write Playbook
     ↓
Syntax check
     ↓
--list-hosts
     ↓
--check
     ↓
Run on one host
     ↓
Verify
     ↓
Run broader scope

Có thể rút gọn thành:

Write
  ↓
Validate
  ↓
Test
  ↓
Verify
  ↓
Deploy

Đây là workflow nên hình thành ngay từ khi mới học.


54. Tư duy Senior #1 — Playbook là Code

Đừng xem:

playbook.yml

chỉ là file configuration.

Hãy xem nó là:

Infrastructure Code

Vì vậy Playbook nên:

  • Dễ đọc.
  • Dễ review.
  • Có naming rõ ràng.
  • Có version control.
  • Có testing.
  • Có documentation phù hợp.
  • Không chứa secret trực tiếp.

55. Tư duy Senior #2 — Mô tả Intent

Không nên nghĩ:

"Tôi cần chạy command này."

Hãy nghĩ:

"Server cần đạt trạng thái nào?"

Ví dụ:

state: present

thay vì:

apt install nginx

hoặc:

state: started

thay vì:

systemctl start nginx

Đây chính là bước chuyển từ:

Imperative

sang:

Declarative

56. Tư duy Senior #3 — Idempotency

Một Playbook tốt phải có thể chạy nhiều lần.

Ví dụ:

Run #1
    ↓
Create resource

Run #2
    ↓
No unnecessary change

Run #3
    ↓
No unnecessary change

Mục tiêu:

Desired State
      ↓
      = 
Actual State

Không nên viết automation mà mỗi lần chạy đều:

restart
recreate
overwrite
change

mà không cần thiết.


57. Tư duy Senior #4 — Không phải mọi task đều cần changed

Ví dụ:

- name: Check nginx version
  ansible.builtin.command:
    cmd: nginx -v
  changed_when: false

Task này:

Read-only

nên không nên báo:

changed

Hãy phân biệt:

Read operation
        vs
Write operation

Đây là một chi tiết nhỏ nhưng rất quan trọng khi xây dựng automation lớn.


58. Tư duy Senior #5 — Giảm Blast Radius

Nếu có:

100 production servers

không nên mặc định:

Change 100 servers

Có thể:

1 server
   ↓
Verify
   ↓
5 servers
   ↓
Verify
   ↓
25 servers
   ↓
Verify
   ↓
100 servers

Đây chính là tư duy:

Progressive rollout

Sau này chúng ta sẽ dùng các cơ chế như:

  • serial
  • strategy
  • max_fail_percentage

để kiểm soát deployment.


59. Tư duy Senior #6 — Playbook phải có khả năng đọc hiểu

Không nên:

- name: Do thing

Nên:

- name: Ensure nginx is installed

Không nên:

- name: Execute command

Nên:

- name: Check nginx service status

Một năm sau, chính bạn hoặc đồng đội sẽ phải đọc lại code này.


60. Tư duy Senior #7 — Automation không có nghĩa là chạy càng nhiều càng tốt

Một automation tốt không phải:

1000 lines

mà là:

Clear
+
Predictable
+
Idempotent
+
Reusable
+
Safe

Mục tiêu cuối cùng không phải:

"Ansible chạy được."

Mà là:

"Infrastructure có thể được quản lý một cách đáng tin cậy bằng code."


61. Kiến thức cần ghi nhớ

Sau Lab 4, người học cần nắm chắc:

Playbook
   │
   ├── Play
   │    ├── hosts
   │    ├── become
   │    ├── vars
   │    └── tasks
   │
   └── Tasks
        └── Modules

Và workflow:

Inventory
    ↓
Playbook
    ↓
Module
    ↓
Desired State
    ↓
Managed Node

62. Cheat Sheet

Chạy Playbook

ansible-playbook playbook.yml

Syntax check

ansible-playbook playbook.yml --syntax-check

Check mode

ansible-playbook playbook.yml --check

Diff

ansible-playbook playbook.yml --diff

Xem host

ansible-playbook playbook.yml --list-hosts

Xem task

ansible-playbook playbook.yml --list-tasks

Giới hạn host

ansible-playbook playbook.yml --limit web-01

Tags

ansible-playbook playbook.yml --tags nginx

63. Checklist hoàn thành Lab 4

  • [ ] Hiểu Playbook là gì.
  • [ ] Hiểu sự khác nhau giữa Ad-Hoc và Playbook.
  • [ ] Hiểu Play.
  • [ ] Hiểu Task.
  • [ ] Biết sử dụng hosts.
  • [ ] Biết sử dụng become.
  • [ ] Biết sử dụng module trong Playbook.
  • [ ] Viết được Playbook nhiều task.
  • [ ] Viết được nhiều Play trong một Playbook.
  • [ ] Hiểu okchanged.
  • [ ] Hiểu Idempotency.
  • [ ] Biết --syntax-check.
  • [ ] Biết --check.
  • [ ] Biết --diff.
  • [ ] Biết --limit.
  • [ ] Biết --list-hosts.
  • [ ] Biết --list-tasks.
  • [ ] Biết sử dụng debug.
  • [ ] Biết cơ bản về register.
  • [ ] Biết cơ bản về changed_when.
  • [ ] Biết khi nào nên dùng module thay vì shell.
  • [ ] Có thể viết một Playbook provision Web Server đơn giản.

64. Tổng kết Lab 4

Ở các Lab trước, chúng ta có:

Lab 1
Ansible Fundamentals
        ↓
Lab 2
Inventory & SSH
        ↓
Lab 3
Ad-Hoc Commands

Đến Lab 4:

Ad-Hoc
   │
   │ "Run this command"
   ▼
Playbook
   │
   │ "Make the server look like this"
   ▼
Desired State

Đây là bước ngoặt quan trọng nhất của giai đoạn Ansible Fundamentals.

Từ đây, người học không chỉ biết:

ansible <host> -m <module>

mà bắt đầu biết:

Infrastructure
      ↓
Code
      ↓
Playbook
      ↓
Repeatable Automation

Và ở Lab 5 — Ansible Variables & Facts, chúng ta sẽ giải quyết một vấn đề mới:

Playbook hiện tại đang hard-code rất nhiều giá trị.

Ví dụ:

name: nginx
path: /opt/myapp
user: deploy

Nhưng thực tế:

Development
    ↓
user = dev

Staging
    ↓
user = staging

Production
    ↓
user = deploy

Hay:

Ubuntu
    ↓
apt

RHEL
    ↓
dnf

Lúc này chúng ta cần Variables + Facts để Playbook có thể tự thích nghi với từng server và từng environment.

Lab 4
Playbook
   ↓
Hard-coded Automation

Lab 5
Variables + Facts
   ↓
Dynamic Automation

Đây sẽ là nền tảng để bước sang Templates, Handlers, Roles và cuối cùng là Production-grade Ansible Automation.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí