Ansible block ใช้จัดกลุ่ม tasks หลาย ๆ task เข้าด้วยกัน และ apply directive ร่วมกันทั้งกลุ่มได้ในครั้งเดียว — เช่น กำหนด when, become, tags, หรือ notify ระดับ block ให้ทุก task ภายในได้รับผลพร้อมกัน แทนที่จะเขียนซ้ำในแต่ละ task
บทความนี้ครอบคลุมการใช้ block เพื่อจัดกลุ่ม tasks, การ apply when ระดับ block, การ apply become เฉพาะกลุ่ม, การใช้ tags กับ block, การ notify handler จาก block, การซ้อน blocks และ pattern สำหรับ multi-stage deployment
Block พื้นฐาน — จัดกลุ่ม Tasks
block เป็น keyword ระดับเดียวกับ name ใน task — tasks ทั้งหมดที่อยู่ภายใน block จะทำงานตามลำดับเหมือน tasks ปกติ แต่ได้รับประโยชน์จาก directive ที่กำหนดไว้ในระดับ block
---
- name: Block basic grouping
hosts: all
tasks:
- name: Install and configure Nginx
block:
- name: Install Nginx
apt:
name: nginx
state: present
update_cache: true
- name: Create web root
file:
path: /var/www/mysite
state: directory
owner: www-data
mode: '0755'
- name: Deploy index page
copy:
content: "Hello from Ansible"
dest: /var/www/mysite/index.html
owner: www-data
- name: Start and enable Nginx
service:
name: nginx
state: started
enabled: true
Block กับ when — Apply เงื่อนไขทั้งกลุ่ม
แทนที่จะเพิ่ม when ในทุก task สามารถกำหนด when ที่ระดับ block เพียงครั้งเดียว — ถ้าเงื่อนไขเป็น false ทุก task ใน block จะถูก skip พร้อมกัน
---
- name: Block with when condition
hosts: all
become: true
vars:
install_monitoring: true
env: production
tasks:
# ทุก task ใน block นี้จะรันเฉพาะเมื่อ install_monitoring เป็น true
- name: Install monitoring stack
block:
- name: Install Prometheus
apt:
name: prometheus
state: present
- name: Install Grafana
apt:
name: grafana
state: present
- name: Configure Prometheus
template:
src: prometheus.yml.j2
dest: /etc/prometheus/prometheus.yml
- name: Start services
service:
name: "{{ item }}"
state: started
enabled: true
loop:
- prometheus
- grafana-server
when: install_monitoring | bool # apply เงื่อนไขนี้กับทุก task ใน block
# block สำหรับ production เท่านั้น
- name: Production-only hardening
block:
- name: Disable root SSH
lineinfile:
path: /etc/ssh/sshd_config
regexp: '^PermitRootLogin'
line: 'PermitRootLogin no'
- name: Set password policy
command: /opt/scripts/set-password-policy.sh
- name: Enable audit logging
service:
name: auditd
state: started
enabled: true
when: env == "production"
Block กับ become — เปลี่ยน Privilege เฉพาะกลุ่ม
become ที่ระดับ block ช่วยจำกัดการใช้ root privilege เฉพาะ tasks ที่จำเป็นจริง ๆ โดยไม่ต้องเปิด become: true ทั้ง play — เป็น principle of least privilege ที่ดี
---
- name: Block with become privilege separation
hosts: all
# ไม่มี become ระดับ play
tasks:
# tasks ส่วนนี้รันในฐานะ user ปกติ (ไม่ต้องการ root)
- name: Read application config
slurp:
src: /home/appuser/app.conf
register: app_config
- name: Check application health
uri:
url: http://localhost:8080/health
register: health
# tasks ที่ต้องการ root — ใช้ become ระดับ block
- name: System-level configuration
block:
- name: Install system packages
apt:
name:
- libssl-dev
- build-essential
state: present
- name: Configure kernel parameters
sysctl:
name: net.core.somaxconn
value: '1024'
state: present
- name: Set open file limits
pam_limits:
domain: appuser
limit_type: '-'
limit_item: nofile
value: '65536'
become: true # apply become เฉพาะ block นี้
become_user: root
# tasks หลัง block กลับไปเป็น user ปกติ
- name: Verify configuration
command: /home/appuser/verify.sh
changed_when: false
Block กับ tags — Tag ทั้งกลุ่มพร้อมกัน
กำหนด tags ที่ระดับ block เพื่อให้ทุก task ใน block ได้รับ tag นั้น — เมื่อรัน ansible-playbook --tags install จะรันเฉพาะ tasks ที่อยู่ใน block ที่ tag เป็น install ทั้งหมด
---
- name: Block with tags for selective execution
hosts: all
become: true
tasks:
# รัน: ansible-playbook site.yml --tags install
- name: Installation tasks
block:
- name: Install application
apt:
name: myapp
state: present
- name: Install dependencies
apt:
name:
- libmysqlclient-dev
- redis-tools
state: present
tags: [install]
# รัน: ansible-playbook site.yml --tags configure
- name: Configuration tasks
block:
- name: Deploy app config
template:
src: app.conf.j2
dest: /etc/myapp/app.conf
- name: Set environment variables
lineinfile:
path: /etc/environment
line: "APP_ENV={{ env }}"
- name: Configure log rotation
template:
src: logrotate.conf.j2
dest: /etc/logrotate.d/myapp
tags: [configure]
# รัน: ansible-playbook site.yml --tags restart
- name: Service restart tasks
block:
- name: Restart application
service:
name: myapp
state: restarted
- name: Verify application started
uri:
url: http://localhost:8080/health
status_code: 200
retries: 3
delay: 5
tags: [restart]
Block กับ notify — Trigger Handler จาก Block
notify ที่ระดับ block จะ trigger handler เมื่อ task ใด task หนึ่งใน block เกิด changed — ไม่ต้องเพิ่ม notify ในทุก task ที่ควร trigger handler เดียวกัน
---
- name: Block with notify handler
hosts: all
become: true
tasks:
# เมื่อมี task ใดใน block นี้ "changed" → trigger Reload Nginx
- name: Nginx configuration changes
block:
- name: Deploy main nginx config
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
- name: Deploy virtual host configs
template:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
loop:
- { src: site1.conf.j2, dest: /etc/nginx/conf.d/site1.conf }
- { src: site2.conf.j2, dest: /etc/nginx/conf.d/site2.conf }
- name: Deploy SSL certificates
copy:
src: "certs/{{ item }}"
dest: "/etc/nginx/certs/{{ item }}"
loop:
- mysite.crt
- mysite.key
notify: Reload Nginx # trigger handler ถ้า config หรือ cert เปลี่ยน
# block สำหรับ application config
- name: Application configuration changes
block:
- name: Deploy application config
template:
src: app.conf.j2
dest: /etc/myapp/app.conf
- name: Deploy database config
template:
src: db.conf.j2
dest: /etc/myapp/db.conf
notify: Restart Application # trigger handler เมื่อ app config เปลี่ยน
handlers:
- name: Reload Nginx
service:
name: nginx
state: reloaded
- name: Restart Application
service:
name: myapp
state: restarted
Nested Blocks — Block ซ้อน Block
สามารถซ้อน block ภายใน block ได้ เพื่อแบ่งกลุ่มตาม stage หรือ responsibility — directive ของ outer block ไม่ถ่ายทอดลง inner block อัตโนมัติ แต่สามารถกำหนด directive แยกในแต่ละระดับได้
---
- name: Nested blocks example
hosts: all
become: true
vars:
deploy_version: "2.5.0"
env: production
tasks:
- name: Full deployment process
block:
# Inner block 1 — prerequisites (เฉพาะ production)
- name: Pre-deployment checks
block:
- name: Check disk space
command: df -h /opt
changed_when: false
- name: Verify database connectivity
command: /opt/myapp/bin/check-db.sh
changed_when: false
- name: Check external service availability
uri:
url: "{{ external_api_url }}/health"
status_code: 200
when: env == "production"
# Inner block 2 — deployment (ทุก env)
- name: Deploy application
block:
- name: Pull new version
git:
repo: "{{ app_repo }}"
dest: /opt/myapp/current
version: "{{ deploy_version }}"
- name: Install dependencies
command: /opt/myapp/current/bin/install-deps.sh
args:
chdir: /opt/myapp/current
- name: Run migrations
command: /opt/myapp/current/bin/migrate.sh
register: migration_result
changed_when: '"Applied" in migration_result.stdout'
# Inner block 3 — service restart
- name: Restart services
block:
- name: Restart application
service:
name: myapp
state: restarted
- name: Verify health
uri:
url: http://localhost:8080/health
status_code: 200
retries: 5
delay: 3
notify: Send Deployment Notification
rescue:
- name: Handle deployment failure
debug:
msg: "Deployment failed at step: {{ ansible_failed_task.name }}"
handlers:
- name: Send Deployment Notification
debug:
msg: "Deployment of {{ deploy_version }} completed successfully"
Pattern: Multi-Stage Deployment ด้วย Blocks
ตัวอย่าง Playbook deploy application แบบ multi-stage โดยใช้ blocks แยก stage ออกจากกัน — แต่ละ stage มี when, become, tags เป็นของตัวเอง และ notify handler ที่เหมาะสม
---
- name: Multi-stage deployment with blocks
hosts: appservers
vars:
app_name: myapp
deploy_version: "{{ target_version | default('latest') }}"
env: "{{ deployment_env | default('staging') }}"
handlers:
- name: Reload Nginx
service:
name: nginx
state: reloaded
become: true
- name: Restart Application
service:
name: "{{ app_name }}"
state: restarted
become: true
tasks:
# Stage 1: System preparation
- name: Stage 1 - System preparation
block:
- name: Update package cache
apt:
update_cache: true
cache_valid_time: 3600
- name: Ensure required packages
apt:
name:
- curl
- git
- unzip
state: present
become: true
tags: [prepare, always]
# Stage 2: Deploy application code
- name: Stage 2 - Deploy application
block:
- name: Create app directories
file:
path: "{{ item }}"
state: directory
owner: "{{ app_name }}"
mode: '0755'
loop:
- "/opt/{{ app_name }}/releases"
- "/opt/{{ app_name }}/shared/config"
- "/opt/{{ app_name }}/shared/logs"
- name: Deploy release
git:
repo: "{{ app_repo }}"
dest: "/opt/{{ app_name }}/releases/{{ deploy_version }}"
version: "{{ deploy_version }}"
- name: Link shared directories
file:
src: "/opt/{{ app_name }}/shared/{{ item }}"
dest: "/opt/{{ app_name }}/releases/{{ deploy_version }}/{{ item }}"
state: link
loop:
- config
- logs
- name: Update current symlink
file:
src: "/opt/{{ app_name }}/releases/{{ deploy_version }}"
dest: "/opt/{{ app_name }}/current"
state: link
become: true
become_user: "{{ app_name }}"
tags: [deploy]
notify: Restart Application
# Stage 3: Configure web server
- name: Stage 3 - Web server configuration
block:
- name: Deploy Nginx virtual host
template:
src: "nginx-{{ app_name }}.conf.j2"
dest: "/etc/nginx/conf.d/{{ app_name }}.conf"
- name: Validate Nginx config
command: nginx -t
changed_when: false
become: true
tags: [nginx, configure]
notify: Reload Nginx
when: configure_nginx | default(true) | bool
# Stage 4: Post-deploy verification
- name: Stage 4 - Verify deployment
block:
- name: Wait for application to be ready
uri:
url: "http://localhost:8080/health"
status_code: 200
retries: 10
delay: 5
- name: Run smoke tests
command: "/opt/{{ app_name }}/current/bin/smoke-test.sh"
changed_when: false
- name: Log successful deployment
lineinfile:
path: "/var/log/{{ app_name }}-deployments.log"
line: "{{ ansible_date_time.iso8601 }} version={{ deploy_version }} env={{ env }} status=success"
create: true
become: true
tags: [verify]
สรุป
block ช่วยจัดกลุ่ม tasks ที่เกี่ยวข้องกันเข้าไว้ด้วยกัน ทำให้ Playbook อ่านง่ายและลดความซ้ำซ้อน — directive ที่ apply ที่ระดับ block ได้แก่ when, become, tags, notify, ignore_errors, และ rescue/always สำหรับ error handling
Pattern ที่ควรจำ: ใช้ when ระดับ block แทนการเขียนซ้ำในทุก task, ใช้ become ระดับ block เพื่อจำกัด privilege เฉพาะส่วนที่จำเป็น, ใช้ tags ระดับ block เพื่อเปิด/ปิด stage การทำงาน, ใช้ notify ระดับ block เพื่อ trigger handler เมื่อมีการเปลี่ยนแปลงในกลุ่ม และใช้ nested blocks เพื่อแบ่ง deployment ออกเป็น stages ที่ชัดเจน

