Ansible Playbook o Role: Kailan Gagamit ng Bawat Isa
Alamin kung kailan sapat ang flat playbook at kailan kailangan ng role, kasama ang layout, ansible-galaxy init, role calls, at variable precedence.
Ansible playbook kumpara sa role: ano ang pagkakaiba
Ang Ansible playbook ang file na pinapatakbo mo gamit ang ansible-playbook. Itinatakda nito kung aling grupo ng hosts ang gagawa ng kinakailangang trabaho. Ang Ansible role ay isang directory na may fixed layout para sa tasks, templates, handlers, at default variables, at tinatawag ito ng playbook gamit ang 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 anyo para sa unang automation mo, at mananatili itong angkop nang mas matagal kaysa sa inaasahan ng karamihan. Gawing role kapag kailangang patakbuhin ang parehong block ng tasks para sa ikalawang grupo ng hosts, o kapag lumampas ang file sa humigit-kumulang 100 lines at hindi mo na mahanap ang task sa pag-scroll.
Kung hindi ka pa nakasusulat ng isa, magsimula sa unang playbook laban sa isang VPS at bumalik kapag nagsimula na itong lumaki.
Kapag flat playbook ang tamang sagot
Tama ang flat playbook kapag isang beses lang isinasagawa ang gawain, sa isang host lang, o walang ibang babasa nito. Ang pag-provision ng isang application server o pag-patch ng isang machine 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 naidudulot ang indirection na iyon at nadaragdagan lang ang bawat pagtalon mo kapag gusto mong basahin kung ano talaga ang tumatakbo.
Hindi na tama ang flat playbook sa isang partikular na sandali, at madaling makita kung kailan iyon. Kinokopya mo ang isang block ng tasks sa pangalawang playbook. Iyan ang senyales. Mula noon, kailangang gawin nang dalawang beses ang bawat pag-aayos, at darating ang araw na isang beses lang ito magagawa.
Ano talaga ang 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- Ang
tasks/main.ymlang entry point. Pinapatakbo ng Ansible ang file na ito kapag tinawag ang role, at optional ang lahat ng iba pang directory. - Ang
defaults/main.ymlang naglalaman ng mga variable na inaasahang ma-override ng tumatawag. Ito ang may pinakamababang priority sa Ansible, kaya halos anumang ibang source ay mananaig dito. - Ang
vars/main.ymlang naglalaman ng mga variable na hindi inaasahang ma-override ng tumatawag. Mas mataas ang priority nito kaysa inventory, kaya malakas na pahayag ang paggamit nito. Gamitin ito nang bihira. - Ang
handlers/main.ymlang naglalaman ng mga task na itina-trigger ngnotify. Tumatakbo ang isang handler sa dulo ng play nang isang beses, kahit ilang task pa ang nag-notify rito. - Ang
files/ang naglalaman ng mga file na verbatim na kino-copy ngcopymodule, at angtemplates/ang naglalaman ng mga Jinja2 template na nire-render ngtemplatemodule. Sa loob ng role, tukuyin ang dalawa gamit ang bare filename na walang path, dahil unang hinahanap ng Ansible ang sariling directory ng role. - Ang
meta/main.ymlang nagde-declare ng mga role dependency at metadata na binabasa ng Ansible Galaxy.
Hindi lang usapin ng style ang layout. Hinahanap ng Ansible ang mga file sa eksaktong path na ito, kaya hindi kailanman mahahanap ang template na inilagay mo sa roles/common/template/ (singular).
Buuin ang karaniwang role gamit ang ansible-galaxy init
mkdir -p ~/infra/roles
cd ~/infra
ansible-galaxy init --init-path roles commonIsinusulat 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 ---. Tanggalin ang mga directory na iiwan mong walang laman. Hindi nakaaapekto sa Ansible ang walang-lamang vars/main.yml, pero itinatago nito kung aling mga file sa role ang aktuwal na mahalaga.
Ngayon, punan ang mga file na gumagawa ng 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 na-render na 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, ang systemd unit ay tinatawag na ssh. Sa mga system na kabilang sa RHEL family, tinatawag naman itong sshd. Nabibigo lamang ang handler na may maling pangalan kapag may aktuwal na nagbago sa template. Kaya karaniwang lumalabas ang problema makalipas ang ilang linggo.
Ang validate line ang pinakamahalagang bahagi ng task na iyon. 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 may status na 0. Maglagay ng maling directive sa template at patakbuhin itong muli. Mabibigo ang task na may failed to validate, mananatiling hindi nagagalaw ang totoong /etc/ssh/sshd_config.d/99-hardening.conf, at mayroon ka pa ring server na maaari mong i-log in. Tandaan na higit pa sa syntax ang sinusuri ng check. Kung hindi mabasa ng sshd -t ang host keys, mag-e-exit ito na may sshd: no hostkeys available -- exiting.. Iuulat naman 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=localansible-playbook -i inventory.ini site.ymlDapat magtapos ang play sa failed=0 sa recap. Ipasa ang mga parameter sa call site gamit ang expanded form. Sa ganitong paraan, maaaring gamitin ng isang role para sa dalawang grupo ng hosts:
roles:
- role: common
common_admin_group: ops
common_permit_root_login: prohibit-passwordMay isang ordering rule na nakakagulat sa halos lahat. Maaaring maglaman ang isang play ng pre_tasks, roles, tasks at post_tasks, at pinapatakbo ng Ansible ang mga ito sa ganoong pagkakasunod-sunod anuman ang pagkakasunod na isinulat mo sa file. Ilagay ang tasks: bago ang roles:, ngunit 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: postPara 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 inilagay sa import. Dynamic ang include_role. Walang binabasa hanggang sa tumakbo ang task, kaya maaaring kunin ang pangalan ng role mula sa isang variable o loop. Ang kapalit nito, hindi nakikita ang mga task na iyon ng --list-tasks at --start-at-task.
May isang karaniwang pitfall dito. Sinusuri ang when: sa isang include_role task bago maging available sa scope ang defaults/main.yml ng kasamang role. Kapag isinulat mo ang when: common_packages | length > 0 sa include, hihinto ang run na may 'common_packages' is undefined, kahit defined ang variable na iyon sa mismong role na ini-include mo. Ang solusyon ay ilipat sa labas ng role ang toggle: ilagay ito sa group_vars/all.yml, kung saan nasa scope ito kahit saan, at iwan sa defaults ng role ang mga value na ginagamit mismo ng role.
Aling variable ang mananaig: defaults, group_vars, vars, extra vars
Idinodokumento 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.ymlay nasa bandang ibaba. Halos anumang itakda mo sa ibang lugar ay mananaig dito. Kaya ito ang tamang lagyan ng mga configurable na setting ng isang role.group_vars/athost_vars/ay nasa gitna. Dito dapat ilagay ang mga value na partikular sa site mo. Malinis nitong ino-override ang role defaults.roles/<name>/vars/main.ymlay mas mataas kaysa sahost_vars. Hindi ito maaaring i-override ng value mula sa inventory. Itabi ito para sa mga value na kailangang manatiling internally consistent sa 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. Ang-esa command line naman ay mananaig sa lahat, kabilang ang role parameters.
Makikita mo ang resultang ito sa loob ng humigit-kumulang 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-cliSa unang run, ipi-print ang tunable=from-hostvars internal=from-rolevars. Nanaig ang inventory sa role default, ngunit natalo ito ng role var. Sa ikalawang run, ipi-print ang internal=from-cli dahil nasa pinakataas ang extra vars at walang mas mababang antas ang makapagbabago rito. Kaya ang -e ay angkop sa isang one-off run, ngunit mali ito sa script na patuloy mong ginagamit. Tahimik nitong nilalamangan ang bawat desisyong isinasaalang-alang sa repository mo.
Ito ang praktikal na tuntunin: kung gusto mong maitakda ang isang value, ilagay ito sa defaults/. Kapag inilagay mo ito sa vars/, ipinahihiwatig mo sa bawat susunod na gagamit ng role na hindi ito maaaring baguhin ng inventory. Minsan iyon talaga ang kailangan mo. Ngunit kadalasan, aksidente lang ito.
Patunayan na idempotent ang role: patakbuhin ito nang dalawang beses
Ang Ansible run na mapagkakatiwalaan ay nagbibigay ng parehong resulta sa ikalawang run at nag-uulat na wala itong binago. Patakbuhin ang playbook nang dalawang beses at basahin ang recap.
ansible-playbook -i inventory.ini site.yml
ansible-playbook -i inventory.ini site.ymlGanito dapat ang hitsura ng ikalawang recap:
PLAY RECAP *********************************************************************
localhost : ok=4 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0Ibig sabihin ng changed=0, sinuri ng bawat module ang kasalukuyang state at nakita nitong tapos na ang trabaho. Sa ikalawang run, ang changed=2 ay nangangahulugang may dalawang task na hindi matukoy ang pagkakaiba. 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 para 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.txtPatakbuhin 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 may isang linya ang /tmp/guarded.txt. Sa ikalawang run, hindi talaga na-execute ang guarded task. Taglay ng resulta nito ang mensaheng skipped, since /tmp/guarded.txt exists dahil binibigyan ng creates ang module ng nakikitang output na unang hahanapin. Kapag walang ganitong 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 aktuwal na gumagawa ng mga ito, at ipinapakita ng --diff ang eksaktong mga linyang isusulat muli ng isang template. Basahin ang output na may isang mahalagang paalala: nilalaktawan sa check mode ang mga task na shell at command, kaya maaaring may nakatagong trabaho kahit malinis ang ipinapakitang plan.
May isa pang column sa recap na kailangan ding suriin nang mabuti: ang host na hindi makonekta ng Ansible ay ibinibilang sa unreachable sa halip na failed, at wala sa mga task nito ang na-run. Kaya pagpasyahan muna kung dapat ihinto ng isang unreachable host ang buong run bago mo gamitin ang role na ito sa higit sa ilang machine.
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. Sinusunod ng paghahanap ang playbook, hindi ang iyong shell.
ERROR! the role 'common' was not found in /home/deploy/lonely/roles:/home/deploy/lonelyIbig sabihin ng mensaheng iyon, hindi na magkatugma ang site.yml at roles/. Ipinapakita rin nito ang mga path na sinubukan nito. Panatilihin 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.ymlMay mas tahimik na bersyon ng parehong problema. Hindi ginagamit ng Ansible ang isang ansible.cfg sa kasalukuyang directory kapag writable ito ng lahat, dahil maaaring maglagay doon ng config ang sinumang user sa machine at baguhin 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 hindi naisama ang iyong roles_path at inventory settings, at nabibigo ang role lookup dahil 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 tuwing kumikilos ang isang run na para bang wala ang iyong config.
Pagbabahagi ng roles: requirements.yml at naka-pin na version
Ang role na isinulat ng ibang tao ay ini-install, hindi kinokopya. Ideklara ito nang isang beses:
# requirements.yml
---
roles:
- name: postgres
src: https://github.com/example/ansible-role-postgres
scm: git
version: v1.4.0ansible-galaxy install -r requirements.yml -p galaxy_rolesPalaging itakda ang version. Kung wala ito, makukuha mo ang laman ng default branch sa araw na pinatakbo mo 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 ilabas ang directory na iyon sa git:
# ansible.cfg
[defaults]
inventory = inventory.ini
roles_path = ./galaxy_rolesNahanap pa rin ang mga role sa roles/ na katabi ng playbook, dahil palaging hinahanap ang path na iyon bukod pa sa roles_path. Kaya nananatiling naka-commit at nasusuri ang sarili mong roles, habang ang third-party roles ay mga reproducible download na naka-pin sa isang tag.
Kapag hindi na sapat ang roles
Ang role ay isang unit ng reuse sa loob ng isang Ansible run. Hindi ito gumagawa ng mga server o DNS record sa provider mo. Kapag pinipilit itong gawin iyon, nagiging mahirap i-maintain ang playbook. Basahin ang paghahati ng gawain sa pagitan ng Ansible at Terraform bago ka magsimula. Hindi rin pinapalitan ng role ang disenyo ng inventory. 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 itinatakda ng drop-in sa itaas. Basahin ang mga SSH setting na talagang sulit baguhin at paraan para awtomatikong mag-apply ang Ubuntu ng security update bago ka magpasya kung ano ang dapat ilagay sa role para sa bawat host na pinamamahalaan mo.
FAQ
Kailan ko dapat gawing role ang isang Ansible playbook?
Kapag kailangang patakbuhin ang parehong block ng tasks sa pangalawang play o laban sa pangalawang grupo ng hosts. Ang pagkopya ng mga task sa pagitan ng mga playbook ang palatandaan, dahil mula noon, kailangang ilapat nang dalawang beses ang bawat pag-aayos, at darating ang araw na isang beses lang ito mailalapat. Walang mapapala sa role ang isang playbook na humigit-kumulang 100 lines o mas maikli at palaging nagta-target sa isang grupo lang. Mas mahirap din itong basahin dahil sa mga karagdagang directory.
Nauuna bang tumakbo ang mga role sa mga task 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 paglitaw ng mga key na ito sa file. Ang pagsusulat ng tasks: bago ang roles: ay hindi nangangahulugang mauunang tumakbo ang 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 ko ang role?
Suriin kung nakatakda ang variable sa vars/main.yml ng role sa halip na sa defaults/main.yml. Mas mataas ang posisyon 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 ibaba ng order at ito ang tamang lugar para sa anumang dapat mabago ng tumatawag. Para makumpirmang precedence ang sanhi at hindi typo, isang beses na patakbuhin gamit ang -e name=value, na mas mataas ang precedence kaysa sa lahat ng iba pang source.
Bakit sinasabi ng Ansible na hindi nito nakita ang role?
Nagsisimula ang paghahanap 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 sinusundan ng paghahanap ang path ng playbook at hindi ang working directory ng shell. Kung umaasa ka sa roles_path mula sa ansible.cfg, tiyaking na-load ang file na iyon gamit ang ansible --version, dahil hindi ito ginagamit ng Ansible kapag world writable ang working directory.
Kailangan ko ba ang ansible-galaxy init para gumawa ng role?
Hindi. Ang role ay binubuo lamang ng mga directory na may inaasahang pangalan, kaya gumaganang role na ang mkdir -p roles/common/tasks kasama ang tasks/main.yml. Nakababawas ng pagta-type ang ansible-galaxy init --init-path roles common at ibinibigay nito ang buong skeleton, kasama ang meta/main.yml at README stub. Tanggalin ang mga directory na mananatiling walang laman, dahil itinatago ng walang-lamang vars/main.yml kung aling mga file sa role ang aktuwal na gumagana.