Lab 6 — Ansible Templates với Jinja2
Mục tiêu: Sau Lab này, người học có thể sử dụng Jinja2 Template để sinh file configuration động bằng Ansible, kết hợp Variables + Facts + Conditions + Loops, đồng thời hiểu cách xây dựng configuration có thể tái sử dụng cho Dev / Staging / Production.
1. Bối cảnh
Ở Lab 5 — Variables & Facts, chúng ta đã biết cách:
Variables
↓
Configuration data
Facts
↓
Server information
Playbook
↓
Tasks
Ví dụ:
app_name: todo
app_port: 8080
app_user: deploy
Chúng ta có thể sử dụng:
- name: Create application directory
ansible.builtin.file:
path: "/opt/{{ app_name }}"
state: directory
Nhưng trong thực tế, configuration thường không chỉ có một giá trị.
Ví dụ một file Nginx:
server {
listen 80;
server_name todo.example.com;
location / {
proxy_pass http://127.0.0.1:8080;
}
}
Nếu Production dùng:
todo.example.com
8080
nhưng Staging dùng:
staging.todo.example.com
8081
thì không nên tạo:
nginx-dev.conf
nginx-staging.conf
nginx-production.conf
Thay vào đó:
Variables
│
┌─────────┴─────────┐
▼ ▼
Dev config Prod config
│ │
└─────────┬─────────┘
▼
Jinja2 Template
│
▼
nginx.conf
Đây chính là nhiệm vụ của Template.
2. Template là gì?
Template là một file mẫu chứa:
- Static content
- Variables
- Conditions
- Loops
- Logic của Jinja2
Ví dụ:
server {
listen {{ nginx_port }};
server_name {{ server_name }};
location / {
proxy_pass http://127.0.0.1:{{ app_port }};
}
}
Nếu:
nginx_port: 80
server_name: todo.example.com
app_port: 8080
thì Ansible sẽ sinh ra:
server {
listen 80;
server_name todo.example.com;
location / {
proxy_pass http://127.0.0.1:8080;
}
}
3. Jinja2 là gì?
Jinja2 là template engine được Ansible sử dụng để tạo nội dung động.
Có thể hình dung:
Template
+
Variables
+
Facts
+
Logic
│
▼
Jinja2
│
▼
Final configuration
Ví dụ:
Hello {{ name }}
với:
name: Thong
sẽ trở thành:
Hello Thong
4. Cú pháp Jinja2 cơ bản
Có 3 loại syntax quan trọng.
4.1. Expression
Dùng:
{{ variable }}
Ví dụ:
server_name {{ domain }}
4.2. Statement
Dùng:
{% ... %}
Thường dùng cho:
iffor
Ví dụ:
{% if environment == "production" %}
production
{% endif %}
4.3. Comment
Dùng:
{# comment #}
Ví dụ:
{# This is generated by Ansible #}
Comment này sẽ không xuất hiện trong file được generate.
5. {{ }} vs {% %}
Đây là điểm người mới thường nhầm.
In giá trị
{{ app_port }}
Thực hiện logic
{% if environment == "production" %}
Ví dụ:
server {
listen {{ app_port }};
{% if environment == "production" %}
access_log /var/log/nginx/access.log;
{% endif %}
}
6. Tạo project
Tạo:
mkdir ansible-lab-06
cd ansible-lab-06
Cấu trúc ban đầu:
ansible-lab-06/
├── ansible.cfg
├── inventory.ini
├── group_vars/
│ └── webservers.yml
├── templates/
│ └── nginx.conf.j2
└── playbook.yml
7. ansible.cfg
[defaults]
inventory = ./inventory.ini
8. Inventory
[webservers]
web-01 ansible_host=192.168.56.101
web-02 ansible_host=192.168.56.102
Kiểm tra:
ansible-inventory --graph
9. Variables
Tạo:
group_vars/webservers.yml
Nội dung:
app_name: todo
app_host: 127.0.0.1
app_port: 8080
server_name: todo.example.com
nginx_port: 80
10. Tạo Template đầu tiên
Tạo:
templates/nginx.conf.j2
Nội dung:
server {
listen {{ nginx_port }};
server_name {{ server_name }};
location / {
proxy_pass http://{{ app_host }}:{{ app_port }};
}
}
Đây chưa phải file Nginx hoàn chỉnh cho production, nhưng rất phù hợp để hiểu Template.
11. Sử dụng template module
Trong Playbook:
---
- name: Configure nginx
hosts: webservers
become: true
tasks:
- name: Install nginx
ansible.builtin.apt:
name: nginx
state: present
update_cache: true
- name: Deploy nginx configuration
ansible.builtin.template:
src: nginx.conf.j2
dest: /etc/nginx/sites-available/todo.conf
owner: root
group: root
mode: "0644"
Chạy:
ansible-playbook playbook.yml
Ansible sẽ:
templates/nginx.conf.j2
│
│ Jinja2
▼
/etc/nginx/sites-available/todo.conf
12. Kiểm tra file trên server
SSH vào server:
ssh user@192.168.56.101
Kiểm tra:
cat /etc/nginx/sites-available/todo.conf
Bạn sẽ thấy:
server {
listen 80;
server_name todo.example.com;
location / {
proxy_pass http://127.0.0.1:8080;
}
}
Các:
{{ nginx_port }}
{{ server_name }}
{{ app_host }}
{{ app_port }}
đã được thay thế.
13. Template không phải Copy
Đây là điểm rất quan trọng.
Có hai module:
copy
template
copy
Dùng khi file đã hoàn chỉnh:
ansible.builtin.copy:
src: nginx.conf
dest: /etc/nginx/nginx.conf
Nó gần như:
Source file
↓
Copy
↓
Destination
template
Dùng khi file có dữ liệu động:
ansible.builtin.template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
Flow:
Jinja2 Template
+
Variables
+
Facts
+
Conditions
↓
Rendered file
14. Exercise — thay đổi Variable
Thay:
server_name: todo.example.com
thành:
server_name: api.example.com
Chạy lại:
ansible-playbook playbook.yml
Kiểm tra:
cat /etc/nginx/sites-available/todo.conf
Kết quả:
server_name api.example.com;
Bạn không cần sửa Template.
Đây chính là sức mạnh của Template.
15. Template + Facts
Template không chỉ sử dụng Variables.
Nó cũng có thể sử dụng Facts.
Ví dụ:
# Generated by Ansible
server: {{ ansible_hostname }}
os: {{ ansible_facts.distribution }}
architecture: {{ ansible_facts.architecture }}
ip: {{ ansible_facts.default_ipv4.address }}
Nếu server là:
hostname: web-01
OS: Ubuntu
architecture: x86_64
IP: 192.168.56.101
file sinh ra:
# Generated by Ansible
server: web-01
os: Ubuntu
architecture: x86_64
ip: 192.168.56.101
16. Template + if
Jinja2 hỗ trợ điều kiện.
Ví dụ:
server {
listen {{ nginx_port }};
server_name {{ server_name }};
{% if environment == "production" %}
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
{% endif %}
location / {
proxy_pass http://{{ app_host }}:{{ app_port }};
}
}
Variables:
environment: production
thì phần:
{% if environment == "production" %}
được render.
17. if / else
Ví dụ:
{% if environment == "production" %}
worker_processes auto;
{% else %}
worker_processes 1;
{% endif %}
Nếu:
environment: production
kết quả:
worker_processes auto;
Nếu:
environment: development
kết quả:
worker_processes 1;
18. elif
Có thể có nhiều điều kiện:
{% if environment == "production" %}
worker_processes auto;
{% elif environment == "staging" %}
worker_processes 2;
{% else %}
worker_processes 1;
{% endif %}
Flow:
environment
│
├── production → auto
│
├── staging → 2
│
└── other → 1
19. Loop trong Jinja2
Jinja2 cũng hỗ trợ vòng lặp.
Variables:
upstreams:
- 127.0.0.1:8080
- 127.0.0.1:8081
- 127.0.0.1:8082
Template:
upstream backend {
{% for server in upstreams %}
server {{ server }};
{% endfor %}
}
Kết quả:
upstream backend {
server 127.0.0.1:8080;
server 127.0.0.1:8081;
server 127.0.0.1:8082;
}
20. Đây là sức mạnh rất lớn
Thay vì viết:
server 127.0.0.1:8080;
server 127.0.0.1:8081;
server 127.0.0.1:8082;
chúng ta chỉ cần:
upstreams:
- 127.0.0.1:8080
- 127.0.0.1:8081
- 127.0.0.1:8082
Template tự sinh.
Nếu thêm:
- 127.0.0.1:8083
thì Template tự động sinh thêm:
server 127.0.0.1:8083;
21. Loop với Dictionary
Variables:
users:
- name: deploy
shell: /bin/bash
- name: developer
shell: /bin/bash
- name: monitoring
shell: /usr/sbin/nologin
Template:
{% for user in users %}
User: {{ user.name }}
Shell: {{ user.shell }}
{% endfor %}
Kết quả:
User: deploy
Shell: /bin/bash
User: developer
Shell: /bin/bash
User: monitoring
Shell: /usr/sbin/nologin
22. Jinja2 Filters
Một tính năng rất quan trọng của Jinja2 là Filter.
Syntax:
{{ variable | filter }}
Ví dụ:
{{ app_name | upper }}
Nếu:
app_name: todo
kết quả:
TODO
23. Một số Filter cơ bản
upper
{{ app_name | upper }}
lower
{{ app_name | lower }}
default
{{ app_port | default(8080) }}
length
{{ servers | length }}
join
{{ packages | join(', ') }}
24. default
Một tình huống rất thực tế:
Variable có thể không tồn tại.
Thay vì:
{{ app_port }}
có thể:
{{ app_port | default(8080) }}
Nếu app_port không được khai báo:
8080
sẽ được sử dụng.
Tuy nhiên:
Không nên lạm dụng
default.
Nếu một variable bắt buộc phải có, tốt hơn nên để Playbook fail sớm thay vì âm thầm dùng giá trị mặc định sai.
25. Template với ansible_facts
Ví dụ tạo:
templates/server-info.txt.j2
Server Information
==================
Hostname: {{ ansible_hostname }}
OS: {{ ansible_facts.distribution }}
OS Version: {{ ansible_facts.distribution_version }}
Architecture: {{ ansible_facts.architecture }}
Memory: {{ ansible_facts.memtotal_mb }} MB
IP Address: {{ ansible_facts.default_ipv4.address }}
Task:
- name: Generate server information
ansible.builtin.template:
src: server-info.txt.j2
dest: /tmp/server-info.txt
mode: "0644"
26. Template + Environment
Đây là phần cực kỳ quan trọng đối với DevOps.
Tạo:
group_vars/
├── webservers.yml
├── development.yml
└── production.yml
Development:
environment: development
server_name: todo-dev.example.com
app_port: 8080
Production:
environment: production
server_name: todo.example.com
app_port: 8080
Template có thể dùng:
server_name {{ server_name }};
và:
{% if environment == "production" %}
# Production configuration
{% endif %}
Một Template.
Nhiều Environment.
27. Template + Environment
Kiến trúc:
Playbook
│
▼
Jinja2 Template
│
┌──────────┼──────────┐
▼ ▼ ▼
Dev Staging Prod
│ │ │
▼ ▼ ▼
Variables Variables Variables
│ │ │
└──────────┼──────────┘
▼
Rendered Config
Đây là nền tảng cho Lab 13 — Ansible với nhiều Environment.
28. template module quan trọng thế nào?
Một task production thường có dạng:
- name: Deploy configuration
ansible.builtin.template:
src: app.conf.j2
dest: /etc/myapp/app.conf
owner: root
group: root
mode: "0644"
Đây là pattern bạn sẽ gặp rất nhiều:
Template
↓
Configuration
↓
Service
Ví dụ:
nginx.conf.j2
↓
/etc/nginx/nginx.conf
↓
nginx
hoặc:
app.conf.j2
↓
/etc/myapp/app.conf
↓
application
29. Template + Handler
Có một vấn đề:
Nếu configuration thay đổi:
nginx.conf
thì Nginx cần reload.
Không nên:
- name: Deploy config
template:
...
- name: Restart nginx
service:
name: nginx
state: restarted
Vì mỗi lần chạy Playbook đều restart Nginx.
Đây là vấn đề Lab 7 sẽ giải quyết sâu hơn.
Nhưng ở đây chúng ta bắt đầu làm quen:
- name: Deploy nginx configuration
ansible.builtin.template:
src: nginx.conf.j2
dest: /etc/nginx/sites-available/todo.conf
notify: Reload nginx
Handler:
handlers:
- name: Reload nginx
ansible.builtin.service:
name: nginx
state: reloaded
Flow:
Template
│
├── Changed
│ ↓
│ notify
│ ↓
│ Reload nginx
│
└── Not changed
↓
No reload
Đây là một pattern cực kỳ quan trọng trong production.
30. Full Example
Cấu trúc:
ansible-lab-06/
├── ansible.cfg
├── inventory.ini
├── group_vars/
│ └── webservers.yml
├── templates/
│ └── nginx.conf.j2
└── playbook.yml
group_vars/webservers.yml
app_name: todo
app_host: 127.0.0.1
app_port: 8080
server_name: todo.example.com
nginx_port: 80
environment: production
templates/nginx.conf.j2
server {
listen {{ nginx_port }};
server_name {{ server_name }};
{% if environment == "production" %}
access_log /var/log/nginx/{{ app_name }}_access.log;
error_log /var/log/nginx/{{ app_name }}_error.log;
{% endif %}
location / {
proxy_pass http://{{ app_host }}:{{ app_port }};
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
playbook.yml
---
- name: Configure web server
hosts: webservers
become: true
tasks:
- name: Install nginx
ansible.builtin.apt:
name: nginx
state: present
update_cache: true
- name: Deploy nginx configuration
ansible.builtin.template:
src: nginx.conf.j2
dest: "/etc/nginx/sites-available/{{ app_name }}.conf"
owner: root
group: root
mode: "0644"
notify: Reload nginx
handlers:
- name: Reload nginx
ansible.builtin.service:
name: nginx
state: reloaded
31. Kiểm tra Template trước khi Apply
Một kỹ năng rất hữu ích là kiểm tra Playbook trước khi thay đổi server.
ansible-playbook playbook.yml --check
Đây gọi là:
Check Mode
Ansible sẽ cố gắng mô phỏng thay đổi thay vì thực hiện thật.
32. Diff Mode
Có thể sử dụng:
ansible-playbook playbook.yml --check --diff
Đây là command rất hữu ích khi làm việc với Template.
Bạn có thể nhìn thấy:
- server_name old.example.com;
+ server_name todo.example.com;
Tư duy production:
Change configuration
↓
Check
↓
Diff
↓
Review
↓
Apply
33. Kiểm tra Syntax
Trước khi chạy:
ansible-playbook --syntax-check playbook.yml
Nếu Template có lỗi syntax Jinja2, việc render có thể thất bại khi task chạy.
Workflow tốt:
ansible-playbook --syntax-check playbook.yml
ansible-playbook playbook.yml --check --diff
ansible-playbook playbook.yml
34. Exercise 1 — Template cơ bản
Tạo:
templates/app.conf.j2
Nội dung:
Application: {{ app_name }}
Version: {{ app_version }}
Port: {{ app_port }}
Environment: {{ environment }}
Variables:
app_name: todo
app_version: "1.0.0"
app_port: 8080
environment: development
Generate:
/etc/myapp/app.conf
35. Exercise 2 — Template với Facts
Tạo:
templates/server-info.txt.j2
Sinh:
Hostname:
OS:
OS Version:
Architecture:
Memory:
IP:
Tất cả phải lấy từ Facts.
36. Exercise 3 — Template với if
Tạo:
environment: production
Nếu Production:
DEBUG=false
LOG_LEVEL=INFO
Nếu Development:
DEBUG=true
LOG_LEVEL=DEBUG
Template:
{% if environment == "production" %}
DEBUG=false
LOG_LEVEL=INFO
{% else %}
DEBUG=true
LOG_LEVEL=DEBUG
{% endif %}
37. Exercise 4 — Template với Loop
Variables:
backend_servers:
- 10.0.0.11:8080
- 10.0.0.12:8080
- 10.0.0.13:8080
Generate:
upstream backend {
server 10.0.0.11:8080;
server 10.0.0.12:8080;
server 10.0.0.13:8080;
}
Không được viết thủ công từng server trong Template.
38. Exercise 5 — Dynamic Nginx
Tạo Template:
templates/nginx.conf.j2
Variables:
server_name: todo.example.com
nginx_port: 80
app_host: 127.0.0.1
app_port: 8080
Template phải generate Reverse Proxy:
Client
│
▼
Nginx :80
│
▼
Application :8080
39. Exercise 6 — Multi Environment
Tạo:
group_vars/
├── development.yml
├── staging.yml
└── production.yml
Mỗi Environment có:
environment:
server_name:
app_port:
Template duy nhất:
templates/app.conf.j2
Yêu cầu:
1 Template
│
├── Development
├── Staging
└── Production
Không tạo:
app-dev.conf.j2
app-staging.conf.j2
app-production.conf.j2
40. Exercise 7 — Template + Handler
Khi Template thay đổi:
Reload nginx
Khi Template không thay đổi:
Không reload
Kiểm tra bằng:
ansible-playbook playbook.yml
lần đầu.
Sau đó chạy lại:
ansible-playbook playbook.yml
Lần thứ hai phải có:
changed=0
và handler không chạy.
41. Exercise 8 — Senior Challenge
Xây dựng một hệ thống cấu hình Nginx hoàn chỉnh.
Variables:
app:
name: todo
domain: todo.example.com
port: 8080
nginx:
port: 80
environment: production
backend_servers:
- 127.0.0.1:8080
- 127.0.0.1:8081
Template phải generate:
upstream todo_backend {
server 127.0.0.1:8080;
server 127.0.0.1:8081;
}
server {
listen 80;
server_name todo.example.com;
location / {
proxy_pass http://todo_backend;
}
}
Thêm:
Production
↓
access log
error log
Development:
Development
↓
debug configuration
42. Những lỗi người mới thường gặp
Lỗi 1 — Quên .j2
Không bắt buộc về mặt kỹ thuật, nhưng convention nên là:
nginx.conf.j2
thay vì:
nginx.conf
để người khác biết đây là Jinja2 Template.
Lỗi 2 — Sai {{ }}
Sai:
server_name { server_name };
Đúng:
server_name {{ server_name }};
Lỗi 3 — Nhầm {% %} và {{ }}
Sai:
{{ if environment == "production" }}
Đúng:
{% if environment == "production" %}
43. Lỗi 4 — Quên đóng if
Sai:
{% if environment == "production" %}
access_log /var/log/nginx/access.log;
Đúng:
{% if environment == "production" %}
access_log /var/log/nginx/access.log;
{% endif %}
44. Lỗi 5 — Template phụ thuộc Variable không tồn tại
Ví dụ:
server_name {{ domain_name }};
nhưng không có:
domain_name:
Có thể dẫn tới lỗi hoặc output không như mong muốn tùy context.
Tốt hơn nên thiết kế Variables rõ ràng và validate input khi cần.
45. Lỗi 6 — Template quá nhiều logic
Không nên biến Template thành một chương trình:
{% if ... %}
{% for ... %}
{% if ... %}
{% for ... %}
{% if ... %}
...
Nếu Template có quá nhiều logic:
Template
↓
Khó đọc
Khó test
Khó maintain
Nên đưa configuration data về Variables và giữ Template đơn giản.
46. Lỗi 7 — Hard-code trong Template
Không nên:
proxy_pass http://127.0.0.1:8080;
nếu giá trị có thể thay đổi.
Nên:
proxy_pass http://{{ app_host }}:{{ app_port }};
47. Tư duy Senior #1 — Template là "presentation layer"
Một cách tư duy rất tốt:
Variables
↓
Data
Template
↓
Presentation
Module
↓
Deployment
Ví dụ:
app_port: 8080
↓
nginx.conf.j2
↓
proxy_pass :8080
↓
/etc/nginx/nginx.conf
Template không nên chứa quá nhiều business logic.
48. Tư duy Senior #2 — Data-driven automation
Thay vì:
Nếu server A
làm A
Nếu server B
làm B
Nếu server C
làm C
hãy hướng tới:
Configuration Data
↓
Generic Template
↓
Generated Configuration
Đây là tư duy data-driven automation.
49. Tư duy Senior #3 — Một Template, nhiều Environment
Không nên:
dev.conf.j2
staging.conf.j2
production.conf.j2
nếu sự khác biệt chỉ nằm ở configuration.
Tốt hơn:
app.conf.j2
và:
Development variables
Staging variables
Production variables
Flow:
app.conf.j2
│
┌─────────┼─────────┐
▼ ▼ ▼
Dev Staging Prod
│ │ │
▼ ▼ ▼
config config config
50. Tư duy Senior #4 — Configuration phải deterministic
Cùng một:
Template
+
Variables
+
Facts
nên tạo ra cùng một configuration.
Input
↓
Template
↓
Output
Điều này giúp:
- Debug.
- Review.
- Audit.
- Reproduce.
- CI/CD.
51. Tư duy Senior #5 — Template + Idempotency
Đây là nền tảng của Lab 7.
Nếu configuration không thay đổi:
template
↓
same content
↓
changed = false
↓
no handler
Nếu configuration thay đổi:
template
↓
different content
↓
changed = true
↓
notify handler
↓
reload service
Đây là automation đúng cách.
52. Tư duy Senior #6 — Check trước khi Apply
Một workflow tốt:
Code
↓
Syntax Check
↓
Check Mode
↓
Diff
↓
Review
↓
Apply
Commands:
ansible-playbook --syntax-check playbook.yml
ansible-playbook playbook.yml --check --diff
sau đó:
ansible-playbook playbook.yml
Đây là thói quen rất nên hình thành ngay từ đầu.
53. Template trong Production
Template được sử dụng rất nhiều để generate:
Nginx
Apache
HAProxy
Systemd
Docker Compose
Application config
Environment files
Prometheus
Alertmanager
Fluent Bit
Loki
SSH
Database
Ví dụ trong DevOps:
Ansible
│
├── nginx.conf.j2
├── docker-compose.yml.j2
├── application.yml.j2
├── prometheus.yml.j2
└── systemd.service.j2
Sau đó:
Variables
↓
Templates
↓
Configuration
↓
Services
54. Một ví dụ gần với Kubernetes/DevOps
Giả sử application có:
app:
name: todo
port: 8080
database:
host: postgres.internal
port: 5432
redis:
host: redis.internal
port: 6379
Template:
server:
port: {{ app.port }}
database:
host: {{ database.host }}
port: {{ database.port }}
redis:
host: {{ redis.host }}
port: {{ redis.port }}
Ansible có thể generate:
application.yml
cho từng Environment.
Đây là một pattern rất phổ biến trong infrastructure automation.
55. Lab Challenge — Production Configuration Generator
Đây là bài tập cuối Lab 6.
Xây dựng:
ansible-lab-06/
├── ansible.cfg
├── inventory.ini
├── group_vars/
│ └── webservers.yml
├── templates/
│ ├── nginx.conf.j2
│ └── server-info.txt.j2
└── playbook.yml
Variables
app:
name: todo
host: 127.0.0.1
port: 8080
nginx:
port: 80
environment: production
backend_servers:
- 127.0.0.1:8080
- 127.0.0.1:8081
Template phải có
Nginx
upstream
server
proxy_pass
server_name
access log
error log
Environment
Production:
access log
error log
Development:
debug
Backend
Loop qua:
backend_servers
để generate upstream.
Server Info
Sử dụng Facts:
hostname
OS
version
architecture
memory
IP
Handler
Nếu Nginx configuration thay đổi:
Reload nginx
Nếu không:
Không reload
56. Checklist hoàn thành Lab 6
Người học cần nắm được:
- [ ] Template là gì.
- [ ] Jinja2 là gì.
- [ ]
{{ }}. - [ ]
{% %}. - [ ]
{# #}. - [ ]
templatemodule. - [ ] Template + Variables.
- [ ] Template + Facts.
- [ ]
if. - [ ]
elif. - [ ]
else. - [ ]
for. - [ ] Jinja2 Filters.
- [ ]
default. - [ ]
upper. - [ ]
lower. - [ ]
join. - [ ] Template +
group_vars. - [ ] Template + Environment.
- [ ] Template + Handler.
- [ ] Check Mode.
- [ ] Diff Mode.
- [ ] Syntax Check.
- [ ] Hiểu Template và Copy khác nhau thế nào.
- [ ] Hiểu Template nên chứa presentation logic, không nên chứa quá nhiều business logic.
- [ ] Có thể tạo một Template dùng cho nhiều Environment.
- [ ] Có thể generate Nginx configuration động.
57. Tổng kết
Sau Lab 5:
Variables
Facts
↓
Playbook
Sau Lab 6:
Variables
│
│
Facts
│
▼
Jinja2 Template
│
┌─────────┼─────────┐
▼ ▼ ▼
Dev Staging Prod
│ │ │
▼ ▼ ▼
Config Config Config
Người học đã chuyển từ:
"Ansible chạy task như thế nào?"
sang:
"Ansible có thể tự động sinh configuration phù hợp với từng server/environment như thế nào?"
Đây là một bước tiến rất quan trọng trên con đường lên DevOps/Senior.
Và Lab tiếp theo sẽ ghép hai kiến thức quan trọng lại với nhau:
Lab 6
Templates
│
▼
Configuration changes
│
▼
Lab 7
Handlers & Idempotency
│
├── Nếu config đổi
│ ↓
│ Reload/Restart
│
└── Nếu config không đổi
↓
Không làm gì
Lab 7 — Ansible Handlers & Idempotency sẽ là bài đặc biệt quan trọng vì đây là lúc người học bắt đầu hiểu sâu hơn về tư duy Desired State, Idempotent Automation và cách tránh gây downtime không cần thiết trong production.
All rights reserved