บทความนี้อธิบาย Handlers, Variables ในระดับ play, Conditionals, และ Loops พร้อมตัวอย่างที่นำไปใช้ได้ทันที
Playbook เบื้องต้นที่รัน task ตามลำดับใช้งานได้ดี แต่ระบบจริงต้องการความยืดหยุ่นมากกว่านั้น บางครั้งต้องรีสตาร์ต service เฉพาะเมื่อ config เปลี่ยน บางครั้งต้องรัน task เฉพาะบาง server หรือต้องสร้างไฟล์หลายชุดจากรายการข้อมูล features เหล่านี้คือหัวใจของ playbook ที่ทำงานจริงในสภาพแวดล้อม production
Handlers — รัน Task เฉพาะเมื่อมีการเปลี่ยนแปลง
Handler คือ task พิเศษที่จะรันก็ต่อเมื่อถูก notify เท่านั้น ใช้สำหรับ action ที่ต้องการเฉพาะเมื่อ config หรือไฟล์เปลี่ยนแปลง เช่น restart service หรือ reload config โดย handler จะรันเพียงครั้งเดียวต่อ play ไม่ว่าจะถูก notify กี่ครั้ง
- name: Configure nginx
hosts: webservers
tasks:
- name: Copy nginx config
copy:
src: nginx.conf
dest: /etc/nginx/nginx.conf
notify: restart nginx
- name: Enable nginx site
file:
src: /etc/nginx/sites-available/mysite
dest: /etc/nginx/sites-enabled/mysite
state: link
notify: reload nginx
handlers:
- name: restart nginx
service:
name: nginx
state: restarted
- name: reload nginx
service:
name: nginx
state: reloaded
ถ้า config file ไม่เปลี่ยนแปลง (task status = ok แทน changed) handler จะไม่รัน ทำให้ไม่มีการ restart service โดยไม่จำเป็น
Variables — กำหนดค่าระดับ Play
นอกจาก host_vars และ group_vars แล้ว ยังกำหนด variable ในระดับ play ได้โดยตรงด้วย vars: หรือโหลดจากไฟล์ด้วย vars_files:
- name: Deploy application
hosts: webservers
vars:
app_name: myapp
app_port: 8080
deploy_dir: /opt/apps/myapp
vars_files:
- vars/common.yml
- vars/{{ env }}.yml # โหลดตาม environment
tasks:
- name: Create app directory
file:
path: "{{ deploy_dir }}"
state: directory
- name: Configure app
template:
src: app.conf.j2
dest: "{{ deploy_dir }}/config.conf"
Conditionals — รัน Task เฉพาะเมื่อตรงเงื่อนไข
when: ใช้กรอง task ให้รันเฉพาะ host หรือสถานการณ์ที่ตรงเงื่อนไข ช่วยให้ playbook เดียวรองรับได้หลาย OS หรือหลาย environment
- name: Install packages
hosts: all
tasks:
# รันเฉพาะบน Ubuntu/Debian
- name: Install nginx (apt)
apt:
name: nginx
state: present
when: ansible_os_family == "Debian"
# รันเฉพาะบน RHEL/CentOS
- name: Install nginx (yum)
yum:
name: nginx
state: present
when: ansible_os_family == "RedHat"
# ตรวจสอบ variable ก่อนรัน
- name: Enable SSL
include_tasks: ssl.yml
when: ssl_enabled | bool
# ตรวจสอบหลายเงื่อนไข
- name: Run in production only
command: /opt/scripts/backup.sh
when:
- env == "production"
- backup_enabled | default(true)
Loops — ทำซ้ำ Task กับหลาย Items
loop: ใช้เมื่อต้องการรัน task เดิมหลายครั้งกับข้อมูลต่างกัน แทนการเขียน task ซ้ำหลายบล็อก
- name: Setup users and packages
hosts: all
tasks:
# สร้าง user หลายคนจาก list
- name: Create system users
user:
name: "{{ item }}"
state: present
shell: /bin/bash
loop:
- deploy
- monitor
- backup
# ติดตั้ง packages หลายตัว
- name: Install required packages
apt:
name: "{{ item }}"
state: present
loop:
- git
- curl
- vim
- htop
# loop กับ dict items
- name: Create directories with permissions
file:
path: "{{ item.path }}"
mode: "{{ item.mode }}"
state: directory
loop:
- { path: /opt/app, mode: "0755" }
- { path: /var/log/app, mode: "0750" }
- { path: /etc/app, mode: "0640" }
ใช้ register เก็บผลลัพธ์จาก Task
register: เก็บ output จาก task ไว้ใน variable เพื่อใช้ใน task ถัดไป มีประโยชน์มากเมื่อต้องตัดสินใจตามผลลัพธ์ของ command
- name: Check and conditionally run
hosts: all
tasks:
- name: Check if app is running
command: systemctl is-active myapp
register: app_status
ignore_errors: true
- name: Start app if not running
service:
name: myapp
state: started
when: app_status.rc != 0
- name: Show status
debug:
msg: "App status: {{ app_status.stdout }}"
รวม Features ใน Playbook จริง
ตัวอย่าง playbook ที่ใช้ทุก feature ร่วมกัน เพื่อ deploy และ configure web server
- name: Deploy web application
hosts: webservers
vars:
app_version: "1.2.0"
app_port: 8080
handlers:
- name: restart app
service:
name: myapp
state: restarted
tasks:
- name: Install dependencies
apt:
name: "{{ item }}"
state: present
loop:
- python3
- python3-pip
- name: Deploy application config
template:
src: app.conf.j2
dest: /etc/myapp/config.conf
notify: restart app
when: env == "production"
- name: Check deployment
uri:
url: "http://localhost:{{ app_port }}/health"
status_code: 200
register: health_check
retries: 3
delay: 10
สรุป
Handlers ช่วยลดการ restart service ที่ไม่จำเป็น Conditionals ทำให้ playbook รองรับได้หลาย OS และ environment Loops ลดการเขียน task ซ้ำ และ register เปิดให้ logic ใน playbook ตัดสินใจตามผลลัพธ์จริง ความเข้าใจ feature เหล่านี้เป็นรากฐานของ playbook ที่ใช้ได้จริงในงาน DevOps

