Mục tiêu học tập
Kiến trúc Ansible
Hiểu mô hình Control Node / Managed Nodes, cách Ansible giao tiếp qua SSH mà không cần agent trên managed nodes.
Inventory Files
Tạo inventory files để nhóm và quản lý các hosts, sử dụng static inventory và hiểu cách phân nhóm hosts.
Playbooks YAML
Viết Ansible playbooks định dạng YAML để tự động hóa: cài đặt packages, cấu hình services, quản lý files và users.
Ansible Modules
Sử dụng các modules phổ biến: dnf/yum (packages), service, copy, template, user, file, command, shell.
Ad-hoc Commands
Chạy lệnh ansible ad-hoc trực tiếp (-m module) để thực hiện tasks ngay lập tức mà không cần playbook.
Roles
Tổ chức playbooks thành roles có thể tái sử dụng, hiểu cấu trúc thư mục role và cách sử dụng Ansible Galaxy.
Lý thuyết: Ansible Automation
1. Kiến trúc Ansible
Control Node
Máy chạy Ansible. Cài ansible package. Chạy playbooks từ đây. SSH ra managed nodes.
Managed Nodes
Các hosts được Ansible quản lý. Không cần cài Ansible agent. Chỉ cần SSH + Python.
2. Cài đặt Ansible và SSH Keys
# Cài Ansible trên control node (Fedora/RHEL)
$ sudo dnf install ansible -y
$ ansible --version
ansible [core 2.17.3]
python version = 3.12.5
# Thêm hosts vào /etc/hosts
$ sudo tee -a /etc/hosts <<'EOF'
192.168.122.154 host01
192.168.122.94 host02
192.168.122.189 host03
EOF
# Tạo SSH key pair
$ ssh-keygen -t ed25519
Generating public/private ed25519 key pair.
Enter file: /home/joe/.ssh/id_ed25519: [Enter]
Enter passphrase: [Enter]
# Copy SSH key đến các managed nodes
$ for i in 1 2 3; do ssh-copy-id joe@host0$i; done
Number of key(s) added: 1
Now try logging into the machine, with: "ssh 'joe@host01'"
3. Inventory Files
# Inventory file - nhóm hosts theo mục đích
[webservers]
host01
host02
[dbservers]
host03
[production:children]
webservers
dbservers
[webservers:vars]
http_port=80
ansible_user=joe
$ ansible -i inventory.ini all --list-hosts
hosts (3):
host01
host02
host03
$ ansible -i inventory.ini webservers --list-hosts
hosts (2):
host01
host02
4. Ad-hoc Commands
# Ping tất cả hosts
$ ansible -i inventory.ini all -m ping
host01 | SUCCESS => {"changed": false, "ping": "pong"}
host02 | SUCCESS => {"changed": false, "ping": "pong"}
host03 | SUCCESS => {"changed": false, "ping": "pong"}
# Chạy command trên group webservers
$ ansible -i inventory.ini webservers -m command -a "uptime"
host01 | SUCCESS | rc=0 >>
09:15:32 up 2 days, 3:42, 1 user, load average: 0.01, 0.02, 0.00
# Cài package với module dnf (cần become root)
$ ansible -i inventory.ini webservers -m dnf \
-a "name=nginx state=present" --become
host01 | CHANGED => {"changed": true, "msg": "Installed: nginx-1.24.0"}
host02 | CHANGED => {"changed": true, "msg": "Installed: nginx-1.24.0"}
# Xem help cho module copy
$ ansible-doc copy
> ANSIBLE.BUILTIN.COPY (/usr/lib/python3/dist-packages/ansible/...)
The copy module copies a file from local or remote machine...
5. Ansible Playbooks
---
- name
: Deploy Nginx Web Serverhosts
: webserversbecome
: yesvars
:web_port: 80
web_root: /var/www/html
tasks
:- name: Install nginx
dnf:
name: nginx
state: latest
- name: Start and enable nginx
service:
name: nginx
state: started
enabled: yes
- name: Copy index.html to web root
copy:
src: files/index.html
dest: "{{ web_root }}/index.html"
owner: root
mode: '0644'
- name: Open firewall for HTTP
firewalld:
service: http
permanent: yes
state: enabled
immediate: yes
- name: Create web developer user
user:
name: webdev
groups: wheel
shell: /bin/bash
create_home: yes
state: present
# Dry run (check mode) - không thay đổi thực tế
$ ansible-playbook -i inventory.ini webserver-playbook.yml --check
# Chạy playbook thực sự
$ ansible-playbook -i inventory.ini webserver-playbook.yml
PLAY [Deploy Nginx Web Server] ***********************
TASK [Gathering Facts] ******* ok: [host01] ok: [host02]
TASK [Install nginx] ********* changed: [host01] changed: [host02]
TASK [Start and enable nginx] changed: [host01] changed: [host02]
TASK [Copy index.html] ******* changed: [host01] changed: [host02]
TASK [Open firewall for HTTP] changed: [host01] changed: [host02]
TASK [Create web developer user] changed: [host01] changed: [host02]
PLAY RECAP ********************************************
host01 : ok=6 changed=5 unreachable=0 failed=0
host02 : ok=6 changed=5 unreachable=0 failed=0
6. Ansible Roles
Roles cho phép tổ chức playbooks thành các đơn vị tái sử dụng. Mỗi role có cấu trúc thư mục chuẩn:
$ ansible-galaxy init roles/nginx
- Role roles/nginx was created successfully
$ tree roles/nginx/
roles/nginx/
├── defaults/ # Default variables
│ └── main.yml
├── files/ # Static files to copy
├── handlers/ # Handler definitions
│ └── main.yml
├── tasks/ # Task definitions
│ └── main.yml
├── templates/ # Jinja2 templates
└── vars/ # Role variables
└── main.yml
Lab Thực Hành
Triển khai web server tự động với Ansible: cài Nginx, cấu hình firewall, tạo users và deploy web content lên 3 managed nodes từ một control node.
Cài Ansible trên Control Node
$ sudo dnf install ansible -y
$ ansible --version | head -2
ansible [core 2.17.3]
Setup SSH Keys đến managed nodes
$ ssh-keygen -t ed25519 -f ~/.ssh/ansible_key
$ for i in 1 2 3; do
ssh-copy-id -i ~/.ssh/ansible_key.pub joe@host0$i
done
$ ssh -i ~/.ssh/ansible_key joe@host01 "hostname"
host01
Tạo Inventory File
[webservers]
host01 ansible_user=joe
host02 ansible_user=joe
host03 ansible_user=joe
[webservers:vars]
ansible_ssh_private_key_file=~/.ssh/ansible_key
$ ansible -i hosts.ini all -m ping
host01 | SUCCESS => {"ping": "pong"}
host02 | SUCCESS => {"ping": "pong"}
host03 | SUCCESS => {"ping": "pong"}
Viết Playbook triển khai Nginx
---
- name
: Deploy Nginx on webservershosts
: webserversbecome
: yestasks
:- name: Install nginx
dnf: name=nginx state=latest
- name: Enable and start nginx
service: name=nginx state=started enabled=yes
- name: Deploy index.html
copy:
content: "<h1>Deployed by Ansible</h1>"
dest: /usr/share/nginx/html/index.html
- name: Open HTTP port
firewalld: service=http permanent=yes state=enabled immediate=yes
Chạy Playbook
$ ansible-playbook -i hosts.ini deploy-web.yml --ask-become-pass
BECOME password: ****
PLAY [Deploy Nginx on webservers] ********************
TASK [Install nginx] *** changed: [host01] changed: [host02] changed: [host03]
TASK [Enable and start nginx] changed: [host01] changed: [host02] changed: [host03]
TASK [Deploy index.html] changed: [host01] changed: [host02] changed: [host03]
PLAY RECAP: host01/02/03 ok=4 changed=3 unreachable=0 failed=0
Xác nhận kết quả
$ for h in host01 host02 host03; do
echo "=== $h ==="
curl -s http://$h/
done
=== host01 ===
<h1>Deployed by Ansible</h1>
=== host02 ===
<h1>Deployed by Ansible</h1>
=== host03 ===
<h1>Deployed by Ansible</h1>
Câu hỏi ôn tập
Ansible "agentless" có nghĩa là gì?
Inventory file trong Ansible dùng để làm gì?
hosts: webservers); (2) assign variables per-host hoặc per-group; (3) tạo group hierarchy ([prod:children]). Default inventory: /etc/ansible/hosts.
Sự khác biệt giữa ad-hoc command và playbook?
ansible hosts -m module -a args. Nhanh, không cần file. Dùng cho tasks đơn giản như ping, kiểm tra. Playbook: file YAML định nghĩa nhiều tasks theo thứ tự. Reusable, versionable, idempotent. Dùng cho automation phức tạp, deployment workflows.
become: yes trong playbook có nghĩa là gì?
become: yes cho phép Ansible escalate privileges lên root (qua sudo) khi thực thi tasks. Tương đương chạy lệnh với sudo. Dùng khi tasks cần root: install packages, cấu hình system services, chỉnh sửa system files. Kết hợp với --ask-become-pass để nhập sudo password.
Idempotency trong Ansible có nghĩa là gì?
state: present), Ansible không install lại. Output hiển thị ok thay vì changed. Cho phép chạy playbooks an toàn bất kỳ lúc nào mà không lo gây ra side effects.
Module dnf và module service trong Ansible làm gì?
state: present/absent/latest. Ví dụ: dnf: name=nginx state=latest. service module: quản lý systemd services. state: started/stopped/restarted, enabled: yes/no. Ví dụ: service: name=nginx state=started enabled=yes.
Lệnh ansible --check (dry run) dùng để làm gì?
--check chạy playbook ở chế độ "what-if" — Ansible kiểm tra những gì sẽ thay đổi nhưng không thực sự thực hiện. Useful để: preview changes trước khi apply, validate playbook syntax, CI/CD testing. Một số modules không hỗ trợ check mode và sẽ bị skip.
Ansible Role khác gì so với một Playbook thông thường?