Xin chào các bạn, đây là bài thứ 3 trong series ansible của mình. Ở bài 1 và bài 2 mình đã giới thiệu với các bạn về Ansible và cách để cài đặt cũng như cách chạy một ad-hoc đơin giản trên các mát target. Trong bài này mình sẽ hướng dẫn các bạn setup một playbook đơn giản.Playbook Ansible chính là cách để sử dụng module hoàn thành một tác vụ. Nó là một tệp cấu hình được viết bằng YAML cung cấp các hướng dẫn về việc cần thực hiện trên các nút quản lý vào trạng thái mong muốn. Nó rất đơn giản, bạn có thể đọc được và tự ghi lại. Điều này có nghĩa Playbook có thể chạy trên hệ thống bất cứ lúc nào mà không gây ảnh hưởng tiêu cực.
Một số thuật ngữ trong Ansible
Dưới đây là danh sách một số thuật ngữ được Ansible sử dụng:
- Control Node/Management Control : server cài đặt Ansible, chịu trách nhiệm cho việc “đưa các công việc bạn cung cấp đến các server từ xa mà bạn quản lý và chạy chúng” .Nói một cách dễ hiểu hơn thì đây là server mà bạn đứng trên đó và lệnh cho các server khác thực hiện các việc bạn muốn mà không cần trực tiếp đăng nhập vào chúng.
- Inventory : Một file INI chứa các thông tin về các server từ xa mà bạn quản lý.
- Playbook : Một file YAML chứa một tập các công việc cần tự động hóa.
- Task : một task sẽ xác định một công việc đơn lẻ sẽ được thực hiện.
- Module : Một Module sẽ trừu tượng hóa một tác vụ hệ thống. Ansible cũng cấp rất nhiều Module tích hợp để ta sử dụng nhưng nếu muốn bạn cũng có thể tự tạo Module. Nói cách khác, ta giao tiếp với Ansible thông qua các Module.
- Role : Một tập hợp các Playbook, các template và các file khác, được tổ chức theo cách được xác định trước để tạo điều kiện tái sử dụng và chia sẻ.
- Play : Một lần thực thi suôn sẻ từ đầu tới cuối được gọi là một play.
- Facts : Các biến toàn cục chứa các thông tin về hệ thống, như các network interface hay operating system.
- Handlers : Sử dụng để kích hoạt thay đổi trạng thái các service, như việc ta restart hay reload một service
Một đống các khái niệm khô khan.
Đọc qua chẳng có chút gì đọng lại được cả, đúng không?
Đễ dễ hiểu bạn có thế nhìn qua sơ đồ sau:
Bạn đứng trên một Node Control và ra lệnh cho các server mà bạn quản lý. Tuy nhiên vấn đề đặt ra là số lượng thao tác cần thực hiện trên các server kìa thì nhiều, nhiều server có tác dụng,nhiệm vụ giống nhau nên cần thực hiện các tháo tác giống nhau. Vậy không lẽ bạn định gõ tay hàng trăm thậm chí hàng ngàn lệnh. Để rồi khi có một server mới, bạn lại gõ tay lại, chưa kể việc sai sót khi thao tác. Lúc này bạn sẽ cần viết một Playbook – nơi sẽ chứa chi tiết tất cả những gì bạn muốn làm với các server từ xa kia và cách thức thực hiện chúng Mỗi một thao tác trong Playbook gọi là một Task (Cài đặt, khởi động, dừng,….) Ta sử dụng Module để tạo thành Task (Ví dụ: muốn cài đặt một gói trên CentOs7 ta sử dụng Module yum của Ansible). Có việc cần làm rồi, giờ ta cần truyền thông tin chi tiết hơn về server cho Playbook chứ không thì làm sao nó biết sẽ làm việc với ai. Lúc này ta cần đến Inventory.
Vậy ansible hoạt động như thế nào khi sử dụng playbook?
Tương tự như ad-hoc Ansible sẽ dùng SSH để chạy lệnh trên các server target thông qua cấu trúc của file playbook.
Thành phần cơ bản của 1 playbook.
Một tệp playbook Ansible có cấu trúc dựa trên cú pháp YAML. Cấu trúc chung của một tệp playbook bao gồm một loạt các mục sau:
Khai báo
---
: Tệp playbook Ansible bắt đầu bằng dòng---
để chỉ ra rằng đây là một tệp YAML.Khai báo
name
: Mụcname
cho phép bạn đặt tên cho playbook để mô tả mục đích hoặc công việc mà playbook thực hiện.Khai báo
hosts
: Mụchosts
xác định tên của các máy chủ hoặc nhóm máy chủ mà playbook sẽ chạy trên. Nếu bạn xác định một nhóm máy chủ, các task sẽ được thực thi trên tất cả các máy chủ trong nhóm đó.Khai báo
become
(tùy chọn): Mụcbecome
xác định xem liệu playbook có cần chạy với quyền đặc quyền (privileged) hay không. Nếubecome: yes
được đặt, các task trong playbook sẽ được thực thi với quyền đặc quyền (thông quasudo
hoặcsu
).Các task: Các task là các công việc cụ thể mà playbook sẽ thực hiện. Mỗi task bao gồm một hoặc nhiều module Ansible và các tham số tương ứng. Một task có thể làm việc với các module như
copy
,shell
,apt
,service
, và nhiều module khác. Mỗi task thường có một tên, một module và các tham số của module đó.
Cấu trúc mẫu của 1 file Ansible Playbook như sau
---
- name: Tên playbook
hosts: tên_máy_chủ
become: yes
tasks:
- name: Tên task 1
module1:
tham_số_1: giá_trị_1
tham_số_2: giá_trị_2
- name: Tên task 2
module2:
tham_số_3: giá_trị_3
tham_số_4: giá_trị_4
Dưới đây là một mẫu file ansible đơn giản để thực hiện update repo và cài một số packages cơ bản.
---
- name : Ansible Playbook Demo #Ten cua Playbook
hosts: target-server # Server hoac group Server thuc hien playbook
become: true # Cap quyen thuc hien thao tac duoi quyen root
task:
- name: Update Repo
apt:
update_cache: yes
- name: Install CURL
apt:
name: curl
state: persent
- name: Install nettool
name: net-tools
state: persent
Trong ví dụ trên, mình sử dụng modules apt của Ansible do mình sử dụng các target chạy hệ điều hành Ubutu 22, nếu bạn sử dụng CentOS7 thì bạn có thể sử dụng modules là yum. Ngoài ra để đáp ứng được nhu cầu thì các bạn có thể xem thêm nhiều modules và cách sử dụng của chúng tại trang tài liệu của Ansible.
Để chạy file ansible play book ta dùng lệnh sau:
ansible-playbook -i path_to_inventory_file path_to_playbook
- -i : Chỉ định đường dẫn inventory file, mặc định nếu bạn không truyền tham số này vào sẽ sử dụng file host mặc định của ansible
Ví dụ khi chạy fie ansible mẫu trên như sau:
[root@ansible]# ansible-playbook playbook_ansible.yaml
[WARNING]: Invalid characters were found in group names but not replaced, use -vvvv to see details
PLAY [Ansible Playbook Demo] **************************************************************************************************************************************
TASK [Gathering Facts] ********************************************************************************************************************************************
ok: [server1]
ok: [server2]
TASK [Update Repo] ************************************************************************************************************************************************
changed: [server1]
changed: [server2]
TASK [Install CURL] ***********************************************************************************************************************************************
ok: [server1]
ok: [server2]
TASK [Install nettool] ********************************************************************************************************************************************
changed: [server1]
changed: [server2]
PLAY RECAP ********************************************************************************************************************************************************
server1 : ok=4 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
server2 : ok=4 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Một số biến có thê sử dụng trong Playbook
Loop Item
Phần trước, thay vì viết module apt cho từng gói cài đặt. Giờ ta sẽ nhóm vào Item để chạy 1 lần luôn.
### VD cho Ubuntu###
---
- hosts: allone
become: yes
tasks:
- name: Install Apache.
apt:
name: "{{ item }}"
state: present
loop:
- apache2
- mysql-server
- php
- php-mysql
- name: Restart Apache and Mysql
service:
name: "{{item}}"
state: running
loop:
- apache2
- mysql
### VD cho Centos7###
--
- hosts: allone
become: yes
tasks:
- name: Install Apache.
yum:
name: "{{ item }}"
state: present
loop:
- nginx
- redis
- name: Restart Apache and Mysql
service:
name: "{{item}}"
state: restarted
loop:
- nginx
- redis
Handlers
Handlers giúp chúng ta gọi lại hành động thực thi nhiều lần (notify) mà không cần phải viết lại.
---
- hosts: allone
become: yes
tasks:
- name: Install Apache.
apt:
name: "{{ item }}"
state: present
loop:
- apache2
- mysql-server
- php
- php-mysql
- name: deploy html file
template:
src: /tmp/index.html
dest: /var/www/html/index.html
notify: restart web
handlers:
- name: restart web
service:
name: "{{ item }}"
state: running
loop:
- apache2
- mysql
### Ví dụ handlers cho Centos
---
- hosts: allone
become: yes
tasks:
- name: Install Apache.
yum:
name: "{{ item }}"
state: present
loop:
- nginx
- redis
notify: restart service
handlers:
- name: restart service
service:
name: "{{ item }}"
state: restarted
loop:
- nginx
- redis
Nếu handlers không chạy (do file không có sự thay đổi), bạn hãy thử sửa file /tmp/index.html và chạy lại. Ansible nhận ra sự thay đổi của file index nên sẽ thực thi Handlers.
C.Variables và Template
Đặt giá trị cho biến cố định
---
- hosts: allone
become: yes
vars:
- domain_name: "thanhdan.name.vn"
- index_file: "index.html"
- config_file: "thanhdan.conf"
tasks:
- name: Install Apache.
apt:
name: "{{ item }}"
state: present
loop:
- apache2
- mysql-server
- php
- php-mysql
- name: deploy html file
template:
src: /tmp/{{ index_file }}
dest: /var/www/html/index.html
notify: restart web
handlers:
- name: restart web
service:
name: "{{ item }}"
state: running
loop:
- apache2
- mysql
Sử lại file index.html ở trên server ansible.
vim /tmp/index.html
This is
FILE_NAME: {{ index_file }}
DOMAIN NAME: {{ domain_name }}
Kết quả cho ta biết là Variable có thể ăn đến tận file được deploy nhờ Template.
Fact và when
Ở đây ta sẽ dùng Fact để lấy thông tin và dùng when để thiết lập varriable. Ta có nhìn qua thông tin của Fact client bằng lệnh sau
#ansible 192.168.1.59 -m setup
---
- hosts: allone
become: yes
tasks:
- name: Define Red Hat.
set_fact:
package_name: "httpd"
when:
ansible_os_family == "Red Hat"
- name: Define Debian.
set_fact:
package_name: "apache2"
when:
ansible_os_family == "Debian"
- name: Stop apache
service:
name: "{{ package_name }}"
state: stopped
#ansible 192.168.1.59 -m setup
Một số Module Ansible thuòng được sử dụng
Module 1: Package management
Đây là module được thiết kế cho hầu hết các trình quản lý gói (package management) phổ biến, chẳng hạn như apt, dnf,… cho phép bạn cài đặt các package trên hệ thống. Ngoài các chức năng cụ thể của từng trình quản lý gói thì hầu hết các trình quản lý gọi đều có thể install, update, upgrade, downgrade, remove, và list các packages.
Ví dụ, ở đây, mình có một task là install gói httpd trên CentOS/RHEL 8 sử dụng trình quản lý gói dnf.
- hosts: all
user: ansible
become: True
tasks:
- name: Install httpd package
dnf:
name: httpd
state: present
update_cache: True
Module 2: Flie
Trong Ansible, có nhiều các module làm việc với tệp tin, thư mục, links trên các node đích (node client) như copy, template, file,… thường được sử dụng. Trước tiên, chúng ta sẽ cùng tìm hiểu về file module. File module giúp quản lý tập tin và các thuộc tính của nó. Ngoài việc taọ, xóa, xác định vị trí của tệp tin file module cũng đặt các quyền và quyền sở hữu hay thiết lập symlinks cho tệp tin.
Ví dụ,
- hosts: all
user: ansible
become: True
tasks:
- name: Change file ownership, group and permissions
file:
path: /etc/thuntt.config
owner: danht
group: systemadmin
mode: '0644'
- name: Create an insecure file
file:
path: /vnh
owner: root
group: root
mode: '1777'
- name: Create a symbolic link
file:
src: /file/to/link/to
dest: /path/to/symlink
owner: danht
group: systemadmin
state: link
Module 3: Template
Có nhiều cách khác nhau với Ansible giúp bạn có thể thao tác với nội dung của tệp, ngoài template module thì mình còn thấy lineinfile module cũng rất phổ biến và được sử dụng nhiều. Tuy nhiên, đối với mình, sau khi sử dụng thì mình cảm thấy template module rõ ràng và dễ hiểu hơn khá nhiều so với lineinfile module.Template trong Ansible là một tệp chứa tất cả các tham số cấu hình của bạn, nhưng các giá trị động được cung cấp dưới dạng biến. Trong quá trình thực thi playbook, các biến có thể được thay thế bằng các giá trị bạn cần. Ngoài ra, bạn có thể làm được nhiều việc hơn là thay thế các biến, với sự trợ giúp của công cụ tạo template Jinj2. Bạn có thể có các câu lệnh có điều kiện, vòng lặp, viết macro, bộ lọc để chuyển đổi dữ liệu, thực hiện các phép tính số học, v.v. Các tệp template thường sẽ có phần mở rộng là .j2
. Các biến trong tệp template sẽ được ký hiệu bằng dấu ngoặc nhọn kép, ‘{{biến}}’.
- hosts: all
vars:
variable_to_be_replaced: 'Hello world'
inline_variable: 'hello again'
tasks:
- name: Ansible Template Example
template:
src: hello_world.j2
dest: /Users/mdtutorials2/Documents/Ansible/hello_world.txt
hello_world.j2
--------------
{{ variable_to_be_replaced }}
This line won't be changed
Variable given as inline - {{ inline_variable }} - 🙂
output - hello_world.txt
------
Hello world
This line won't be changed
Variable given as inline - hello again - 🙂
mdtutorials2$ ls -lrt hello_world.txt
-rw-r--r-- 1 root wheel 81 Oct 16 07:23 hello_world.txt
Module 4: Copy
Copy module là module thường được sử dụng khi chúng ta muốn sao chép một tệp tin từ Ansible server (Management node) đến các node đích (client node).
Ví dụ:
- name: copy file from local to remote with owner, group and file permissions (octal)
copy:
src: test_file
dest: $HOME/test_file
owner: danht
group: danht
mode: 0644
- name: copy file from local to remote with owner, group and file permissions (octal)
copy:
src: test_file
dest: $HOME/test_file
owner: danht
group: danht
mode: 0644
- name: copy file from local to remote with root as the owner (become required)
copy:
src: test_file
dest: "/home/{{ ansible_user }}/test_file"
owner: root
group: root
mode: 0644
become: true
Modlue 5: Service
Đối với các node client là Unix/Linux, service module là một module rất hữu ích giúp kiểm soát các service chạy trên các server này. Giống với các module khác, service module cũng đi kèm với một số tham số và các tham số này có các tùy chọn riêng hoặc giá trị phù hợp. Sử dụng các tham số này và các giá trị bắt buộc, các banj có thể quản lý các service với các chức năng như stop, start, reload, … trên các node client.
Ví dụ:
- name: Start service httpd, if not running
service:
name: httpd
state: started
- name: Stop service httpd, if running
service:
name: httpd
state: stopped
- name: Restart service httpd, in all cases
service:
name: httpd
state: restarted
- name: Reload service httpd, in all cases
service:
name: httpd
state: reloaded
- name: Enable service httpd, and not touch the running state
service:
name: httpd
enabled: yes
Module 6: shell
Trong Ansible, chúng ta có shell module được sử dụng để chạy các lệnh thông qua shell (/bin/sh) trên các máy đích từ xa. Module này nhận các lệnh làm đầu vào cùng với một tập hợp các đối số.
Ví dụ:
- name: Execute the command in remote shell; stdout goes to the specified file on the remote.
shell: somescript.sh >> somelog.txt
- name: Change the working directory to somedir/ before executing the command.
shell: somescript.sh >> somelog.txt
args:
chdir: somedir/
Ansible-Roles và Ansible-galaxy
Ansible roles :
Roles một cách đơn giản luôn, bạn có thể hiểu đơn giản là mỗi một ứng dụng, tool,… đều sẽ tạo thành 1 role vậy tương ứng
Role Directory Structure
- Thư mục “tasks“: Thư mục này chứa các tệp tin YAML mà định nghĩa danh sách các tác vụ mà Ansible sẽ thực hiện trên các máy chủ mục tiêu. Các tác vụ này được liệt kê theo thứ tự và sẽ được thực thi một cách tuần tự.
- Thư mục “handlers“: Thư mục này chứa các tệp tin YAML định nghĩa các handlers, các tác vụ được kích hoạt khi có sự thay đổi hoặc thông báo từ các tác vụ khác. Handlers thường được sử dụng để khởi động lại dịch vụ hoặc thực hiện các hành động khác khi cấu hình thay đổi.
- Thư mục “library“: Thư mục này chứa các module mở rộng hoặc script tùy chỉnh có thể được sử dụng trong các tác vụ của role. Các module mở rộng có thể cung cấp chức năng bổ sung mà Ansible không hỗ trợ sẵn.
- Thư mục “files“: Thư mục này chứa các tệp tin tĩnh (không phải tệp tin template) mà cần được sao chép từ máy điều khiển Ansible đến máy chủ mục tiêu. Các tệp tin này có thể là các script, file cấu hình, hoặc tài nguyên khác cần thiết cho role.
- Thư mục “templates“: Thư mục này chứa các tệp tin template Jinja2. Các tệp tin template cho phép tạo ra các tệp tin động bằng cách kết hợp dữ liệu và biến từ Ansible với cú pháp Jinja2.
- Thư mục “vars“: Thư mục này chứa các tệp tin YAML chứa các biến cục bộ cho role. Các biến này có thể được sử dụng trong các tác vụ và templates trong role.
- Thư mục “defaults“: Thư mục này chứa các tệp tin YAML định nghĩa các giá trị mặc định cho role. Các giá trị mặc định có thể được ghi đè bởi biến trong inventory hoặc khi triển khai role.
- Tệp tin “meta“: Tệp tin này chứa thông tin mô tả về role và các phụ thuộc của nó. Nó có thể chứa các định nghĩa về các role cần được chạy trước hoặc sau role hiện tại, các phụ thuộc gói và phiên bản Ansible yêu cầu, tác giả, mô tả và các thông tin khác.
Role search path
Bạn phải khai báo việc set role chính xác trong ansible.cfg để ansible có thể hiểu được bạn viết role và thực thi nó.
Using Roles
Bạn có thể sử dụng role theo cách sau .
---
- hosts: dev
roles:
- nginx
Ansible Galaxy
Ansible Galaxy là một kho lưu trữ trực tuyến chứa các roles và các bộ sưu tập (collections) có thể được sử dụng bởi cộng đồng Ansible. Nó cung cấp một cách tiện lợi để chia sẻ và tái sử dụng các tài nguyên Ansible đã được phát triển trước đó.
Install Role
Bạn dùng command ansible-galaxy để download role từ Galaxy :ansible-galaxy install geerlingguy.nginx
Để xem danh sách các role được install thì bạn dùng :ansible-galaxy list
Create Role
Như hướng dẫn ở trên phần Role thì bạn có thể dùng command này :ansible-galaxy init __template__
Search for Roles
Để tìm kiếm 1 role thì bạn có thể sử dụng command sau :ansible-galaxy search apache --author geerlingguy
Trên đây là những modules thường xuyên được sử dụng nhất. Ngoài ra để đáp ứng được nhu cầu thì các bạn có thể xem thêm nhiều modules và cách sử dụng của chúng tại trang tài liệu của Ansible.
Ở bài tiếp theo mình sẽ ứng dụng ansible để cài đặt LAMP stack và triển khai wordpress. Các bạn nhớ chú ý đón xem nhé.
Tài liệu tham khảo :
https://docs.ansible.com/ansible/latest/index.html
[Book]
- Ansible Up And Running Book
- Ansible Playbook Essentials
- Learning Ansible – Use Ansible to Configure Systems Deploy Software and Orchestrate Advanced IT Tasks