โครงสร้าง playbook ที่ดีช่วยให้อ่านเข้าใจง่าย แก้ไขได้คล่อง และทีมใหม่สามารถ contribute ได้โดยไม่ต้องใช้เวลานาน ทุกส่วนใน playbook ตั้งแต่ plays, tasks, handlers, ไปจนถึง variables มีบทบาทและตำแหน่งที่ชัดเจน การเข้าใจโครงสร้างนี้เป็นพื้นฐานสำคัญก่อนเขียน playbook ที่ซับซ้อนขึ้น
บทความนี้อธิบายแต่ละส่วนของ playbook อย่างละเอียด พร้อมแนวทาง structuring ที่นำไปใช้ได้กับงานจริง
โครงสร้างภาพรวมของ Playbook
Playbook คือไฟล์ YAML ที่ประกอบด้วย play หนึ่งหรือหลาย play แต่ละ play กำหนดว่าจะรัน tasks ใดกับ hosts กลุ่มใด โครงสร้างระดับสูงมีดังนี้
---
# playbook.yml
- name: Play 1 — Configure web servers
hosts: webservers
become: true
vars:
http_port: 80
tasks:
# tasks ที่ต้องการรัน
handlers:
# handlers ที่รอถูก notify
- name: Play 2 — Configure database servers
hosts: dbservers
become: true
tasks:
# tasks สำหรับ database
Play-level Options
แต่ละ play มี options ระดับบนที่กำหนด context ของการรัน
- name: Configure application servers
hosts: appservers # กลุ่ม hosts เป้าหมาย
become: true # ใช้ sudo/privilege escalation
become_user: root # เปลี่ยน user เป็น root
gather_facts: true # เก็บข้อมูล host (default: true)
serial: 2 # รันทีละ 2 hosts (rolling update)
max_fail_percentage: 20 # หยุดถ้า hosts ล้มเหลวเกิน 20%
any_errors_fatal: false # หยุดทุก host ถ้า task fail
environment: # กำหนด environment variables
APP_ENV: production
LOG_LEVEL: info
Tasks — หน่วยงานพื้นฐาน
Task คือหน่วยงานที่เล็กที่สุด แต่ละ task ใช้ module หนึ่งตัวเพื่อทำงานเฉพาะอย่าง โครงสร้าง task มาตรฐานมีดังนี้
tasks:
- name: Install nginx web server # ชื่อ task ที่อ่านเข้าใจ
apt: # module ที่ใช้
name: nginx
state: present
update_cache: true
become: true # override privilege ระดับ task
when: ansible_os_family == "Debian" # เงื่อนไขการรัน
notify: restart nginx # notify handler
tags:
- packages # tag สำหรับ selective run
ignore_errors: false # ถ้า true จะไม่หยุดเมื่อ fail
retries: 3 # ลองใหม่ถ้าล้มเหลว
delay: 5 # รอ 5 วินาทีก่อนลองใหม่
Handlers — Task ที่รอถูกเรียก
Handlers เหมือน tasks ทั่วไปแต่รันเฉพาะเมื่อถูก notify และรันเพียงครั้งเดียวหลังจาก tasks ทั้งหมดใน play เสร็จ วางไว้ใน section handlers: ในระดับเดียวกับ tasks:
handlers:
- name: restart nginx
service:
name: nginx
state: restarted
listen: "web server restart" # alias สำหรับ notify หลาย handler พร้อมกัน
- name: reload nginx config
service:
name: nginx
state: reloaded
listen: "web server restart" # handler 2 ตัวนี้จะรันเมื่อ notify "web server restart"
Variables ในระดับต่าง ๆ
สามารถกำหนด variables ได้ในหลายระดับภายใน playbook ลำดับความสำคัญจากต่ำไปสูง ได้แก่ play vars → vars_files → task vars → set_fact → extra_vars
- name: Variable examples
hosts: all
vars:
# inline vars (ต่ำสุดในระดับ play)
app_port: 8080
debug_mode: false
vars_files:
- vars/common.yml # โหลดจากไฟล์ภายนอก
tasks:
- name: Set computed variable
set_fact:
full_app_url: "http://{{ inventory_hostname }}:{{ app_port }}"
- name: Override for this task only
debug:
msg: "Running on port {{ app_port }}"
vars:
app_port: 9090 # override เฉพาะ task นี้
Tags — รัน Subset ของ Tasks
Tags ช่วยให้รัน tasks บางส่วนได้โดยไม่ต้องรันทั้ง playbook มีประโยชน์มากในระหว่าง development หรือเมื่อต้องการ apply เฉพาะบางส่วน
tasks:
- name: Install packages
apt:
name: "{{ item }}"
state: present
loop: [nginx, git, curl]
tags: [packages, setup]
- name: Deploy config
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
tags: [config, deploy]
- name: Start services
service:
name: nginx
state: started
tags: [services]
# รันเฉพาะ task ที่มี tag "config"
ansible-playbook site.yml --tags config
# ข้าม task ที่มี tag "packages"
ansible-playbook site.yml --skip-tags packages
Include และ Import — แบ่ง Playbook เป็นไฟล์ย่อย
เมื่อ playbook ยาวขึ้น ควรแบ่งออกเป็นไฟล์ย่อย ทำให้แต่ละไฟล์ทำหน้าที่เดียวและนำกลับมาใช้ซ้ำได้
# site.yml — playbook หลัก
- name: Full site deployment
hosts: all
tasks:
- import_tasks: tasks/install.yml # โหลดก่อนรัน (static)
- include_tasks: tasks/configure.yml # โหลดระหว่างรัน (dynamic)
when: configure_required | bool
# tasks/install.yml
- name: Install nginx
apt:
name: nginx
state: present
- name: Install certbot
apt:
name: certbot
state: present
สรุป
โครงสร้าง playbook ที่ดีประกอบด้วย plays ที่กำหนด scope ชัดเจน, tasks ที่มีชื่ออ่านเข้าใจ, handlers ที่จัดการ service restarts, variables ที่จัดระดับถูกต้อง และ tags ที่ทำให้รัน selective ได้ การแบ่ง tasks ออกเป็นไฟล์ย่อยด้วย include/import เพิ่มความ maintainability ในโปรเจกต์ขนาดใหญ่

