SSD Nodes Learn 🎉 VPS mula $5.50/buwan
Mga Gabay Matt ConnorNi Matt Connor · Na-update 2026-08-07

Ansible Playbook o Role: Kailan Gagamit ng Bawat Isa

Alamin kung kailan sapat ang flat Ansible playbook at kailan sulit ang role, kasama ang layout, ansible-galaxy init, role calls, at variable precedence.

Verified Every command ran end-to-end on a fresh Ubuntu 24.04 server, July 30, 2026.

Ansible playbook at role: ano ang pagkakaiba

Ang Ansible playbook ay ang file na pinapatakbo mo gamit ang ansible-playbook. Itinatakda nito kung aling grupo ng hosts ang gagawa ng kinakailangang gawain. Ang Ansible role ay isang directory na may fixed layout. Naglalaman ito ng tasks, templates, handlers, at default variables. Tinatawag ito ng playbook ayon sa pangalan nito. Magkapareho ang task syntax sa dalawa. Kaya hindi ito usapin ng kung ano ang maaari mong i-express. Usapin ito ng reuse.

Magsimula sa isang flat playbook. Ang isang site.yml na naglalaman ng listahang tasks: ang tamang format para sa unang automation mo. Mananatili rin itong angkop nang mas matagal kaysa sa inaasahan ng karamihan. I-convert ito sa role kapag kailangang patakbuhin ang parehong block ng tasks para sa ikalawang grupo ng hosts, o kapag lumampas ang file sa humigit-kumulang 100 linya at hindi mo na mahanap ang isang task sa pag-scroll.

Kung hindi ka pa nakakasulat ng isa, magsimula sa unang playbook laban sa isang VPS at bumalik kapag nagsimula na itong lumaki.

Kailan ang flat playbook ang tamang sagot

Tama ang flat playbook kapag isang beses lang isinasagawa ang gawain, sa iisang host lang, o walang ibang magbabasa nito. Ang pag-provision ng isang application server o pag-patch ng isang box bago ang maintenance window ay hindi nangangailangan ng directory tree. Nagdaragdag ang isang role ng pitong directory at isang layer ng indirection. Kung ang tanging tumatawag dito ay ang playbook na nasa tabi nito, walang pakinabang ang indirection na iyon at kailangan mo pang mag-jump sa bawat pagbasa sa aktuwal na nagra-run.

May partikular na sandali kung kailan hindi na tama ang flat playbook, at madaling makita ang sandaling iyon. Kinopya mo ang isang block ng tasks sa ikalawang playbook. Iyon ang signal. Mula noon, kailangang gawin nang dalawang beses ang bawat fix, at darating ang araw na isang beses na lang ito magagawa.

Mga aktuwal na laman ng isang role directory

roles/common/
  defaults/main.yml
  vars/main.yml
  tasks/main.yml
  handlers/main.yml
  templates/99-hardening.conf.j2
  files/
  meta/main.yml
  • tasks/main.yml ang entry point. Pinapatakbo ng Ansible ang file na ito kapag tinawag ang role, at optional ang lahat ng iba pang directory.
  • defaults/main.yml ang naglalaman ng mga variable na inaasahang mao-override ng caller. Ito ang source na may pinakamababang priority sa Ansible, kaya halos anumang iba pang source ang nangingibabaw dito.
  • vars/main.yml ang naglalaman ng mga variable na hindi inaasahang mao-override ng caller. Mas mataas ang priority nito kaysa inventory, kaya seryosong desisyon ang paggamit nito. Gamitin ito nang madalang.
  • handlers/main.yml ang naglalaman ng mga task na tina-trigger ng notify. Tumatakbo ang isang handler sa pagtatapos ng play, isang beses lamang, gaano man karaming task ang nag-notify rito.
  • files/ ang naglalaman ng mga file na verbatim na kinokopya ng copy module, at templates/ ang naglalaman ng mga Jinja2 template na nire-render ng template module. Sa loob ng role, i-reference ang dalawang ito gamit ang bare filename at walang path, dahil unang hinahanap ng Ansible ang sariling directory ng role.
  • meta/main.yml ang nagde-declare ng role dependencies at metadata na binabasa ng Ansible Galaxy.

Hindi lang style preference ang layout. Naghahanap ang Ansible sa eksaktong mga path na ito, kaya hindi kailanman mahahanap ang template na inilagay mo sa roles/common/template/ (singular).

Buuin ang common role gamit ang ansible-galaxy init

mkdir -p ~/infra/roles
cd ~/infra
ansible-galaxy init --init-path roles common

Isinusulat nito ang buong skeleton sa ilalim ng roles/common, kasama ang mga directory na hindi mo gagamitin at mga main.yml stub na naglalaman lamang ng ---. I-delete ang mga iiwan mong walang laman. Hindi nakasasama sa Ansible ang walang-lamang vars/main.yml, pero itinatago nito kung aling mga file sa role ang aktuwal na mahalaga.

Punan ngayon ang mga file na gumagawa ng aktuwal na trabaho. Unahin ang defaults dahil ito ang public interface ng role.

# roles/common/defaults/main.yml
---
common_packages:
  - ufw
  - fail2ban
  - unattended-upgrades
common_admin_group: admins
common_permit_root_login: "no"
common_password_authentication: "no"

Lagyan ng quote ang "no" at "yes". Pino-parse ng Ansible ang YAML gamit ang PyYAML. Binabasa nito ang bare na no bilang boolean na false, kaya nagiging PermitRootLogin False ang rendered config line at nire-reject ito ng sshd. Pinananatili ng mga quote na string ang value.

# roles/common/tasks/main.yml
---
- name: Install the base packages
  ansible.builtin.apt:
    name: "{{ common_packages }}"
    state: present
    update_cache: true
    cache_valid_time: 3600

- name: Create the admin group
  ansible.builtin.group:
    name: "{{ common_admin_group }}"
    state: present

- name: Install the sshd hardening drop-in
  ansible.builtin.template:
    src: 99-hardening.conf.j2
    dest: /etc/ssh/sshd_config.d/99-hardening.conf
    owner: root
    group: root
    mode: "0644"
    validate: /usr/sbin/sshd -t -f %s
  notify: Restart sshd
# roles/common/handlers/main.yml
---
- name: Restart sshd
  ansible.builtin.service:
    name: ssh
    state: restarted
# roles/common/templates/99-hardening.conf.j2
# Managed by Ansible. Local edits are overwritten on the next run.
PermitRootLogin {{ common_permit_root_login }}
PasswordAuthentication {{ common_password_authentication }}

Sa Debian at Ubuntu, ssh ang pangalan ng systemd unit. Sa mga system na kabilang sa RHEL family, sshd naman ito. Nabibigo ang handler na maling unit ang pangalan nito kapag may aktuwal na pagbabago sa template. Kaya karaniwan lamang itong lumilitaw pagkalipas ng ilang linggo.

Ang linyang validate ang pinakamahalagang bahagi ng task na ito. Nire-render ng Ansible ang template sa isang temporary file, ipinapalit ang path ng file na iyon sa %s, at pinapatakbo ang command. Pinapalitan lamang ang destination kapag nag-exit ang command nang 0. Maglagay ng maling directive sa template at patakbuhin itong muli. Mabibigo ang task gamit ang failed to validate, mananatiling hindi nagagalaw ang aktuwal na /etc/ssh/sshd_config.d/99-hardening.conf, at magkakaroon ka pa rin ng server na maaari mong i-log in. Tandaan na higit pa sa syntax ang tine-test ng check. Kung hindi mabasa ng sshd -t ang host keys, mag-e-exit ito gamit ang sshd: no hostkeys available -- exiting. at iuulat ng Ansible ang parehong failed to validate. Basahin muna ang msg ng module bago sisihin ang template.

Paano tumatawag ng role ang isang play

# site.yml
---
- name: Base configuration for every server
  hosts: all
  become: true
  roles:
    - common
# inventory.ini
[local]
localhost ansible_connection=local
ansible-playbook -i inventory.ini site.yml

Dapat magtapos ang play sa failed=0 sa recap. Magpasa ng mga parameter sa call site gamit ang expanded form. Sa ganitong paraan, maaaring gamitin ang isang role para sa dalawang grupo ng hosts:

  roles:
    - role: common
      common_admin_group: ops
      common_permit_root_login: prohibit-password

May isang ordering rule dito na ikinagugulat ng halos lahat. Maaaring maglaman ang isang play ng pre_tasks, roles, tasks at post_tasks, at pinapatakbo ito ng Ansible sa ganoong pagkakasunod-sunod anuman ang pagkakaayos ng mga ito sa file. Ilagay man ang tasks: bago ang roles:, mauunang tumakbo ang mga role. Kaya kung may kailangang mangyari bago ang isang role, ilagay ito sa pre_tasks:, hindi sa itaas ng tasks:.

- name: Ordering demonstration
  hosts: local
  gather_facts: false
  pre_tasks:
    - name: Runs first
      ansible.builtin.debug:
        msg: pre
  roles:
    - common
  tasks:
    - name: Runs after the role
      ansible.builtin.debug:
        msg: task
  post_tasks:
    - name: Runs last
      ansible.builtin.debug:
        msg: post

Para tumawag ng role mula sa loob ng task list sa halip na gamitin ang roles: key, gamitin ang import_role o include_role.

  tasks:
    - name: Static, read when the playbook is parsed
      ansible.builtin.import_role:
        name: common

    - name: Dynamic, resolved when the task runs
      ansible.builtin.include_role:
        name: postgres
      when: "'db' in group_names"

Static ang import_role. Binabasa ng Ansible ang role sa parse time, at nagiging bahagi ng play ang mga task nito. Dahil dito, inililista ng ansible-playbook --list-tasks site.yml ang mga ito, at nalalapat sa bawat task sa loob ang tag na nasa import. Dynamic ang include_role. Walang binabasa hanggang sa tumakbo ang task, kaya maaaring kunin ang pangalan ng role mula sa variable o loop. Ang kapalit nito ay hindi nakikita ang mga task na iyon ng --list-tasks at --start-at-task.

May isang karaniwang bitag dito. Sinusuri ang when: sa isang include_role task bago maging available ang defaults/main.yml ng kasamang role. Kapag isinulat ang when: common_packages | length > 0 sa include, hihinto ang run at lalabas ang 'common_packages' is undefined, kahit defined ang variable na iyon sa mismong role na ini-include. Ang solusyon ay ilipat ang toggle sa labas ng role: ilagay ito sa group_vars/all.yml, kung saan available ito sa lahat ng scope, at gamitin ang defaults ng role para sa mga value na mismong role ang kumokonsumo.

Aling variable ang mananaig: defaults, group_vars, vars, o extra vars

Idinadokumento ng Ansible ang mahigit dalawampung antas ng variable precedence. Apat sa mga ito ang sumasagot sa halos lahat ng aktuwal na pagtatalo. Narito ang mga ito mula sa pinakamahina hanggang sa pinakamalakas.

  • roles/<name>/defaults/main.yml ay nasa bandang ibaba. Halos anumang itakda mo sa ibang lugar ay mananaig dito. Kaya ito ang tamang paglagyan ng mga adjustable setting ng isang role.
  • group_vars/ at host_vars/ ay nasa gitna. Dito dapat ilagay ang mga setting ng iyong site. Malinis nitong ino-override ang role defaults.
  • roles/<name>/vars/main.yml ay mas mataas kaysa host_vars. Hindi ito mao-override ng value mula sa inventory. Ilaan ito sa mga value na kailangang manatiling consistent sa loob ng role, gaya ng package name na kailangang tumugma sa service name.
  • Ang role parameter na ipinasa sa call site ay mananaig sa vars/main.yml. Samantala, ang -e sa command line ay mananaig sa lahat, kabilang ang role parameters.

Makikita mo ang prosesong ito sa loob ng halos isang minuto. Bigyan ang isang maliit na role ng isang default at isang role var. Pagkatapos, itakda ang parehong pangalan sa host_vars.

# roles/prec/defaults/main.yml
---
prec_tunable: from-defaults
prec_internal: from-defaults
# roles/prec/vars/main.yml
---
prec_internal: from-rolevars
# host_vars/localhost.yml
---
prec_tunable: from-hostvars
prec_internal: from-hostvars
# roles/prec/tasks/main.yml
---
- name: Show which value survived
  ansible.builtin.debug:
    msg: "tunable={{ prec_tunable }} internal={{ prec_internal }}"
ansible-playbook -i inventory.ini prec.yml
ansible-playbook -i inventory.ini prec.yml -e prec_internal=from-cli

Sa unang run, ipinapakita ang tunable=from-hostvars internal=from-rolevars. Nanaig ang inventory sa role default, ngunit natalo ito sa role var. Sa ikalawang run, ipinapakita ang internal=from-cli dahil nasa pinakamataas na antas ang extra vars at walang value sa ibaba nito ang makapag-override dito. Kaya ang -e ay angkop para sa isang one-off run, ngunit hindi para sa script na patuloy mong ginagamit. Tahimik nitong nilalampasan ang lahat ng pinag-isipang setting sa iyong repository.

Ang praktikal na tuntunin: kung gusto mong ma-set ang isang value, ilagay ito sa defaults/. Kapag inilagay mo ito sa vars/, sinasabi mo sa bawat susunod na gagamit ng role na hindi ito maaaring baguhin ng inventory. Minsan iyon talaga ang kailangan mo, pero kadalasan ay hindi sinasadya.

Patunayan na idempotent ang role: patakbuhin ito nang dalawang beses

Ang Ansible run na mapagkakatiwalaan ay gumagawa ng parehong resulta sa ikalawang run at nag-uulat na walang nagbago. Patakbuhin ang playbook nang dalawang beses at basahin ang recap.

ansible-playbook -i inventory.ini site.yml
ansible-playbook -i inventory.ini site.yml

Dapat ganito ang hitsura ng ikalawang recap:

PLAY RECAP *********************************************************************
localhost   : ok=4  changed=0  unreachable=0  failed=0  skipped=0  rescued=0  ignored=0

Ang changed=0 ay nangangahulugang sinuri ng bawat module ang kasalukuyang state at nakita nitong tapos na ang kinakailangang gawain. Sa ikalawang run, ang changed=2 ay nangangahulugang may dalawang task na hindi matukoy ang pagkakaiba, kaya patuloy nilang isusulat muli ang mga file at ire-restart ang mga serbisyo. Karaniwang sanhi nito ang command o shell, dahil walang paraan ang Ansible upang malaman kung ano ang ginawa ng isang arbitrary command.

# traps.yml
---
- name: Command modules do not know what they changed
  hosts: local
  gather_facts: false
  tasks:
    - name: This appends a line on every run
      ansible.builtin.shell: "echo run >> /tmp/grow.txt"

    - name: This appends a line only once
      ansible.builtin.shell: "echo run >> /tmp/guarded.txt"
      args:
        creates: /tmp/guarded.txt

Patakbuhin ang playbook nang dalawang beses, pagkatapos ay bilangin ang mga linyang may wc -l /tmp/grow.txt /tmp/guarded.txt. May dalawang linya ang /tmp/grow.txt at isang linya ang /tmp/guarded.txt. Sa ikalawang run, hindi talaga na-execute ang guarded task, at naglalaman ang resulta nito ng mensaheng skipped, since /tmp/guarded.txt exists, dahil binibigyan ng creates ang module ng nakikitang output na hahanapin muna. Kapag walang ganoong output ang isang command, i-register ang output nito at ikaw mismo ang magpasya gamit ang changed_when.

Hinuhulaan ng ansible-playbook --check --diff site.yml ang mga pagbabago nang hindi isinasagawa ang mga ito, at ipinapakita ng --diff ang eksaktong mga linyang isusulat muli ng isang template. Basahin ang output na may isang caveat: nilalaktawan sa check mode ang mga task na shell at command, kaya maaaring may mga nakatagong gawain pa rin kahit malinis ang nakikitang plan.

Bakit sinasabi ng Ansible na hindi nakita ang role

Hinahanap ng Ansible ang isang roles/ directory sa tabi ng playbook file, at pagkatapos ay sa roles_path. Ang sinusundan ng search ay ang playbook, hindi ang iyong shell.

ERROR! the role 'common' was not found in /home/deploy/lonely/roles:/home/deploy/lonely

Ibig sabihin ng mensaheng iyon, hindi na magkatugma ang site.yml at roles/. Awtomatikong ipinapakita nito ang mga path na sinubukan nito. Ilagay ang dalawang ito sa iisang directory. Ayos lang tumakbo mula sa parent directory, dahil ang playbook path ang ginagamit na batayan:

ansible-playbook -i infra/inventory.ini infra/site.yml

May mas tahimik na bersyon ng parehong problema. Hindi ginagamit ng Ansible ang isang ansible.cfg sa current directory kapag world-writable ang directory na iyon, dahil maaaring maglagay doon ng config ang sinumang user sa machine at mabago ang resulta ng iyong run.

[WARNING]: Ansible is being run in a world writable directory (/tmp/infra), ignoring it as an ansible.cfg source.

Dahil dito, tahimik na nawawala ang iyong roles_path at inventory settings, at nabibigo ang role lookup sa dahilang walang kinalaman sa mga role. Ipinapakita ng ansible --version ang config file na aktuwal nitong na-load, at ipinapakita ng ansible-config dump --only-changed ang bawat setting na naiiba sa built-in defaults. Suriin ang dalawa kapag kumikilos ang run na para bang hindi umiiral ang iyong config.

Mga role: requirements.yml at naka-pin na bersyon

Ini-install ang role na isinulat ng ibang tao; hindi ito kinokopya. Ideklara ito nang isang beses:

# requirements.yml
---
roles:
  - name: postgres
    src: https://github.com/example/ansible-role-postgres
    scm: git
    version: v1.4.0
ansible-galaxy install -r requirements.yml -p galaxy_roles

Palaging itakda ang version. Kung wala ito, makukuha mo ang laman ng default branch sa araw kung kailan mo pinatakbo ang command. Dahil dito, maaaring masira ang deployment na gumana noong nakaraang buwan kahit walang binago sa sarili mong repository. Ituro ang roles_path sa download directory, at huwag isama ang directory na iyon sa git:

# ansible.cfg
[defaults]
inventory = inventory.ini
roles_path = ./galaxy_roles

Nahanap pa rin ang mga role sa roles/ na nasa tabi ng playbook, dahil palaging hinahanap ang path na iyon bukod sa roles_path. Kaya ang sarili mong mga role ay nananatiling naka-commit at nasusuri, habang ang third-party roles ay reproducible na mga download na naka-pin sa isang tag.

Kapag hindi na sapat ang mga role

Ang role ay isang reusable na yunit sa loob ng isang Ansible run. Hindi ito gumagawa ng mga server o DNS record sa provider mo. Kapag pinilit mo itong gawin iyon, nagiging mahirap nang i-maintain ang mga playbook. Basahin muna ang paghahati ng trabaho sa pagitan ng Ansible at Terraform bago ka magsimula. Hindi rin pinapalitan ng role ang inventory design. Kapag lumampas na sa ilang machine ang pinamamahalaan mo, mas mahalaga ang paraan ng pag-group at pag-access sa mga server kaysa sa kung paano inayos ang mga task.

Nangangailangan din ng hiwalay na mga desisyon ang hardening na ini-install ng common role na ito. Dalawang directive lamang ang sine-set ng drop-in sa itaas. Basahin ang mga SSH setting na talagang dapat baguhin at paraan para awtomatikong mag-apply ang Ubuntu ng mga security update bago ka magpasya kung ano ang dapat isama sa role para sa bawat host na pinamamahalaan mo.

FAQ

Kailan ko dapat gawing role ang isang Ansible playbook?

Gawin itong role kapag kailangang patakbuhin ang parehong block ng tasks sa ikalawang play o sa ikalawang grupo ng hosts. Ang pagkopya ng tasks sa pagitan ng mga playbook ang malinaw na senyales, dahil mula noon kailangan mong ilapat nang dalawang beses ang bawat fix, at darating ang panahong isang beses mo lamang ito mailalapat. Walang pakinabang ang role sa isang playbook na wala pang humigit-kumulang 100 lines at palaging nagta-target ng iisang grupo. Mas mahirap din itong basahin dahil sa mga dagdag na directory.

Nauuna ba ang roles sa mga tasks sa parehong play?

Oo. Pinapatakbo ng Ansible ang pre_tasks, pagkatapos ang lahat ng nakalista sa ilalim ng roles:, kasunod ang tasks:, at pagkatapos ang post_tasks:. Hindi nito sinusunod ang pagkakasunod-sunod ng mga key na ito sa file. Ang paglalagay ng tasks: bago ang roles: ay hindi magpapapatakbo nang mas maaga sa mga task na iyon. Kung may kailangang mangyari bago ang isang role, ilagay ito sa pre_tasks:.

Bakit hindi nao-override ng value sa group_vars ang role?

Tingnan kung ang variable ay naka-set sa vars/main.yml ng role sa halip na sa defaults/main.yml. Mas mataas ang ranggo ng vars/ kaysa sa group_vars at host_vars sa precedence order ng Ansible, kaya hindi ito ma-o-override ng inventory. Ilipat ang variable sa defaults/main.yml. Malapit ito sa pinakailalim ng order at ito ang tamang paglalagyan ng anumang value na dapat mabago ng tumatawag. Para makumpirmang precedence ang sanhi at hindi typo, isang beses na patakbuhin gamit ang -e name=value. Mas mataas ang ranggo nito kaysa sa lahat ng ibang source.

Bakit sinasabi ng Ansible na hindi nahanap ang role?

Nagsisimula ang search sa tabi ng playbook file, kaya dapat nasa parehong directory ang site.yml at roles/. Ipinapakita ng error ang mga path na sinubukan nito, gaya ng the role 'common' was not found in /home/deploy/lonely/roles:/home/deploy/lonely. Ayos lang patakbuhin ang playbook mula sa parent directory, dahil sinusunod ng search ang path ng playbook at hindi ang working directory ng shell. Kung umaasa ka sa roles_path mula sa ansible.cfg, kumpirmahing na-load ang file gamit ang ansible --version, dahil hindi ito papansinin ng Ansible kapag world writable ang working directory.

Kailangan ko ba ang ansible-galaxy init para gumawa ng role?

Hindi. Ang role ay mga directory lamang na may inaasahang pangalan, kaya ang mkdir -p roles/common/tasks kasama ang isang tasks/main.yml ay isa nang gumaganang role. Nakababawas sa pagta-type ang ansible-galaxy init --init-path roles common at ibinibigay nito ang buong skeleton, kasama ang meta/main.yml at isang README stub. Tanggalin ang mga directory na iniiwang walang laman, dahil itinatago ng isang walang-lamang vars/main.yml kung aling mga file sa role ang aktuwal na may ginagawa.

#ansible#roles#playbook#structure#automation