Ansible file module ใช้จัดการ filesystem objects บน remote server ครอบคลุมการสร้างและลบไฟล์/directory, กำหนด permissions, ownership และ symbolic links โดยไม่ต้องใช้ command รัน chmod, chown หรือ mkdir ตรง ๆ ซึ่งมักไม่ idempotent
บทความนี้ครอบคลุม state ทั้งหมดที่รองรับ, การกำหนด owner, group และ mode, การสร้าง directory tree, symlink management, การใช้ร่วมกับ loop และ pattern สำหรับ prepare filesystem ก่อน deploy application
file Module พื้นฐาน — State ที่รองรับ
file module ควบคุมสถานะของ filesystem object ผ่าน parameter state ซึ่งรองรับหลายค่าแต่ละค่ามีพฤติกรรมต่างกัน
---
- name: file module state examples
hosts: all
become: true
tasks:
# touch: สร้างไฟล์ว่างถ้าไม่มี, อัพเดต timestamp ถ้ามีอยู่แล้ว
- name: Create empty file
file:
path: /var/log/myapp/app.log
state: touch
owner: appuser
group: appgroup
mode: '0644'
# directory: สร้าง directory (ถ้ามีอยู่แล้วจะไม่ทำอะไร)
- name: Create directory
file:
path: /opt/myapp/data
state: directory
owner: appuser
group: appgroup
mode: '0755'
# absent: ลบไฟล์หรือ directory (idempotent)
- name: Remove file or directory
file:
path: /tmp/old-config.bak
state: absent
# link: สร้าง symbolic link
- name: Create symbolic link
file:
src: /opt/myapp/current
dest: /usr/local/bin/myapp
state: link
# hard: สร้าง hard link
- name: Create hard link
file:
src: /etc/ssl/certs/myapp.crt
dest: /opt/myapp/ssl/myapp.crt
state: hard
Owner, Group และ Mode
กำหนด ownership และ permissions ได้ทั้งตอนสร้างและตอนอัพเดต object ที่มีอยู่แล้ว module จะ idempotent — ถ้า permissions ตรงแล้วจะไม่เปลี่ยนอะไร
---
- name: Permissions and ownership management
hosts: all
become: true
tasks:
# กำหนด owner, group, mode พร้อมกัน
- name: Set file permissions
file:
path: /etc/myapp/app.conf
owner: root
group: appgroup
mode: '0640' # owner=rw, group=r, others=none
state: file # state: file ตรวจว่าเป็นไฟล์และแก้ไข attributes
# ใช้ symbolic mode (u+x, g-w, o=r)
- name: Make script executable
file:
path: /opt/myapp/bin/start.sh
mode: 'u+x,g+x'
state: file
# กำหนดเฉพาะ mode (ไม่เปลี่ยน owner)
- name: Restrict config file
file:
path: /etc/myapp/secret.conf
mode: '0600' # owner only
state: file
# setuid/setgid bit
- name: Set SUID bit on binary
file:
path: /usr/local/bin/myapp
mode: '4755' # SUID + rwxr-xr-x
state: file
# สร้าง directory พร้อมกำหนด permissions
- name: Create log directory
file:
path: /var/log/myapp
state: directory
owner: appuser
group: adm
mode: '0750'
สร้าง Directory Tree ลึกหลายระดับ
สำหรับ path ที่ลึกหลายระดับ ใช้ recurse: true เพื่อกำหนด permissions กับทุก object ใน tree หรือใช้ loop สร้างหลาย directory พร้อมกัน
---
- name: Directory tree management
hosts: all
become: true
tasks:
# สร้าง directory path ลึกหลายชั้น (mkdir -p equivalent)
- name: Create deep directory path
file:
path: /opt/myapp/data/uploads/images
state: directory
owner: www-data
group: www-data
mode: '0755'
# recurse: กำหนด permissions กับทุกไฟล์/directory ใน tree
- name: Fix permissions recursively
file:
path: /opt/myapp
state: directory
owner: appuser
group: appgroup
recurse: true
# สร้างหลาย directory พร้อมกันด้วย loop
- name: Create application directories
file:
path: "{{ item }}"
state: directory
owner: appuser
group: appgroup
mode: '0755'
loop:
- /opt/myapp/bin
- /opt/myapp/conf
- /opt/myapp/data
- /opt/myapp/logs
- /opt/myapp/tmp
Symbolic Links
Symlink ใน Ansible ทำงาน idempotent — ถ้า link ชี้ไปที่ถูกต้องแล้วจะไม่เปลี่ยนอะไร ใช้ force: true เพื่อแทนที่ link ที่มีอยู่แล้ว
---
- name: Symlink management
hosts: all
become: true
tasks:
# สร้าง version symlink สำหรับ blue-green deploy
- name: Create current version symlink
file:
src: /opt/myapp/releases/v2.5.0
dest: /opt/myapp/current
state: link
force: true # แทนที่ link เดิมถ้ามีอยู่แล้ว
# symlink สำหรับ config
- name: Link config to expected path
file:
src: /etc/myapp/nginx-site.conf
dest: /etc/nginx/sites-enabled/myapp.conf
state: link
# ลบ symlink
- name: Remove symlink
file:
path: /etc/nginx/sites-enabled/old-site.conf
state: absent
# ตรวจสอบว่า symlink ถูก resolve ไปที่ถูกต้อง
- name: Check symlink target
stat:
path: /opt/myapp/current
register: symlink_info
- name: Show symlink target
debug:
msg: "current → {{ symlink_info.stat.lnk_target }}"
when: symlink_info.stat.islnk
ลบไฟล์และ Directory
state: absent ลบ object ไม่ว่าจะเป็นไฟล์, directory (รวม subdirectory ทั้งหมด), หรือ symlink — idempotent ถ้าไม่มีอยู่แล้วจะไม่ error
---
- name: Cleanup examples
hosts: all
become: true
tasks:
# ลบไฟล์
- name: Remove config
file:
path: /etc/myapp/old.conf
state: absent
# ลบ directory และ contents ทั้งหมด (rm -rf equivalent)
- name: Remove old release directory
file:
path: /opt/myapp/releases/v1.0.0
state: absent
# ลบหลาย path พร้อมกันด้วย loop
- name: Clean up temporary files
file:
path: "{{ item }}"
state: absent
loop:
- /tmp/deploy.lock
- /tmp/myapp-install.tmp
- /var/run/myapp.pid
# ลบ symlink (ไม่ลบ target)
- name: Remove nginx site symlink
file:
path: /etc/nginx/sites-enabled/disabled-site.conf
state: absent
Pattern: Prepare Filesystem ก่อน Deploy
ตัวอย่าง Playbook เตรียม directory structure, permissions และ symlinks สำหรับ application ก่อน deploy จริง
---
- name: Prepare filesystem for application
hosts: appservers
become: true
vars:
app_name: myapp
app_version: "2.5.0"
app_user: appuser
app_group: appgroup
tasks:
- name: Create application directory structure
file:
path: "{{ item.path }}"
state: directory
owner: "{{ app_user }}"
group: "{{ app_group }}"
mode: "{{ item.mode }}"
loop:
- { path: "/opt/{{ app_name }}/releases", mode: "0755" }
- { path: "/opt/{{ app_name }}/releases/v{{ app_version }}", mode: "0755" }
- { path: "/opt/{{ app_name }}/shared/config", mode: "0750" }
- { path: "/opt/{{ app_name }}/shared/logs", mode: "0755" }
- { path: "/opt/{{ app_name }}/shared/tmp", mode: "0755" }
- name: Set config directory permissions (restricted)
file:
path: "/opt/{{ app_name }}/shared/config"
owner: root
group: "{{ app_group }}"
mode: '0750'
state: directory
- name: Create log with correct ownership
file:
path: "/opt/{{ app_name }}/shared/logs/app.log"
state: touch
owner: "{{ app_user }}"
group: "{{ app_group }}"
mode: '0644'
- name: Switch current symlink to new release
file:
src: "/opt/{{ app_name }}/releases/v{{ app_version }}"
dest: "/opt/{{ app_name }}/current"
state: link
force: true
- name: Remove old releases
file:
path: "/opt/{{ app_name }}/releases/{{ item }}"
state: absent
loop: "{{ old_releases | default([]) }}"
สรุป
file module เป็นเครื่องมือหลักสำหรับจัดการ filesystem บน Ansible รองรับ state ครบทั้ง touch, directory, absent, link, hard และ file การกำหนด owner, group, mode ทำได้ทั้งตอนสร้างและตอนแก้ไข object ที่มีอยู่แล้ว
Pattern ที่ควรจำ: ใช้ loop สร้างหลาย directory พร้อมกันแทนการเขียน task ซ้ำ, ใช้ recurse: true เฉพาะเมื่อต้องการแก้ permissions ทั้ง tree (ระวัง performance บน directory ใหญ่), ใช้ force: true กับ symlink เพื่อให้ replace link เดิมได้ และใช้ state: absent แทน command: rm เสมอ

