Ansible service module ใช้จัดการ system daemon บน Linux ผ่าน init system ที่หลากหลาย ไม่ว่าจะเป็น systemd, SysV init, หรือ Upstart โดยไม่ต้องรู้ว่าเซิร์ฟเวอร์ใช้ init system อะไร module จะจัดการให้อัตโนมัติ ทำให้ Playbook ทำงานได้ข้ามหลาย distro
บทความนี้ครอบคลุม syntax พื้นฐาน, state ทั้งหมดที่รองรับ, การตั้งค่า enabled/disabled สำหรับ auto-start, ความแตกต่างระหว่าง reload กับ restart, การใช้ร่วมกับ loop และ handler และ pattern สำหรับ deploy พร้อม enable daemon แบบ idempotent
service Module พื้นฐาน
service module มี parameters หลักสองตัวที่ต้องรู้จัก คือ name (ชื่อ daemon) และ state (สถานะที่ต้องการ) ส่วน enabled ใช้ควบคุม auto-start เมื่อ boot
---
- name: Basic service module usage
hosts: all
become: true
tasks:
- name: Start nginx
service:
name: nginx
state: started
- name: Stop mysql
service:
name: mysql
state: stopped
- name: Restart redis
service:
name: redis
state: restarted
- name: Reload nginx config (ไม่ drop connections)
service:
name: nginx
state: reloaded
module จะตรวจสอบสถานะปัจจุบันของ daemon ก่อน ถ้า nginx กำลัง started อยู่แล้วและสั่ง state: started จะไม่ทำอะไร — ทำให้ Playbook เป็น idempotent โดยอัตโนมัติ
state ที่รองรับทั้งหมด
service module รองรับ state 4 แบบ แต่ละแบบมีพฤติกรรมต่างกัน ควรเลือกให้ตรงกับสิ่งที่ต้องการทำ
---
- name: service states demo
hosts: all
become: true
tasks:
# started: เริ่ม daemon ถ้ายังไม่ได้ run (idempotent)
- name: Ensure nginx is started
service:
name: nginx
state: started
# stopped: หยุด daemon ถ้ากำลัง run อยู่ (idempotent)
- name: Ensure nginx is stopped
service:
name: nginx
state: stopped
# restarted: หยุดแล้วเริ่มใหม่เสมอ (ไม่ idempotent — ทำทุกครั้ง)
- name: Restart nginx unconditionally
service:
name: nginx
state: restarted
# reloaded: สั่ง reload config โดยไม่ kill process (graceful)
# ถ้า daemon ไม่รองรับ reload จะ fallback เป็น restart อัตโนมัติ
- name: Reload nginx config
service:
name: nginx
state: reloaded
enabled — ตั้งค่า Auto-start เมื่อ Boot
enabled ควบคุมว่า daemon จะ start อัตโนมัติเมื่อ boot หรือไม่ สามารถใช้ร่วมกับ state หรือใช้แยกกันได้ ในหลายกรณีควรตั้งทั้งคู่พร้อมกัน
---
- name: Managing enabled state
hosts: all
become: true
tasks:
# เริ่ม daemon ทันทีและตั้งให้ auto-start เมื่อ boot
- name: Start and enable nginx
service:
name: nginx
state: started
enabled: true
# หยุด daemon และปิด auto-start
- name: Stop and disable nginx
service:
name: nginx
state: stopped
enabled: false
# เปิด auto-start โดยไม่เปลี่ยน running state ปัจจุบัน
- name: Enable nginx on boot (without changing current state)
service:
name: nginx
enabled: true
# pattern มาตรฐานสำหรับ install + enable daemon
- name: Install and enable sshd
service:
name: sshd
state: started
enabled: true
ข้อควรระวัง: enabled: true เพียงอย่างเดียวไม่ได้ start daemon ทันที — ต้องใส่ state: started ด้วยถ้าต้องการให้ทำงานทันที
reload vs restart — ใช้อย่างไรให้ถูก
ความแตกต่างระหว่าง reload และ restart มีผลกระทบต่อ availability ของระบบ ควรเลือกให้เหมาะกับสถานการณ์
---
- name: reload vs restart comparison
hosts: webservers
become: true
tasks:
# reload: ส่ง SIGHUP — process เดิมยังอยู่, โหลด config ใหม่
# เหมาะสำหรับ: nginx, apache, haproxy, postfix
# ข้อดี: ไม่ drop connections ที่กำลังใช้งานอยู่
- name: Reload nginx after config change (graceful)
service:
name: nginx
state: reloaded
# restart: หยุดแล้วเริ่มใหม่ — มี downtime สั้น ๆ
# เหมาะสำหรับ: เปลี่ยน port, เปลี่ยน binary, daemon ที่ไม่รองรับ reload
- name: Restart mysql after major config change
service:
name: mysql
state: restarted
# ตรวจ reload support ก่อนสั่ง
- name: Check if daemon supports reload
command: systemctl show nginx --property=ExecReload
register: reload_check
changed_when: false
- name: Reload if supported, else restart
service:
name: nginx
state: "{{ 'reloaded' if reload_check.stdout != 'ExecReload=' else 'restarted' }}"
ใช้ loop — จัดการหลาย Daemon พร้อมกัน
เมื่อต้องจัดการหลาย daemon พร้อมกัน ใช้ loop แทนการเขียน task ซ้ำหลาย task ทำให้ Playbook สั้นและดูแลง่าย
---
- name: Manage multiple daemons with loop
hosts: all
become: true
tasks:
# start + enable หลาย daemon
- name: Ensure web stack is running
service:
name: "{{ item }}"
state: started
enabled: true
loop:
- nginx
- mysql
- redis
- php8.1-fpm
# หยุดและปิด daemon ที่ไม่ต้องการ
- name: Disable unnecessary daemons
service:
name: "{{ item }}"
state: stopped
enabled: false
loop:
- cups
- bluetooth
- avahi-daemon
# ใช้ loop กับ dict เพื่อระบุ state ต่างกันแต่ละ daemon
- name: Set different states per daemon
service:
name: "{{ item.name }}"
state: "{{ item.state }}"
enabled: "{{ item.enabled }}"
loop:
- { name: nginx, state: started, enabled: true }
- { name: mysql, state: started, enabled: true }
- { name: memcached, state: stopped, enabled: false }
ใช้ร่วมกับ Handler — Pattern มาตรฐาน
การใช้ service module ร่วมกับ Handler เป็น pattern ที่พบบ่อยที่สุดใน Ansible โดย Handler จะ restart/reload daemon เฉพาะเมื่อ config มีการเปลี่ยนแปลงจริง ๆ เท่านั้น
---
- name: service with handler pattern
hosts: webservers
become: true
handlers:
- name: Reload nginx
service:
name: nginx
state: reloaded
- name: Restart mysql
service:
name: mysql
state: restarted
tasks:
- name: Deploy nginx config
copy:
src: files/nginx.conf
dest: /etc/nginx/nginx.conf
owner: root
group: root
mode: '0644'
notify: Reload nginx # trigger handler เฉพาะเมื่อ config เปลี่ยน
- name: Deploy nginx vhost
template:
src: templates/vhost.conf.j2
dest: /etc/nginx/conf.d/myapp.conf
notify: Reload nginx # หลาย task notify handler เดียวกัน — reload แค่ครั้งเดียว
- name: Deploy mysql config
copy:
src: files/my.cnf
dest: /etc/mysql/my.cnf
notify: Restart mysql
ข้อดีของ Handler: ถ้า task ทั้งหมดไม่มีการเปลี่ยนแปลง (เช่น config เหมือนเดิม) Handler จะไม่ถูก trigger — ทำให้ Playbook เป็น idempotent อย่างแท้จริงและไม่ restart daemon โดยไม่จำเป็น
register — ตรวจสอบสถานะก่อนดำเนินการ
ใช้ register ร่วมกับ command เพื่อดึงสถานะ daemon มาตรวจสอบหรือตัดสินใจใน task ถัดไป ป้องกันการสั่ง reload daemon ที่ยังไม่ได้ start
---
- name: Check status before action
hosts: all
become: true
tasks:
# ตรวจสถานะก่อนดำเนินการ
- name: Check nginx status
command: systemctl is-active nginx
register: nginx_status
changed_when: false
failed_when: false
- name: Print nginx status
debug:
msg: "nginx is {{ nginx_status.stdout }}"
# ดำเนินการเฉพาะเมื่อ daemon active
- name: Reload nginx only if running
service:
name: nginx
state: reloaded
when: nginx_status.stdout == 'active'
# ตรวจหลาย daemon พร้อมกัน
- name: Check all required daemons
command: systemctl is-active "{{ item }}"
register: svc_status
changed_when: false
failed_when: false
loop:
- nginx
- mysql
- redis
- name: Report stopped daemons
debug:
msg: "Daemon {{ item.item }} is NOT running!"
loop: "{{ svc_status.results }}"
when: item.stdout != 'active'
Pattern: Deploy และ Enable
ตัวอย่าง Playbook ครบวงจร ติดตั้ง package, deploy config, เปิด daemon และตรวจสอบว่า endpoint พร้อมรับ request ก่อนจบ
---
- name: Deploy and enable Nginx
hosts: webservers
become: true
handlers:
- name: Reload nginx
service:
name: nginx
state: reloaded
tasks:
- name: Install nginx
apt:
name: nginx
state: present
update_cache: true
- name: Deploy nginx configuration
template:
src: templates/nginx.conf.j2
dest: /etc/nginx/nginx.conf
owner: root
group: root
mode: '0644'
validate: 'nginx -t -c %s' # ตรวจ syntax ก่อน deploy
notify: Reload nginx
- name: Deploy virtual host
template:
src: templates/vhost.conf.j2
dest: /etc/nginx/conf.d/{{ app_name }}.conf
notify: Reload nginx
- name: Start and enable nginx
service:
name: nginx
state: started
enabled: true
- name: Verify nginx is responding
uri:
url: "http://{{ inventory_hostname }}"
status_code: 200
register: health_check
retries: 3
delay: 5
until: health_check.status == 200
สรุป
service module เป็นเครื่องมือหลักสำหรับจัดการ system daemon ใน Ansible รองรับ state ครบทั้ง started, stopped, restarted, reloaded และ parameter enabled สำหรับ auto-start ควรใช้ reload แทน restart เมื่อทำได้ เพื่อไม่ให้กระทบ connections ที่กำลังใช้งาน
Pattern ที่ควรจำ: ใช้ state: started + enabled: true คู่กันเสมอเมื่อ deploy daemon ใหม่, ใช้ Handler สำหรับ reload/restart เพื่อให้ทำงานเฉพาะเมื่อ config จริง ๆ เปลี่ยน และใช้ loop เมื่อต้องจัดการหลาย daemon แทนการเขียน task ซ้ำ ทั้งหมดนี้ทำให้ Playbook เป็น idempotent และดูแลง่ายในระยะยาว

