0

Lab 5 — Ansible Variables & Facts

Mục tiêu: Sau Lab này, người học hiểu cách Ansible lưu trữ và sử dụng dữ liệu động thông qua VariablesFacts. Người học sẽ biết cách viết Playbook không còn hard-code, biết cách truy cập thông tin của server, sử dụng register, debug, when và bắt đầu xây dựng Playbook có khả năng thích nghi với nhiều server/environment.


1. Bối cảnh

Ở Lab 4, chúng ta đã viết được 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: Create application directory
      ansible.builtin.file:
        path: /opt/myapp
        state: directory
        owner: deploy
        group: deploy
        mode: "0755"

Playbook này hoạt động.

Nhưng có một vấn đề:

name: deploy
path: /opt/myapp
mode: 0755

Tất cả đều được hard-code.

Giả sử chúng ta có:

Development
    user = dev
    app = todo-dev

Staging
    user = staging
    app = todo-staging

Production
    user = deploy
    app = todo

Nếu viết hard-code:

deploy-dev.yml
deploy-staging.yml
deploy-production.yml

thì chúng ta đang tạo ra rất nhiều code trùng lặp.

Thay vào đó:

                Playbook
                   │
                   ▼
              Variables
             /     |      \
            ▼      ▼       ▼
          Dev   Staging   Prod

Đây là lý do Variables rất quan trọng.


2. Variable là gì?

Variable đơn giản là một giá trị có thể thay đổi.

Ví dụ:

app_name: todo
app_user: deploy
app_port: 8080

Sau đó sử dụng:

- name: Create application directory
  ansible.builtin.file:
    path: "/opt/{{ app_name }}"
    state: directory
    owner: "{{ app_user }}"

Thay vì:

path: /opt/todo
owner: deploy

Ta có:

Variable
   ↓
{{ app_name }}
   ↓
todo

3. Jinja2 expression

Ansible sử dụng Jinja2 để xử lý expression.

Cú pháp cơ bản:

{{ variable }}

Ví dụ:

app_name: todo

Sử dụng:

msg: "Application: {{ app_name }}"

Kết quả:

Application: todo

Có thể hình dung:

{{ app_name }}
      ↓
  Template Engine
      ↓
     todo

Phần Jinja2 nâng cao sẽ được học sâu hơn ở Lab 6 — Templates với Jinja2. Trong Lab này chúng ta chỉ sử dụng Jinja2 ở mức cần thiết cho Variables.


4. Tạo project

Tạo project:

mkdir ansible-lab-05
cd ansible-lab-05

Cấu trúc:

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

ansible.cfg:

[defaults]
inventory = ./inventory.ini

5. Inventory

Sử dụng:

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

Kiểm tra:

ansible-inventory --graph

6. Variable đầu tiên

Tạo:

---
- name: Variable demo
  hosts: webservers

  vars:
    app_name: todo
    app_user: deploy
    app_port: 8080

  tasks:
    - name: Show application information
      ansible.builtin.debug:
        msg: "App={{ app_name }}, User={{ app_user }}, Port={{ app_port }}"

Chạy:

ansible-playbook playbook.yml

Kết quả:

App=todo, User=deploy, Port=8080

7. vars

Variables có thể được khai báo trực tiếp trong Play:

vars:
  app_name: todo
  app_user: deploy

Phạm vi:

Play
 │
 ├── vars
 │    ├── app_name
 │    └── app_user
 │
 └── tasks

Các task trong Play có thể sử dụng những variable này.


8. Sử dụng Variable trong Task

Ví dụ:

---
- name: Configure application
  hosts: webservers
  become: true

  vars:
    app_name: todo
    app_user: deploy

  tasks:
    - name: Create application user
      ansible.builtin.user:
        name: "{{ app_user }}"
        state: present

    - name: Create application directory
      ansible.builtin.file:
        path: "/opt/{{ app_name }}"
        state: directory
        owner: "{{ app_user }}"
        group: "{{ app_user }}"
        mode: "0755"

Bây giờ thay đổi:

app_name: payment
app_user: payment

thì Playbook sẽ tự động tạo:

/opt/payment

và:

payment user

Không cần sửa từng task.


9. Tại sao Variables quan trọng?

Không có variable:

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

- name: Create directory
  ansible.builtin.file:
    path: /opt/todo
    owner: deploy

Có variable:

vars:
  app_name: todo
  app_user: deploy

Sau đó:

- name: Create application user
  ansible.builtin.user:
    name: "{{ app_user }}"

- name: Create application directory
  ansible.builtin.file:
    path: "/opt/{{ app_name }}"
    owner: "{{ app_user }}"

So sánh:

Hard-coded
     ↓
Khó thay đổi
Khó reuse
Khó scale

Variables
     ↓
Dễ thay đổi
Dễ reuse
Dễ scale

10. Variable kiểu String

app_name: todo
environment: production
app_user: deploy

Sử dụng:

msg: "Deploy {{ app_name }} to {{ environment }}"

Kết quả:

Deploy todo to production

11. Variable kiểu Number

app_port: 8080
worker_count: 4

Có thể:

msg: "Application port: {{ app_port }}"

Lưu ý:

Trong YAML, kiểu dữ liệu có thể ảnh hưởng đến cách Ansible xử lý giá trị.

Ví dụ:

app_port: 8080

là number.

Trong một số context, đặc biệt khi cần truyền giá trị chuỗi, có thể chủ động sử dụng:

app_port: "8080"

12. Boolean

nginx_enabled: true
debug_enabled: false

Sử dụng với module:

- name: Ensure nginx is enabled
  ansible.builtin.service:
    name: nginx
    enabled: "{{ nginx_enabled }}"

13. List

Variable có thể là danh sách:

packages:
  - nginx
  - curl
  - git

Có thể sử dụng:

- name: Install required packages
  ansible.builtin.apt:
    name: "{{ packages }}"
    state: present

Kết quả:

nginx
curl
git

sẽ được cài đặt.


14. Dictionary

Variable cũng có thể chứa nhiều key:

app:
  name: todo
  user: deploy
  port: 8080

Truy cập:

{{ app.name }}
{{ app.user }}
{{ app.port }}

Ví dụ:

- name: Show app information
  ansible.builtin.debug:
    msg: "{{ app.name }} runs on port {{ app.port }}"

Kết quả:

todo runs on port 8080

15. Nested Variables

Có thể tạo cấu trúc:

application:
  name: todo
  version: "1.0.0"

  server:
    host: 0.0.0.0
    port: 8080

Truy cập:

{{ application.name }}
{{ application.version }}
{{ application.server.port }}

Đây là cấu trúc rất thường gặp trong Ansible thực tế.


16. Variable trong debug

Module rất hữu ích để debug:

ansible.builtin.debug:

Ví dụ:

- name: Show application name
  ansible.builtin.debug:
    var: app_name

Hoặc:

- name: Show application configuration
  ansible.builtin.debug:
    var: application

17. msg vs var

msg

- name: Show message
  ansible.builtin.debug:
    msg: "Application is {{ app_name }}"

Dùng khi muốn tạo message tùy chỉnh.

var

- name: Show variable
  ansible.builtin.debug:
    var: app_name

Dùng khi muốn xem trực tiếp giá trị variable.


18. Facts là gì?

Đây là phần quan trọng thứ hai của Lab.

Khi Ansible kết nối tới server, nó có thể tự động thu thập thông tin về server.

Ví dụ:

OS
Hostname
IP
CPU
Memory
Architecture
Kernel
Python
Interfaces
Disks

Những thông tin này gọi là:

Ansible Facts

Flow:

Control Node
      │
      │ SSH
      ▼
Managed Node
      │
      │ Gather information
      ▼
Ansible Facts

19. gather_facts

Mặc định:

- name: Configure server
  hosts: webservers

Ansible thường sẽ thực hiện:

Gathering Facts
       ↓
Tasks

Bạn có thể thấy:

TASK [Gathering Facts]
ok: [web-01]
ok: [web-02]

20. Xem Facts

Tạo Playbook:

---
- name: Explore Ansible Facts
  hosts: webservers

  tasks:
    - name: Show all facts
      ansible.builtin.debug:
        var: ansible_facts

Chạy:

ansible-playbook playbook.yml

Bạn sẽ nhận được rất nhiều dữ liệu.

Không nên cố đọc toàn bộ output.

Thay vào đó, lấy từng thông tin cần thiết.


21. Hostname

Một Fact thường được sử dụng:

ansible_hostname

Ví dụ:

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

Có thể sử dụng:

msg: "Server hostname: {{ ansible_hostname }}"

22. Operating System

Có thể sử dụng:

ansible_facts.distribution

Ví dụ:

- name: Show operating system
  ansible.builtin.debug:
    msg: "OS: {{ ansible_facts.distribution }}"

Ví dụ kết quả:

OS: Ubuntu

hoặc:

OS: Debian

hoặc:

OS: Rocky

23. OS Version

ansible_facts.distribution_version

Ví dụ:

- name: Show OS version
  ansible.builtin.debug:
    msg: "{{ ansible_facts.distribution }} {{ ansible_facts.distribution_version }}"

Kết quả:

Ubuntu 24.04

24. Architecture

ansible_facts.architecture

Ví dụ:

- name: Show architecture
  ansible.builtin.debug:
    var: ansible_facts.architecture

Có thể nhận:

x86_64

hoặc:

aarch64

Điều này đặc biệt hữu ích khi làm việc với:

  • ARM server
  • AWS Graviton
  • Raspberry Pi
  • Apple Silicon VM
  • Multi-architecture deployment

25. CPU

Ví dụ:

ansible_facts.processor_vcpus
- name: Show CPU count
  ansible.builtin.debug:
    msg: "vCPU: {{ ansible_facts.processor_vcpus }}"

26. Memory

Ví dụ:

ansible_facts.memtotal_mb
- name: Show memory
  ansible.builtin.debug:
    msg: "Memory: {{ ansible_facts.memtotal_mb }} MB"

27. Default IPv4

Có thể truy cập:

ansible_facts.default_ipv4.address

Ví dụ:

- name: Show server IP
  ansible.builtin.debug:
    msg: "IP: {{ ansible_facts.default_ipv4.address }}"

28. Facts vs Variables

Đây là điểm cần phân biệt rõ.

Variable

Do chúng ta hoặc inventory cung cấp:

app_name: todo

Fact

Ansible tự thu thập từ server:

ansible_facts.distribution
ansible_facts.architecture
ansible_facts.memtotal_mb

Có thể hình dung:

Variables
   │
   └── Configuration / Input

Facts
   │
   └── Information about server

29. Fact có thể dùng để quyết định

Ví dụ:

- name: Install nginx on Debian family
  ansible.builtin.apt:
    name: nginx
    state: present
  when: ansible_facts.os_family == "Debian"

Nếu:

OS = Ubuntu

thì task chạy.

Nếu:

OS = Rocky Linux

thì task bị skip.


30. when

when dùng để thực hiện task có điều kiện.

Ví dụ:

- name: Install nginx
  ansible.builtin.apt:
    name: nginx
    state: present
  when: ansible_facts.os_family == "Debian"

Không đặt {{ }} trong when cho biểu thức điều kiện:

Đúng:

when: ansible_facts.os_family == "Debian"

Không cần:

when: "{{ ansible_facts.os_family == 'Debian' }}"

31. Ubuntu và RHEL

Một ví dụ thực tế:

---
- name: Install web server
  hosts: all
  become: true

  tasks:
    - name: Install nginx on Debian family
      ansible.builtin.apt:
        name: nginx
        state: present
      when: ansible_facts.os_family == "Debian"

    - name: Install nginx on RedHat family
      ansible.builtin.dnf:
        name: nginx
        state: present
      when: ansible_facts.os_family == "RedHat"

Flow:

                    Server
                      │
                 Gather Facts
                      │
             ┌────────┴────────┐
             ▼                 ▼
          Debian            RedHat
             │                 │
             ▼                 ▼
            apt               dnf

Đây là lúc Facts bắt đầu tạo ra giá trị thực tế.


32. register

Ngoài Facts, một nguồn dữ liệu quan trọng khác là kết quả của task.

Ví dụ:

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

Kết quả task được lưu vào:

nginx_result

Sau đó:

- name: Show result
  ansible.builtin.debug:
    var: nginx_result

33. Register hoạt động thế nào?

Task
 │
 │ execute
 ▼
Command / Module
 │
 │ result
 ▼
register
 │
 ▼
Variable
 │
 ├── stdout
 ├── stderr
 ├── rc
 └── changed

Ví dụ:

nginx_result.stdout
nginx_result.rc

34. stdout

Ví dụ:

- name: Check hostname
  ansible.builtin.command:
    cmd: hostname
  register: hostname_result
  changed_when: false

Có thể:

- name: Show hostname
  ansible.builtin.debug:
    msg: "{{ hostname_result.stdout }}"

35. rc

rc thường là return code.

Ví dụ:

0

thường biểu thị command thành công.

Có thể:

- name: Check command result
  ansible.builtin.debug:
    msg: "Return code: {{ hostname_result.rc }}"

36. Register + when

Đây là pattern rất quan trọng.

Ví dụ:

- name: Check nginx configuration
  ansible.builtin.command:
    cmd: nginx -t
  register: nginx_test
  changed_when: false

Sau đó có thể dựa trên kết quả:

- name: Show nginx test result
  ansible.builtin.debug:
    msg: "Nginx configuration is valid"
  when: nginx_test.rc == 0

Flow:

Execute
   ↓
Register result
   ↓
Check condition
   ↓
Take action

37. Variable precedence — giới thiệu

Một trong những phần khó nhất của Ansible là:

Một variable có thể được khai báo ở nhiều nơi.

Ví dụ:

defaults
vars
inventory
group_vars
host_vars
extra vars

Không phải tất cả đều có độ ưu tiên giống nhau.

Ở Lab này chưa cần học thuộc toàn bộ precedence.

Điều cần hiểu:

Variable source
      ↓
Precedence
      ↓
Final value

Chúng ta sẽ xây dựng cấu trúc Variable bài bản ở Lab 13 khi bắt đầu quản lý nhiều Environment.


38. Inventory Variables

Variable có thể đặt trực tiếp trong Inventory.

Ví dụ:

[webservers]
web-01 ansible_host=192.168.56.101 app_port=8080
web-02 ansible_host=192.168.56.102 app_port=9090

Sau đó:

- name: Show application port
  ansible.builtin.debug:
    msg: "{{ app_port }}"

Kết quả:

web-01 → 8080
web-02 → 9090

Điều này cho phép từng server có cấu hình riêng.


39. group_vars

Khi project lớn hơn, không nên nhét tất cả vào Inventory.

Có thể tạo:

group_vars/
└── webservers.yml

Ví dụ:

app_name: todo
app_user: deploy
app_port: 8080

Cấu trúc:

ansible-lab-05/
├── inventory.ini
├── playbook.yml
└── group_vars/
    └── webservers.yml

Ansible sẽ tự động load variables cho group webservers.


40. host_vars

Nếu một server cần cấu hình riêng:

host_vars/
├── web-01.yml
└── web-02.yml

Ví dụ:

# host_vars/web-01.yml

app_port: 8080

và:

# host_vars/web-02.yml

app_port: 9090

Flow:

webservers
    │
    ├── web-01
    │      └── app_port=8080
    │
    └── web-02
           └── app_port=9090

41. Đây là cấu trúc rất quan trọng

Một project thực tế có thể:

ansible/
├── ansible.cfg
├── inventory.ini
├── group_vars/
│   └── webservers.yml
├── host_vars/
│   ├── web-01.yml
│   └── web-02.yml
└── playbook.yml

Tư duy:

Playbook
   │
   ├── Common logic
   │
   └── Variables
        ├── Group
        └── Host

Như vậy logic và dữ liệu bắt đầu được tách ra.


42. Thực hành — Dynamic Web Server

Bây giờ chúng ta xây dựng một Playbook thực tế hơn.

Mục tiêu:

Install nginx
Create application user
Create application directory
Deploy website
Start nginx

Nhưng tất cả configuration phải sử dụng Variables.


43. Tạo group_vars

Tạo:

group_vars/webservers.yml

Nội dung:

app_name: todo
app_user: deploy
app_directory: "/opt/{{ app_name }}"
web_root: /var/www/html

44. Playbook

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

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

    - name: Create application user
      ansible.builtin.user:
        name: "{{ app_user }}"
        state: present

    - name: Create application directory
      ansible.builtin.file:
        path: "{{ app_directory }}"
        state: directory
        owner: "{{ app_user }}"
        group: "{{ app_user }}"
        mode: "0755"

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

Điểm quan trọng:

Playbook không biết:

deploy
todo
/opt/todo

Nó chỉ biết:

app_user
app_name
app_directory

45. Thay đổi Environment

Chỉ cần:

app_name: payment
app_user: payment
app_directory: "/opt/{{ app_name }}"

Playbook sẽ tạo:

user:
payment

directory:
/opt/payment

Không cần sửa Playbook.

Đây chính là lợi ích lớn của Variables.


46. Thực hành Facts

Tạo:

facts.yml
---
- name: Explore server facts
  hosts: webservers

  tasks:
    - name: Show hostname
      ansible.builtin.debug:
        msg: "Hostname: {{ ansible_hostname }}"

    - name: Show OS
      ansible.builtin.debug:
        msg: "OS: {{ ansible_facts.distribution }}"

    - name: Show OS version
      ansible.builtin.debug:
        msg: "Version: {{ ansible_facts.distribution_version }}"

    - name: Show architecture
      ansible.builtin.debug:
        msg: "Architecture: {{ ansible_facts.architecture }}"

    - name: Show memory
      ansible.builtin.debug:
        msg: "Memory: {{ ansible_facts.memtotal_mb }} MB"

    - name: Show IP
      ansible.builtin.debug:
        msg: "IP: {{ ansible_facts.default_ipv4.address }}"

Chạy:

ansible-playbook facts.yml

47. Exercise 1 — Variables

Tạo Playbook:

variables.yml

Khai báo:

app_name: todo
app_version: "1.0.0"
app_port: 8080
app_user: deploy

In ra:

Application:
Version:
Port:
User:

Không được hard-code các giá trị trong debug.


48. Exercise 2 — List

Tạo:

packages:
  - curl
  - git
  - nginx

Viết task cài toàn bộ package.

Gợi ý:

ansible.builtin.apt:
  name: "{{ packages }}"
  state: present

49. Exercise 3 — Dictionary

Tạo:

app:
  name: todo
  user: deploy
  port: 8080
  directory: /opt/todo

In:

Name
User
Port
Directory

sử dụng:

app.name
app.user
app.port
app.directory

50. Exercise 4 — Facts

Viết Playbook hiển thị:

Hostname
OS
OS Version
Architecture
CPU
Memory
IP

Yêu cầu:

Không được hard-code bất kỳ thông tin server nào.

Tất cả phải lấy từ Facts.


51. Exercise 5 — OS Detection

Viết Playbook:

Debian family
    ↓
Install nginx with apt

RedHat family
    ↓
Install nginx with dnf

Sử dụng:

when:

và:

ansible_facts.os_family

52. Exercise 6 — Register

Viết task:

Check nginx version
       ↓
register
       ↓
Print stdout

Ví dụ:

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

Sau đó hiển thị:

nginx_version.stderr

Lưu ý: nginx -v trên nhiều phiên bản Nginx ghi version vào stderr, không phải stdout.


53. Exercise 7 — Register + Condition

Viết Playbook:

Check nginx
    ↓
Register result
    ↓
Nếu thành công
    ↓
Print "Nginx check passed"

Nếu thất bại
    ↓
Playbook fail

Gợi ý:

failed_when: nginx_test.rc != 0

54. Exercise 8 — Group Variables

Tạo:

group_vars/
└── webservers.yml

Khai báo:

app_name: todo
app_user: deploy
app_port: 8080

Playbook phải sử dụng Variables từ group_vars.

Sau đó thay đổi:

app_name: payment

và chạy lại.

Kiểm tra xem Playbook có tự động thay đổi theo không.


55. Exercise 9 — Host Variables

Có:

web-01
web-02

Cấu hình:

web-01
    app_port = 8080

web-02
    app_port = 9090

Sử dụng:

host_vars/

để cấu hình.

Sau đó viết Playbook in:

hostname → port

Kết quả:

web-01 → 8080
web-02 → 9090

56. Exercise 10 — Senior Challenge

Xây dựng Playbook:

server-provision.yml

Yêu cầu:

Input

Variables:

app_name
app_user
app_port
packages

Facts

Tự phát hiện:

OS
Architecture
Memory
Hostname
IP

Logic

              Server
                 │
          Gather Facts
                 │
        ┌────────┴────────┐
        ▼                 ▼
     Debian             RedHat
        │                 │
        ▼                 ▼
       apt               dnf
        │                 │
        └────────┬────────┘
                 ▼
          Install packages
                 │
                 ▼
          Create app user
                 │
                 ▼
        Create app directory

Playbook phải chạy được trên cả Debian-family và RedHat-family server.


57. Một vấn đề rất quan trọng: Variable không phải Secret

Không nên:

db_password: "MySuperSecretPassword"

trong:

playbook.yml

hoặc:

group_vars/webservers.yml

nếu file được commit vào Git.

Secret sẽ được học kỹ hơn ở:

Lab 11 — Ansible Secrets & Vault

Ở Lab này chỉ cần nhớ:

Variable
   ≠
Secret

58. Một lỗi nguy hiểm với debug

Không nên debug secret:

- name: Show password
  ansible.builtin.debug:
    var: db_password

Vì secret có thể xuất hiện trong log.

Khi làm việc với secret, cần sử dụng:

no_log: true

và cơ chế quản lý secret phù hợp như Ansible Vault.


59. Tư duy Senior #1 — Tách Logic và Data

Đây là một trong những nguyên tắc quan trọng nhất của Lab này.

Không nên:

Playbook
 ├── Logic
 ├── Configuration
 ├── Environment
 └── Host-specific values

Tốt hơn:

Playbook
   │
   └── Logic

Variables
   │
   ├── Environment config
   ├── Group config
   └── Host config

Ví dụ:

Playbook
   │
   └── "Create application"

Variables
   │
   └── "Application name = todo"

60. Tư duy Senior #2 — Facts giúp Playbook thích nghi

Không nên:

apt:

một cách mù quáng nếu Playbook phải hỗ trợ nhiều OS.

Có thể:

Facts
  ↓
OS Detection
  ↓
Correct module

Ví dụ:

when: ansible_facts.os_family == "Debian"

và:

when: ansible_facts.os_family == "RedHat"

Đây là bước đầu tiên để xây dựng cross-platform automation.


61. Tư duy Senior #3 — Không lạm dụng Facts

Facts rất hữu ích nhưng không phải lúc nào cũng cần.

Nếu Playbook chỉ cần:

Install nginx

thì không nhất thiết phải thu thập hàng trăm thông tin về server.

Có thể:

gather_facts: false

khi thực sự không cần.

Tư duy tốt là:

Gather only what you need, when appropriate.


62. Tư duy Senior #4 — Variable naming

Nên:

app_name
app_user
app_port
app_directory

Không nên:

name
user
port
dir

Vì Playbook lớn sẽ có rất nhiều loại:

user
port
name
path

Tên rõ ràng giúp tránh collision và tăng khả năng đọc.


63. Tư duy Senior #5 — Đừng tạo Variable chỉ để tạo Variable

Không nên biến mọi thứ thành:

nginx_service_name: nginx

nếu giá trị đó không bao giờ thay đổi và không có lý do để cấu hình.

Variable nên tồn tại khi:

  • Có khả năng thay đổi.
  • Phụ thuộc environment.
  • Phụ thuộc host.
  • Được sử dụng nhiều lần.
  • Cần override.
  • Có ý nghĩa cấu hình.

64. Tư duy Senior #6 — register là runtime data

Phân biệt:

Variable
   ↓
Configuration/Input

và:

register
   ↓
Runtime result

Ví dụ:

app_port: 8080

là configuration.

Trong khi:

register: nginx_result

là kết quả của một task vừa chạy.


65. Tư duy Senior #7 — Condition phải dựa trên dữ liệu đáng tin cậy

Ví dụ:

when: ansible_facts.os_family == "Debian"

tốt hơn việc kiểm tra:

cat /etc/os-release

bằng shell rồi parse text thủ công.

Tận dụng dữ liệu Ansible đã cung cấp trước khi tự viết logic bằng shell.


66. Debugging Workflow

Khi Variable không hoạt động:

Variable không đúng
       ↓
debug
       ↓
Kiểm tra giá trị
       ↓
Kiểm tra source
       ↓
Kiểm tra precedence
       ↓
Kiểm tra type

Ví dụ:

- name: Debug application configuration
  ansible.builtin.debug:
    var: app

Đây là kỹ năng cực kỳ quan trọng khi Playbook trở nên lớn.


67. Workflow sau Lab 5

Từ Lab 4:

Playbook
   ↓
Hard-coded values

Sau Lab 5:

Playbook
   │
   ├── Variables
   │      ↓
   │   Configuration
   │
   ├── Facts
   │      ↓
   │   Server information
   │
   └── Register
          ↓
      Runtime result

Và bắt đầu có:

Condition
    ↓
when
    ↓
Dynamic automation

68. Cheat Sheet

Variable

vars:
  app_name: todo

Sử dụng Variable

"{{ app_name }}"

List

packages:
  - nginx
  - curl

Dictionary

app:
  name: todo
  port: 8080

Truy cập:

"{{ app.name }}"

Fact

ansible_facts.distribution

OS Family

ansible_facts.os_family

Hostname

ansible_hostname

Architecture

ansible_facts.architecture

Memory

ansible_facts.memtotal_mb

IP

ansible_facts.default_ipv4.address

Register

register: result

Output

result.stdout

Return code

result.rc

Condition

when: ansible_facts.os_family == "Debian"

Debug

ansible.builtin.debug:
  var: app

69. Checklist hoàn thành Lab 5

Người học nên có thể:

  • [ ] Giải thích Variable là gì.
  • [ ] Khai báo Variable bằng vars.
  • [ ] Sử dụng {{ variable }}.
  • [ ] Sử dụng String.
  • [ ] Sử dụng Number.
  • [ ] Sử dụng Boolean.
  • [ ] Sử dụng List.
  • [ ] Sử dụng Dictionary.
  • [ ] Hiểu nested variables.
  • [ ] Hiểu Ansible Facts.
  • [ ] Hiểu gather_facts.
  • [ ] Lấy hostname.
  • [ ] Lấy OS.
  • [ ] Lấy OS version.
  • [ ] Lấy architecture.
  • [ ] Lấy memory.
  • [ ] Lấy IP.
  • [ ] Sử dụng Facts trong when.
  • [ ] Hiểu register.
  • [ ] Lấy stdout.
  • [ ] Lấy rc.
  • [ ] Sử dụng register + when.
  • [ ] Biết group_vars.
  • [ ] Biết host_vars.
  • [ ] Hiểu cơ bản về variable precedence.
  • [ ] Biết phân biệt Variables và Facts.
  • [ ] Biết phân biệt Variables và register.
  • [ ] Không hard-code configuration không cần thiết.
  • [ ] Có thể viết Playbook chạy trên nhiều loại server.

70. Tổng kết

Sau Lab 5, người học đã đi qua một bước rất quan trọng:

Lab 1
Ansible Fundamentals
        ↓
Lab 2
Inventory & SSH
        ↓
Lab 3
Ad-Hoc Commands
        ↓
Lab 4
Playbook
        ↓
Lab 5
Variables & Facts

Tư duy đã chuyển từ:

"Chạy command này trên server"

sang:

"Đưa server về Desired State"

và tiếp tục tiến tới:

"Đưa mọi server về Desired State
dựa trên configuration và thông tin thực tế của từng server."

Kiến trúc hiện tại:

                  Ansible
                     │
             ┌───────┴────────┐
             ▼                ▼
        Variables           Facts
             │                │
             │                │
       Configuration     Server Info
             │                │
             └───────┬────────┘
                     ▼
                  Playbook
                     │
                  Tasks
                     │
                  Modules
                     │
                     ▼
                Managed Node

Và đây là nền tảng trực tiếp cho Lab 6 — Ansible Templates với Jinja2.

Ở Lab 6, chúng ta sẽ giải quyết vấn đề tiếp theo:

Variable đã giúp Playbook thay đổi dữ liệu, nhưng làm thế nào để dùng những dữ liệu đó sinh ra cả một file configuration động?

Ví dụ:

Variables
    │
    ├── app_name
    ├── app_port
    ├── app_host
    └── workers
           │
           ▼
       Jinja2 Template
           │
           ▼
   nginx.conf / app.conf
           │
           ▼
       Server

Đây là lúc Ansible bắt đầu trở nên rất mạnh trong việc tự động hóa configuration của production server.


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í