Share
Embed
構成管理ツール Ansible 実践 / ansible-seminar-20160715
勉強会講演資料 構成管理ツール Ansible 実践
Hands on 用のAnsinle Playbookは以下で公開しています。
https://github.com/uorat/ansible-handson/
Taro Hirose
July 15, 2016
Transcript
49 slides
-
ࣗݾհ ኍ ଠ @ CyberZ ‣ גࣜձࣾ CyberZ - OPENRECࣄۀ෦
‣ Πϯϑϥ & αʔόαΠυ ΤϯδχΞ ‣ ܦྺ ‣ ಠཱܥITίϯαϧςΟϯάϑΝʔϜ R&D ‣ גࣜձࣾCyberZ ΞυςΫϊϩδʔࣄۀ෦ / Πϯϑϥہ ‣ גࣜձࣾCyberZ OPENRECࣄۀ෦ (ݱ৬) ‣ ಘҙྖҬ ‣ ӡ༻ࢹɺߏཧ/ࣗಈԽ ‣ Contents ‣ http://uorat.hatenablog.com/ -
࣍ 1. Ansible ֓ཁ ‣ Ansible ͱ ‣ Ansible ͷಛ
‣ σϞʢදతͳ͍ํͱߏઆ໌ʣ 2. Ansible ೖ ‣ ༻ޠઆ໌ ‣ Playbook ͷॻ͖ํ ‣ σϞʢPlaybookαϯϓϧઆ໌ͱ࣮ߦʣ 3. Ansible ࣮ફ ‣ σΟϨΫτϦߏ / Best Practice ‣ Playbook ࡞ͷ ίπ ‣ ฐࣾͰͷࣄྫ -
Ansibleͱ “Ansible is Simple IT Automation” SIMPLE AGENTLESS POWERFUL Automate
in hours - not weeks - with Ansible's human-readable IT automation language. Ansible uses SSH instead of agents. More efficient, more secure and less to manage. App deployment, configuration management and orchestration - all from one system. qt: http://www.ansible.com/home -
ߏཧͷ͢ʍΊ (1) - ߏཧ ‣ ಉظ͞Εͳ͍υΩϡϝϯτ ‣ هࡌ༰͕ݹ͍ ‣ ίϚϯυ͕ؒҧ͍ͬͯΔ
‣ ൿͷλϨͱԽͨ͠Snapshot ‣ ΫϦʔϯΠϯετʔϧ͞Εͨαʔό ͔Βಉ༷ͷڥΛߏஙͰ͖ͳ͍ ‣ νϡʔχϯά༰͕ෆ໌ ‣ Ṗͷdaemon͕ಈ͍͍ͯΔ ߏཧΛߦ͍ɺαʔόͷʮ͋Δ ͖࢟ʯΛཧ͠Α͏ -
ߏཧͷ͢ʍΊ (2) - ࣗಈԽ ‣ Ճ͢ΔϏδωεεϐʔυ ‣ ܹԽ͢Δάϩʔόϧڝ૪ ‣ Ϋϥυͷ಄ʹΑΓɺϦιʔεͷௐ
ୡʹ͔͔ΔϦʔυλΠϜ͕ܹݮ ‣ Մೳͳ͔͗Γ͘ੈʹग़͢ ‣ ՃՁΛߴΊΔۀʹूத ‣ ఆৗۀίετͰ ‣ αʔό / ϛυϧΣΞ ηοτΞοϓ ‣ ΞϓϦέʔγϣϯσϓϩΠ ‣ ੬ऑੑରԠ ਓґଘͳ࡞ۀΛࣗಈԽ͠ɺߴͳ σϦόϦΛ࣮ݱ͠Α͏ -
࠶ܝ “Ansible is Simple IT Automation” SIMPLE AGENTLESS POWERFUL Automate
in hours - not weeks - with Ansible's human-readable IT automation language. Ansible uses SSH instead of agents. More efficient, more secure and less to manage. App deployment, configuration management and orchestration - all from one system. qt: http://www.ansible.com/home -
Ansibleͷಛ “Ansible is Simple IT Automation” ‣ ఆٛYAMLʢ㲈ઃఆϑΝΠϧʣ ‣ ϓϩάϥϜͰ͢Βແ͍ͨΊֶशোน͕গͳ͍
SIMPLE Automate in hours - not weeks - with Ansible's human-readable IT automation language. --- - hosts: webservers tasks: - name: yum install nginx yum: pkg=nginx state=installed -
Ansibleͷಛ “Ansible is Simple IT Automation” ‣ agentΠϯετʔϧෆཁ ‣ ӡ༻ཧαʔόͰansible*ίϚϯυ͕͑ΕOK
‣ Python͕ೖ͍ͬͯΕಋೖՄೳ ‣ ઐ༻ͷserveragentͷӡ༻ཧෆཁ ‣ ৗற͢Δϓϩηεͳ͠ AGENTLESS Ansible uses SSH instead of agents. More efficient, more secure and less to manage. -
Ansibleͷಛ “Ansible is Simple IT Automation” ‣ ߏཧ͚ͩͰͳ͘Orchestrationͱͯ͑͠ΔͷͰɺͪΐͬͱ͠ ͨૢ࡞ௐࠪͷࢧԉπʔϧʹͳΔ ‣
ߴػೳ͕ͩɺεϞʔϧελʔτͰ࢝ΊΔ͜ͱՄೳ POWERFUL App deployment, configuration management and orchestration - all from one system. ॊೈͳ࣮ߦํ๏ ‣ ࢦఆͨ͠λΠϛϯάͰ࣮ߦ ‣ ෳฒྻ࣮ߦ ‣ ඞཁͳॲཧ͚ͩΛone-linerͰadhocʹ࣮ߦ ‣ Pushܕ͚ͩͰͳ͘Pullܕαϙʔτ (ansible-pull) -
Ansibleͷಛ “Ansible is Simple IT Automation” ႈੑ ‣ هࡌͨ͠DSLͷఆٛͷঢ়ଶʹऩଋͯ͘͠ΕΔ ‣
͋Δૢ࡞ΛԿճߦͬͯ݁Ռಉ͡ ‣ มߋ͕ͳ͚ΕॲཧΛεΩοϓ͢Δ ҎԼ͕Πϯετʔϧ͞Ε͍ͯΔ͜ͱ ɾnginx ɾjava ɾzabbix_agentd αʔϏε͕ىಈ͍ͯ͠Δ͜ͱ ɾnginx ɾzabbix_agentd -
Chef ͱͷൺֱ ‣ ػೳ໘ͷࠩ΄΅ແ͍ɻ ‣ ߏͱఆٛܗࣜ/ςϯϓϨʔτΤϯδϯʹ͕ࠩ͋Δ Ansible Chef Agent Agent
ෆཁ ཧରͷ Agent Πϯετʔϧඞཁ Pull / Push Pushܕ ʢಛఆͷαʔό͔ΒSSHͰૢ࡞ʣ Pullܕ ʢChef server͔ΒߏใΛऔಘ࣮ͯ͠ߦʣ ఆٛܗࣜ YAML Ruby DSL ςϯϓϨʔτ Τϯδϯ Jinja2 eRuby ڞ༗ϦϙδτϦ Ansible Galaxy Chef Supermarket ։ൃݴޠ Python Ruby -
ߏ ‣ Ansible࣮ߦαʔό 1 ‣ ansible01 [172.30.221.] ‣ Targetαʔό 3
‣ test01 [172.30.221.] ‣ test02 [172.30.222.] -
Ansibleख࢝Ί 1. Inventory HostΛهࡌ 2. AnsibleίϚϯυΛࢼ͠ଧͪ ✤ `ansible TARGET -m
'ping'` ✤ `ansible TARGET -m 'setup'` # /etc/ansible/hosts [webservers] ansible-target0x -
ओͳίϚϯυ ‣ ansible ‣ Adhoc ʹ࣮ߦ͢Δ ‣ ansible-playbook ‣ ࣄલʹ࡞ͨ͠ॲཧ܈
(Playbook) Λ࣮ߦ͢Δ # ίϚϯυ࣮ߦྫ $ ansible -m 'ping' webservers ansible-test02 | success >> { "changed": false, "ping": "pong" } # dry-run $ ansible-playbook hands-on00.yml --check --diff … PLAY RECAP ******************************************************************** ansible-test02 : ok=2 changed=0 unreachable=0 failed=0 # execute $ ansible-playbook hands-on00.yml … PLAY RECAP ******************************************************************** ansible-test02 : ok=2 changed=0 unreachable=0 failed=0 -
Inventory File ‣ Ansible Ͱཧ͢ΔϗετΛ ini ܗࣜͰهड़͢Δ ‣ ϗετͷάϧʔϐϯά͕Մೳ ‣
εΫϦϓτͷ࣮ߦ݁ՌΛInventoryʹར༻͢Δ͜ͱՄೳ (Dynamic Inventory) ‣ ׆༻γʔϯ ‣ AWSOpenstackͷΑ͏ͳΫϥυڥΛར༻͍ͯ͠Δ ‣ αʔό͕ಈతʹ૿ݮ͢ΔͨΊɺϦιʔεʹ͚ͭͨTag Ͱཧ͍ͨ͠ # ྫ: example.com αΠτΛAnsibleͰཧ͢Δ mail.example.com [webservers] foo.example.com bar.example.com [dbservers] one.example.com two.example.com three.example.com -
Playbook ࣮ߦ͢Δॲཧͷ༰ΛYAMLܗࣜͰهࡌ͢Δ ‣ PlaybookͱInventry File͑͞ἧ͑ɺऔΓ࣮͑ͣߦͰ͖Δ --- - hosts: webservers tasks:
- name: ensure apache is at the latest version yum: pkg=httpd state=latest - name: write the apache config file template: src=templates/httpd.j2 dest=/etc/httpd.conf notify: - restart apache - name: ensure apache is running (and enable it at boot) service: name=httpd state=started enabled=yes handlers: - name: restart apache service: name=httpd state=restarted -
YAML ‣ ߏԽ͞ΕͨσʔλΛදݱ͢ΔϑΥʔϚοτ ‣ “YAML ain't markup language“ ‣ Ruby,
Python, Java, PHP͡Ί֤छݴޠͰར༻Մೳ ‣ ઃఆϑΝΠϧͰར༻͞ΕΔ͜ͱ͕ଟ͍ ‣ ߏԽ͞ΕͨσʔλΛදݱ͢ΔϑΥʔϚοτ ‣ γʔέϯε (ྻܗࣜ): “- “ (ϋΠϑϯ + ۭന) ‣ Ϛοϐϯά (ϋογϡܗࣜ): “: “ (ίϩϯ + ۭന) - name: ensure apache is at the latest version yum: pkg=httpd state=latest - name: write the apache config file template: src=templates/httpd.j2 dest=/etc/httpd.conf notify: - restart apache - name: ensure apache is running (and enable it at boot) service: name=httpd state=started enabled=yes ྻ ϋογϡ ϋογϡ ϋογϡ ྻ -
Task (Tasks lists) ۩ମతͳॲཧΛɺ࣮ߦ͢ΔॱʹྻͰهࡌ͢Δ ‣ جຊ name ͱ module ͷηοτΛهࡌ͢Δ
‣ ࣮ߦ݅τϦΨʔ (notify/handler) ΛՃ͑Δ͜ͱՄೳ ‣ ࣮ߦ݅: [when, changed_when, ignore_errors, always_runͳͲ] ‣ τϦΨʔ: handlers Ͱهࡌͨ͠ॲཧͷ໊લΛnotifyͰࢦఆ --- - hosts: webservers tasks: - name: ensure apache is at the latest version yum: pkg=httpd state=latest - name: write the apache config file template: src=templates/httpd.j2 dest=/etc/httpd.conf notify: - restart apache - name: ensure apache is running (and enable it at boot) service: name=httpd state=started enabled=yes handlers: - name: restart apache service: name=httpd state=restarted -
Module TasksͰࢦఆͨ͠ॲཧΛ࣮ߦ͢Δ൚༻ϥΠϒϥϦ ‣ Modules are “idempotent” (ႈੑ) ‣ Core ModulesͰඞཁͳ࡞ۀେମΧόʔͰ͖Δ
--- - hosts: webservers tasks: - name: ensure apache is at the latest version yum: pkg=httpd state=latest - name: write the apache config file template: src=templates/httpd.j2 dest=/etc/httpd.conf notify: - restart apache - name: ensure apache is running (and enable it at boot) service: name=httpd state=started enabled=yes handlers: - name: restart apache service: name=httpd state=restarted -
දతͳModule ‣ yum / apt : ύοέʔδཧ (Πϯετʔϧ, আͳͲ) ‣
service : αʔϏεૢ࡞ (ىಈ, ఀࢭ, ࠶ىಈͳͲ) ‣ file : ϑΝΠϧૢ࡞ (࡞, আ, ଐੑมߋͳͲ) ‣ copy : ϑΝΠϧΛίϐʔ ‣ get_url: ࢦఆURL͔ΒϑΝΠϧΛμϯϩʔυ ‣ template : ϑΝΠϧΛܗͱͯ͠ϑΝΠϧੜ (ޙड़) ‣ shell : ҙͷshellίϚϯυΛ࣮ߦʢ˞ႈੑࣗͰ୲อʣ ‣ ۩ମతͳૢ࡞ͷଞɺ“register” Λซ༻ͯ݅͠ذʹར༻͢Δͷ͍ํ͋Δ ެࣜυΩϡϝϯτʹModuleͷҰཡͱઆ໌͕͋ΔͷͰɺৄ͘͠ҎԼΛࢀর͍ͩ͘͞ɻ http://docs.ansible.com/ansible/modules_by_category.html -
ڞ௨Խ (Template / Variable) ‣ Template: ‣ ܗͷϑΝΠϧʹมΛల։ͯ͠ੜͨ͠ϑΝΠϧΛͰ͖Δ ‣ IPhostnameɺenvͳͲڥϗετຖʹҟͳΔϑΝΠϧΛ͢Δ࣌ͳͲʹ׆༻
‣ ॻࣜ “Jinja2” (PythonςϯϓϨʔτΤϯδϯ) ‣ มͷຒΊࠐΈ 2ॏதׅހ “{{ hogefuga }}“ ‣ ifจforจͳͲͷ੍ޚจར༻Մೳ # files/etc/motd.j2 ################################################## !!! Production server {{ ansible_hostname }} !!! ################################################## __| __|_ ) _| ( / Amazon Linux AMI ___|\___|___| https://aws.amazon.com/amazon-linux-ami/2015.03-release-notes/ -
ڞ௨Խ (Template / Variable) ‣ Variable: ‣ ݅ذTemplateͰར༻͢ΔมΛఆٛ͠ݺग़Մೳ ‣ ॻࣜYAML
‣ playbook, inventry host, varsͳͲ༷ʑͳՕॴͰࢦఆՄೳ ‣ OSͷԼճΓͷใansible͕ࣗಈͰऔಘ͠ݺग़Մೳ (Gathering Facts) ‣ ར༻Մೳͳม `ansible hostname -m setup` Ͱ֬ೝՄೳ ‣ ChefͰݴ͏ ohai # Variables innodb_buffer_pool_size: 6144M innodb_log_file_size: 2048M max_connections: 1000 … $ ansible ansible-test02 -m 'setup' ansible-test02 | success >> { "ansible_facts": { "ansible_all_ipv4_addresses": [ "172.31.xx.xx" ], "ansible_all_ipv6_addresses": [], "ansible_architecture": "x86_64", "ansible_bios_date": "NA", "ansible_bios_version": "NA", "ansible_cmdline": { "KEYTABLE": "us", "LANG": "ja-JP.UTF-8", -
ڞ௨Խ (Include / Role) ‣ Include: ‣ taskshanderlsΛผϑΝΠϧͱͯ͠Γग़͠ɺҰͭͷRoleͱͯ͠·ͱΊ͓ͯ͘͜ͱͰ࠶ར༻ ͘͢͢͠Δ ---
- hosts: webservers tasks: - include: apache.yml - include: deploy.yml site=service_A - include: deploy.yml site=service_B -
ڞ௨Խ (Include / Role) ‣ Role: ‣ task, vars, files,
templates, handlersҰࣜΛڞ௨Խ ‣ playbook͔Β roles ҰൃͰݺͼग़͠Ͱ͖Δ ‣ ෳαʔόʹద༻͢Δɺ൚Խͤ͞ΔͳͲͷ༻్Ͱ׆༻ # playbook --- - hosts: webservers roles: - common - webserver # σΟϨΫτϦߏ hosts webservers.yml roles/ common/ files/ templates/ tasks/ handlers/ vars/ defaults/ meta/ webservers/ … -
ɹ Webαʔό setup 1. ӡ༻πʔϧΛΠϯετʔϧ ‣ epel-release, telnet, wget, rsync,
tree, tcpdump, sysstat, dstat, vim- enhanced, git 2. όφʔΛஔ ‣ /etc/motd 3. Nginx install ‣ yum install ‣ ࣗಈىಈ༗ޮ 4. Deploy ‣ page upload (దͳhtml) -
ɹ Webαʔό setup 1. ࣮ྫ1) 1ͭͷPlaybook ‣ αϯϓϧPlaybook (Github) 2.
࣮ྫ2) RoleΛ׆༻ ‣ αϯϓϧPlaybook (Github) -
BestPractice Best Practices Directory Layout - Ansible Documentation ެࣜυΩϡϝϯτʹհ͞Ε ͍ͯΔσΟϨΫτϦߏͷϕ
ετϓϥΫςΟεɻ ͜Εʹ४ͯ͡࡞͢Δͱɺ pathΛҙࣝͤͣʹRoleVars ΛࢀরͰ͖Δɻ production # Inventory Hostάϧʔϓ͝ͱʹ࡞ staging # ʏ group_vars/ # άϧʔϓ༻ͷมͷ֨ೲॴ group1 # group2 # host_vars/ # ϗετ༻ͷมͷ֨ೲॴ hostname1 # hostname2 # library/ # ࣗ࡞Moduleͷ֨ೲॴ (optional) filter_plugins/ # ࣗ࡞Filter Pluginͷ֨ೲॴ (optional) site.yml # master Playbook webservers.yml # Playbook dbservers.yml # Playbook roles/ # ϩʔϧ (Role) ͷ֨ೲॴ common/ # “common” ϩʔϧ tasks/ # Taskͷ֨ೲॴ main.yml # <-- Task͕͠ଟ͘ͳΔ߹খ͚͘͞Δ handlers/ # Handlerͷ֨ೲॴ main.yml # <-- ʏ templates/ # Templateͷ֨ೲॴ ntp.conf.j2 # <------- TemplateϑΝΠϧ໊ *.j2 files/ # Fileͷ֨ೲॴ bar.txt # foo.sh # vars/ # Varsͷ֨ೲॴ main.yml # defaults/ # main.yml # VarsͷσϑΥ (group/host_varsͰ্ॻ͖Մ) meta/ # ϩʔϧͷґଘ͕ؔ͋Εఆٛ main.yml # webtier/ # “webtier” ϩʔϧ monitoring/ # “monitiring" ϩʔϧ fooapp/ # “fooapp” ϩʔϧ -
Playbook ࡞/࣮ߦͷίπ 1. shell ϞδϡʔϧΛۃྗΘͳ͍ ‣ ࣮ݱ͍ͨ͜͠ͱେModuleԽ͞Ε͍ͯΔ ‣ ࣗ࡞ͨ͠ϩδοΫͷɺႈੑͷ୲อ͕ࠔʹͳΔ 2.
AnsibleͰϏϧυ͠ͳ͍ ‣ Shell ModuleͰϏϧυΛͤͣɺRPMύοέʔδΛ࡞ΔํʹΛΔ͜ͱ ‣ ͦͷ্ͰύοέʔδϚωʔδϟʔΛAnsibleͰݺͼग़͢ʢYum, Apt, pip, nvm, …etcʣ 3. มΛ׆༻ͯ͠RoleΛ൚Խ͢Δ ‣ σϑΥϧτ: $ROLE/defaults/main.yml ‣ ϗετ/άϧʔϓຖʹՄมͳ: group_vars, host_vars ‣ ϗετݻ༗ͷ: Gathering Facts 4. Roleͷ൚Խʹͩ͜ΘΓ͗͢ͳ͍ ‣ Multi OSରԠͳͲͩ͜ΘΓա͗ΔͱɺPlaybook͕٫ͬͯಡΈͮΒ͘ͳΔ͜ͱ ‣ ඞཁ࠷খݶͷॲཧʹͱͲΊ͓ͯ͘ 5. όʔδϣϯཧ͢Δʢgitʣ ‣ ίϛοτϩά͕ͦͷ··ߏมߋͷഎܠͷઆ໌ʹͳΔ ‣ ޙʑӾཡͯ͠Ձͷ͋ΔʮಡΈʯͱͯ͠ॻ͘͜ͱ -
Playbook ࡞/࣮ߦͷίπ 6. ڞ௨ॲཧΛूΊͨRoleΛ༻ҙ͢Δ ‣ roles/common ͳͲ ‣ ӡ༻ʹඞཁͳύοέʔδͷΠϯετʔϧɺࢹΤʔδΣϯτͷઃఆͳͲΛೖΕ͓ͯ͘ 7.
ႈੑΛࣺ͑ͯͯΔɺׂΓ͖Γඞཁ ‣ OS update, kernel tuning, ੬ऑੑରԠͳͲɺӡ༻தͷαʔόʹྲྀͨ͘͠ͳ͍ॲཧ ‣ ΫϦʔϯΠϯετʔϧ࣌ʹ࣮ߦ͍ͨ͠ॲཧΛ roles/init ʹ·ͱΊ͓ͯ͘ ‣ Snapshotӡ༻ͩͱɺߦͬͨ࡞ۀ͕ൿͷλϨԽ͢ΔͷͰɻ ‣ kickstartcloud-initΛطʹ͍ͬͯΕɺͦͪΒʹدͤΔͰྑ͍ɻ 8. RoleͷܗΛ༻ҙ͓ͯ͘͠ ‣ Roleྔ࢈͢Δ͜ͱʹͳΔ ‣ ຖಉ͡σΟϨΫτϦΛ༻ҙ͢Δͷखؒ ‣ ӈਤͷΑ͏ͳۭRoleΛ࡞͓ͬͯ͘ ‣ ۭRoleΛίϐʔ͢Εɺ͙ʹRole࡞ʹྭΊΔ 9. ࣮ߦલʹඞͣdry-run͢Δ ‣ --check ΦϓγϣϯͰ dry-run ࣮ߦ͞ΕΔ ‣ ࣮ߦରͷϗετͷ࠶֬ೝɺॲཧͷ࠶֬ೝ ‣ --diff ΦϓγϣϯΛ͚ͭΔͱɺϑΝΠϧߋ৽࣌diffදࣔ͞ΕΔͷͰ֬ೝʹศར ‣ ࣮ߦ͢Δ·Ͱ -s (sudoϞʔυ) Ͱansible-playbookίϚϯυ࣮ߦ͠ͳ͍͜ͱ ‣ ͳΔ͘ࣄނΛ͙Α͏ʹ ‣ root ϢʔβͰग़དྷΔݶΓansible࣮ߦ͠ͳ͍ $ tree -a roles/__model/ roles/__model/ ᵓᴷᴷ defaults ᴹ ᵋᴷᴷ .gitkeep ᵓᴷᴷ files ᴹ ᵋᴷᴷ .gitkeep ᵓᴷᴷ handlers ᴹ ᵋᴷᴷ .gitkeep ᵓᴷᴷ meta ᴹ ᵋᴷᴷ .gitkeep ᵓᴷᴷ tasks ᴹ ᵋᴷᴷ .gitkeep ᵓᴷᴷ templates ᴹ ᵋᴷᴷ .gitkeep ᵋᴷᴷ vars ᵋᴷᴷ .gitkeep -
ฐࣾͷࣄྫ ‣ OSܗ࡞ ‣ ڞ௨ॲཧྲྀ͠ࠐΈ ‣ ϛυϧΣΞΠϯετʔϧ ‣ ઃఆϑΝΠϧ ‣
OSϢʔβՃ/আ ‣ ੬ऑੑରԠ ‣ ͏Δ͏ඵରԠ ‣ ΞυϗοΫௐࠪ -
Hands On 1. SwapfileΛ࡞ ✤ 512MBͷswapfileΛ࡞ ✤ swaponͰεϫοϓՃ ✤ boot࣌ʹࣗಈϚϯτ
✤ ※ႈੑ୲อ͢Δ͜ͱ 2. ӡ༻πʔϧΛՃ ✤ htop, glances ✤ ag (the-silver-searcher) 3. Deploy (from github) ✤ yteraoka/ansible-tutorial ✤ /var/www/ ҎԼʹdeploy ✤ NginxઃఆϑΝΠϧฤूˠrestart -
ղྫ ✤ ղྫ (P.48) ✤ https://github.com/uorat/ansible- handson/blob/master/hands-on02.sh ✤ ղྫ (P.49)
✤ Playbook ✤ https://github.com/uorat/ansible- handson/blob/master/hands- on03.yml ✤ Role ✤ https://github.com/uorat/ansible- handson/tree/master/roles/hands- on3