Ansible Role เป็นวิธีจัดระเบียบ Playbook ให้ reusable และ shareable — แต่ Role ที่ดีจริง ๆ ต้องเข้าใจการจัดการ dependencies ระหว่าง roles, ความแตกต่างระหว่าง defaults และ vars และการใช้ประโยชน์จาก Ansible Galaxy เพื่อดึง community roles มาใช้แทนการเขียนเอง
บทความนี้ครอบคลุม role dependencies ใน meta/main.yml, การใช้ defaults/main.yml สำหรับ overridable variables, การติดตั้งและใช้ roles จาก Ansible Galaxy, การจัดการ requirements ด้วย requirements.yml และ pattern สำหรับ production-ready role
Role Dependencies — กำหนด roles ที่ต้องการก่อน
Role dependencies กำหนดใน meta/main.yml — เมื่อ role A มี dependency ต่อ role B, Ansible จะรัน role B อัตโนมัติก่อน role A ทุกครั้ง ทำให้ไม่ต้องระบุ role B ใน Playbook เอง
# roles/myapp/meta/main.yml
---
galaxy_info:
author: myteam
description: Deploy MyApp web application
license: MIT
min_ansible_version: "2.9"
platforms:
- name: Ubuntu
versions:
- focal
- jammy
- name: EL
versions:
- "8"
- "9"
dependencies:
# role นี้ต้องการ nginx role ก่อนเสมอ
- role: geerlingguy.nginx
vars:
nginx_vhosts:
- listen: "80"
server_name: "{{ app_domain }}"
root: "/opt/{{ app_name }}/current/public"
# ต้องการ postgresql role
- role: geerlingguy.postgresql
vars:
postgresql_databases:
- name: "{{ app_db_name }}"
postgresql_users:
- name: "{{ app_db_user }}"
password: "{{ app_db_password }}"
# ต้องการ common role ของทีม (local role)
- role: common
vars:
common_packages:
- curl
- git
- unzip
defaults/main.yml — Variables ที่ Override ได้
defaults/main.yml เก็บ variables ที่มี priority ต่ำที่สุด — ผู้ใช้ role สามารถ override ค่าเหล่านี้ได้จาก inventory, group_vars, host_vars หรือ Playbook vars โดยตรง ทำให้ role ยืดหยุ่นและ reusable ข้าม project
# roles/myapp/defaults/main.yml
---
# Application settings (ทุกค่าที่ user ควรปรับได้ตาม environment)
app_name: myapp
app_port: 8080
app_user: appuser
app_group: appuser
app_install_dir: "/opt/{{ app_name }}"
app_log_dir: "/var/log/{{ app_name }}"
app_config_dir: "/etc/{{ app_name }}"
# Database defaults
app_db_host: localhost
app_db_port: 5432
app_db_name: "{{ app_name }}_db"
app_db_user: "{{ app_name }}_user"
# Feature flags (ปิดเป็น default — เปิดเมื่อต้องการ)
app_enable_ssl: false
app_enable_metrics: false
app_enable_cache: true
# Performance tuning defaults
app_workers: 4
app_max_connections: 100
app_timeout: 30
# Deployment settings
app_version: latest
app_repo: "" # บังคับให้ user ตั้งค่า — ไม่มี default ที่สมเหตุสมผล
เปรียบเทียบกับ vars/main.yml ที่มี priority สูงและไม่ควร override — ใช้สำหรับ internal constants ที่ role ต้องการ:
# roles/myapp/vars/main.yml
---
# Internal constants — ไม่ควร override จากภายนอก
_app_service_name: "{{ app_name }}"
_app_pid_file: "/var/run/{{ app_name }}.pid"
_app_socket: "/var/run/{{ app_name }}.sock"
# OS-specific paths (ตั้งตาม ansible_os_family)
_app_config_paths:
Debian: /etc/{{ app_name }}
RedHat: /etc/{{ app_name }}
# Role version tracking
_role_version: "1.2.0"
Ansible Galaxy — ติดตั้งและใช้ Community Roles
Ansible Galaxy เป็น repository สาธารณะสำหรับ roles ที่ community เขียนไว้ — ใช้คำสั่ง ansible-galaxy install ติดตั้ง role ที่ต้องการ หรือใช้ requirements.yml เพื่อ declare dependencies ทั้งหมดในครั้งเดียว
# ค้นหาและติดตั้ง role เดี่ยว
ansible-galaxy install geerlingguy.nginx
# ติดตั้งหลาย roles พร้อมกัน
ansible-galaxy install geerlingguy.nginx geerlingguy.postgresql geerlingguy.redis
# ติดตั้ง version เฉพาะ
ansible-galaxy install geerlingguy.nginx,3.2.0
# ดู roles ที่ติดตั้งแล้ว
ansible-galaxy list
# ลบ role
ansible-galaxy remove geerlingguy.nginx
# ค้นหา role บน Galaxy
ansible-galaxy search nginx --author geerlingguy
requirements.yml — จัดการ Galaxy Dependencies
requirements.yml เก็บรายการ roles และ collections ที่ project ต้องการ — เหมาะสำหรับ version pinning และ reproducible deployments โดย commit ไฟล์นี้ไว้ใน git แล้วรัน ansible-galaxy install -r requirements.yml
# requirements.yml
---
roles:
# ติดตั้งจาก Galaxy ด้วย version เฉพาะ
- name: geerlingguy.nginx
version: "3.2.0"
- name: geerlingguy.postgresql
version: "3.4.0"
- name: geerlingguy.redis
version: "1.9.0"
# ติดตั้งจาก GitHub repo โดยตรง
- name: myteam.common
src: https://github.com/myteam/ansible-role-common
version: main
scm: git
# ติดตั้งจาก local path (สำหรับ private roles)
- name: internal_security
src: /opt/ansible-roles/security
collections:
# ติดตั้ง Ansible Collections
- name: community.general
version: ">=6.0.0"
- name: ansible.posix
version: "1.5.4"
- name: community.postgresql
version: "2.3.0"
# ติดตั้งทุก dependencies จาก requirements.yml
ansible-galaxy install -r requirements.yml
# ติดตั้งลงใน path เฉพาะ (สำหรับ project-level roles)
ansible-galaxy install -r requirements.yml -p roles/
# Force re-install แม้มีอยู่แล้ว
ansible-galaxy install -r requirements.yml --force
# ติดตั้ง collections แยก
ansible-galaxy collection install -r requirements.yml
ใช้ Galaxy Roles ใน Playbook
หลังติดตั้ง Galaxy roles แล้ว ใช้ได้เหมือน local roles — สามารถ override defaults ของ Galaxy role ด้วย vars ใน Playbook หรือ group_vars เพื่อปรับให้ตรงกับ environment ของตัวเอง
---
- name: Deploy web application stack
hosts: appservers
become: true
vars:
# Override defaults ของ geerlingguy.nginx
nginx_worker_processes: "auto"
nginx_worker_connections: "1024"
nginx_vhosts:
- listen: "80"
server_name: "mysite.example.com"
root: "/var/www/mysite"
index: "index.php index.html"
extra_parameters: |
location ~ \.php$ \{
fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
\}
# Override defaults ของ geerlingguy.postgresql
postgresql_version: "14"
postgresql_databases:
- name: myapp_db
encoding: UTF-8
postgresql_users:
- name: myapp_user
password: "{{ vault_db_password }}"
db: myapp_db
priv: "ALL"
# Override defaults ของ geerlingguy.redis
redis_bind_interface: "127.0.0.1"
redis_maxmemory: "512mb"
redis_maxmemory_policy: "allkeys-lru"
roles:
- role: geerlingguy.postgresql
- role: geerlingguy.redis
- role: geerlingguy.nginx
- role: myapp # local role ที่มี dependencies ข้างต้น
Pattern: Production-Ready Role พร้อม Dependencies และ Galaxy
ตัวอย่าง role structure ที่พร้อมใช้ใน production — มี defaults ครบถ้วน, meta/main.yml ระบุ dependencies และ platform support, พร้อม requirements.yml สำหรับ Galaxy dependencies
# โครงสร้าง role สำหรับ Django application
roles/
django_app/
defaults/
main.yml # overridable settings ทั้งหมด
vars/
main.yml # internal constants
tasks/
main.yml # task entry point
install.yml # ติดตั้ง packages
configure.yml # deploy config files
service.yml # manage systemd service
handlers/
main.yml # reload/restart handlers
templates/
gunicorn.service.j2
django_settings.py.j2
nginx_site.conf.j2
meta/
main.yml # dependencies และ galaxy_info
molecule/ # tests (ถ้าใช้ Molecule)
default/
converge.yml
verify.yml
# roles/django_app/meta/main.yml
---
galaxy_info:
author: myteam
description: Deploy Django application with Gunicorn
license: MIT
min_ansible_version: "2.12"
platforms:
- name: Ubuntu
versions: [focal, jammy]
- name: EL
versions: ["8", "9"]
galaxy_tags:
- django
- python
- web
dependencies:
- role: geerlingguy.nginx
vars:
nginx_vhosts:
- listen: "80"
server_name: "{{ django_domain }}"
extra_parameters: |
location / \{
proxy_pass http://127.0.0.1:{{ django_port }};
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
\}
location /static/ \{
alias {{ django_static_root }}/;
\}
- role: geerlingguy.postgresql
vars:
postgresql_databases:
- name: "{{ django_db_name }}"
postgresql_users:
- name: "{{ django_db_user }}"
password: "{{ django_db_password }}"
db: "{{ django_db_name }}"
priv: ALL
# roles/django_app/defaults/main.yml
---
# Application identity
django_app_name: django_app
django_domain: localhost
django_port: 8000
# Paths
django_install_dir: "/opt/{{ django_app_name }}"
django_static_root: "{{ django_install_dir }}/staticfiles"
django_media_root: "{{ django_install_dir }}/media"
django_venv_path: "{{ django_install_dir }}/venv"
# Database
django_db_name: "{{ django_app_name }}_db"
django_db_user: "{{ django_app_name }}_user"
django_db_password: "" # ต้อง set ใน vault
# Python / Gunicorn
django_python_version: "3.11"
django_gunicorn_workers: "{{ ansible_processor_vcpus * 2 + 1 }}"
django_gunicorn_timeout: 30
# Django settings
django_debug: false
django_allowed_hosts:
- "{{ django_domain }}"
django_secret_key: "" # ต้อง set ใน vault
สรุป
Role ที่ดีต้องมีทั้ง 3 องค์ประกอบ: meta/main.yml สำหรับ declare dependencies ที่ต้องรันก่อน, defaults/main.yml สำหรับ variables ที่ผู้ใช้ override ได้, และการใช้ Galaxy roles แทนการเขียนซ้ำในส่วนที่มี community role ที่ดีแล้ว
Pattern ที่ควรจำ: ใส่ทุก variable ที่ user ควรปรับได้ใน defaults/main.yml, ใช้ vars/main.yml สำหรับ internal constants เท่านั้น, pin version ของ Galaxy roles ใน requirements.yml เสมอเพื่อ reproducible deployments และ commit ไฟล์ requirements.yml ไว้ใน git ร่วมกับ Playbook

