Ansible playbook বনাম role: কোনটি কখন ব্যবহার করবেন
সরল playbook কখন যথেষ্ট এবং কখন role ব্যবহার করবেন তা জানুন। role layout, ansible-galaxy init, role call ও variable precedence, সঙ্গে প্রায় 100 lines-এর বাস্তব সীমা।
Ansible playbook বনাম role: পার্থক্য কী
Ansible playbook হলো সেই ফাইল, যেটি আপনি ansible-playbook দিয়ে চালান। এটি একদল host-কে তাদের প্রয়োজনীয় কাজের সঙ্গে যুক্ত করে। Ansible role হলো নির্দিষ্ট কাঠামোর একটি directory, যেখানে tasks, templates, handlers এবং default variables থাকে। একটি playbook নাম ধরে role-টি ব্যবহার করে। উভয়ের ভেতরের task syntax একই। তাই এখানে কোন ধরনের কাজ প্রকাশ করা যায়, সেটি বিষয় নয়। বিষয় হলো পুনর্ব্যবহার।
একটি সরল playbook দিয়ে শুরু করুন। একটি site.yml-এ একটি tasks: list রাখা আপনার প্রথম automation-এর জন্য উপযুক্ত কাঠামো। অধিকাংশ মানুষ যতটা ভাবেন, তার চেয়েও বেশি সময় এটি কার্যকর থাকে। একই task block দ্বিতীয় কোনো host group-এ চালাতে হলে, অথবা ফাইলটি প্রায় 100 lines ছাড়িয়ে গেলে এবং scroll করে কোনো task খুঁজে পাওয়া কঠিন হলে, সেটিকে role-এ রূপান্তর করুন।
আপনি যদি এখনও একটি playbook না লিখে থাকেন, একটি single VPS-এর জন্য প্রথম playbook দিয়ে শুরু করুন এবং এটি বড় হতে শুরু করলে ফিরে আসুন।
যখন একটি সরল playbook-ই সঠিক পছন্দ
কাজটি একবার হয়, একটি host-এ হয়, অথবা অন্য কেউ playbook-টি পড়বে না—এমন ক্ষেত্রে সরল playbook-ই সঠিক। একটি application server provision করা, অথবা maintenance window-এর আগে একটি box patch করা—এসব কাজের জন্য directory tree তৈরি করার প্রয়োজন নেই। একটি role সাতটি directory এবং একটি অতিরিক্ত abstraction layer যোগ করে। যদি একমাত্র caller হয় তার পাশেই থাকা playbook, তাহলে এই abstraction-এর কোনো সুবিধা নেই; বরং কী চালানো হচ্ছে তা পড়তে প্রতিবার অতিরিক্ত file jump করতে হয়।
একটি নির্দিষ্ট পর্যায়ে সরল playbook আর সঠিক থাকে না, এবং সেই পর্যায়টি সহজেই চেনা যায়। আপনি একটি tasks block দ্বিতীয় playbook-এ copy করেন। এই copy-ই সংকেত। এরপর থেকে প্রতিটি fix দুই জায়গায় করতে হয়, এবং একদিন তা শুধু এক জায়গায় করা হবে।
একটি role directory-তে আসলে কী থাকে
roles/common/
defaults/main.yml
vars/main.yml
tasks/main.yml
handlers/main.yml
templates/99-hardening.conf.j2
files/
meta/main.ymltasks/main.ymlহলো entry point। role কল করা হলে Ansible এই ফাইলটি চালায়, এবং অন্য সব directory ঐচ্ছিক।defaults/main.yml-এ caller-এর override করার কথা থাকা variable থাকে। Ansible-এ এটি priority-এর দিক থেকে সর্বনিম্ন source, তাই প্রায় সব অন্য source-ই এটিকে অগ্রাহ্য করে।vars/main.yml-এ caller-এর override করার কথা না থাকা variable থাকে। priority-তে এটি inventory-এর ওপরে থাকে, যা একটি শক্তিশালী সিদ্ধান্ত। এটি খুব কম ব্যবহার করুন।handlers/main.yml-এnotifyদ্বারা trigger হওয়া task থাকে। একটি handler play-এর শেষে একবার চলে, যতগুলো task-ই তাকে notify করুক না কেন।files/-এcopymodule দিয়ে verbatim কপি করা file থাকে, এবংtemplates/-এtemplatemodule দিয়ে render করা Jinja2 template থাকে। role-এর ভিতরে উভয়কেই path ছাড়া bare filename দিয়ে reference করবেন, কারণ Ansible প্রথমে role-এর নিজস্ব directory-তে খোঁজে।meta/main.ymlrole dependency ঘোষণা করে এবং Ansible Galaxy যে metadata পড়ে তা ধারণ করে।
এই layout কোনো style preference নয়। Ansible এই নির্দিষ্ট path-গুলোতেই খোঁজে, তাই roles/common/template/-এ (singular) রাখা কোনো template কখনোই পাওয়া যাবে না।
ansible-galaxy init দিয়ে common role তৈরি করুন
mkdir -p ~/infra/roles
cd ~/infra
ansible-galaxy init --init-path roles commonএটি roles/common-এর অধীনে সম্পূর্ণ skeleton তৈরি করে। এর মধ্যে এমন directory-ও থাকে যেগুলো আপনি ব্যবহার করবেন না এবং main.yml-এর এমন stub থাকে যাতে শুধু --- রয়েছে। যেগুলো খালি রাখবেন, সেগুলো মুছে দিন। খালি vars/main.yml Ansible-এর জন্য ক্ষতিকর নয়, তবে role-এ আসলে কোন ফাইল গুরুত্বপূর্ণ তা বোঝা কঠিন করে।
এখন কাজ সম্পাদনকারী ফাইলগুলো পূরণ করুন। প্রথমে defaults লিখুন, কারণ এগুলোই role-এর public interface।
# roles/common/defaults/main.yml
---
common_packages:
- ufw
- fail2ban
- unattended-upgrades
common_admin_group: admins
common_permit_root_login: "no"
common_password_authentication: "no""no" এবং "yes"-কে quote-এর মধ্যে রাখুন। Ansible PyYAML দিয়ে YAML parse করে। PyYAML একটি bare no-কে boolean false হিসেবে পড়ে। ফলে rendered config line PermitRootLogin False হয়ে যায় এবং sshd সেটি প্রত্যাখ্যান করে। Quote ব্যবহার করলে value-টি string হিসেবে থাকে।
# 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 }}Debian ও Ubuntu-তে systemd unit-এর নাম ssh। RHEL family-র system-এ নাম sshd। কোনো পরিবর্তনের পরে তবেই handler চালু হয়। তাই ভুল unit-এর নাম দেওয়া handler সাধারণত কয়েক সপ্তাহ পরে ধরা পড়ে।
এই task-এর সবচেয়ে গুরুত্বপূর্ণ অংশ হলো validate line। Ansible template-টি একটি temporary file-এ render করে, সেই ফাইলের path দিয়ে %s প্রতিস্থাপন করে এবং command চালায়। Command 0 exit code দিলে তবেই destination প্রতিস্থাপিত হয়। Template-এ একটি ভুল directive যোগ করে আবার চালান। Task failed to validate-সহ ব্যর্থ হবে, আসল /etc/ssh/sshd_config.d/99-hardening.conf অপরিবর্তিত থাকবে, এবং আপনি এখনও সার্ভারে login করতে পারবেন। মনে রাখবেন, এই check শুধু syntax পরীক্ষা করে না। sshd -t host key পড়তে না পারলে sshd: no hostkeys available -- exiting. exit code দেয়। তখন Ansible একই failed to validate report করে। তাই template-কে দোষ দেওয়ার আগে module-এর msg পড়ুন।
একটি play কীভাবে role কল করে
# 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.ymlrecap-এ play-টি failed=0 দিয়ে শেষ হওয়া উচিত। call site-এ expanded form ব্যবহার করে parameter পাঠান। এভাবেই একটি role দুইটি host group-এর জন্য ব্যবহার করা যায়:
roles:
- role: common
common_admin_group: ops
common_permit_root_login: prohibit-passwordএখানে একটি ordering rule আছে, যা প্রায় সবাইকে অবাক করে। একটি play-তে pre_tasks, roles, tasks এবং post_tasks থাকতে পারে। ফাইলে আপনি যে ক্রমেই লিখুন না কেন, Ansible সেগুলো ওই ক্রমেই চালায়। tasks:-কে roles:-এর উপরে রাখলেও role আগে চলে। তাই কোনো কাজ role-এর আগে করাতে হলে সেটি pre_tasks:-এ রাখতে হবে, 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: postroles: key-এর পরিবর্তে task list-এর ভেতর থেকে কোনো role কল করতে import_role অথবা 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"import_role static। Ansible parse time-এ role পড়ে এবং তার task-গুলো play-এর অংশ হয়ে যায়। তাই ansible-playbook --list-tasks site.yml সেগুলো তালিকাভুক্ত করে এবং import-এর একটি tag ভেতরের প্রতিটি task-এ প্রযোজ্য হয়। include_role dynamic। task চলার আগে কিছুই পড়া হয় না। তাই variable বা loop থেকে role-এর নাম নির্ধারণ করা যায়। এর ফলে --list-tasks এবং --start-at-task-এ ওই task-গুলো দেখা যায় না।
এখানে একটি সাধারণ ভুল হতে পারে। include_role task-এর ওপর থাকা when: অন্তর্ভুক্ত role-এর defaults/main.yml scope-এ আসার আগেই মূল্যায়ন করা হয়। include-এর ওপর when: common_packages | length > 0 লিখলে run 'common_packages' is undefined দিয়ে থেমে যায়, যদিও ওই variable-টি আপনি যে role অন্তর্ভুক্ত করছেন তার মধ্যেই সংজ্ঞায়িত। সমাধান হলো toggle-টি role-এর বাইরে সরিয়ে নেওয়া। এটি group_vars/all.yml-এ রাখুন, যেখানে তা সর্বত্র scope-এ থাকবে। role নিজে যে value ব্যবহার করে, সেগুলোর জন্য role-এর defaults রেখে দিন।
কোন variable কার্যকর হয়: defaults, group_vars, vars, extra vars
Ansible variable precedence-এর 20টিরও বেশি স্তর নথিভুক্ত করেছে। বাস্তব ব্যবহারের প্রায় সব বিরোধ মেটাতে এর মধ্যে 4টি স্তরই যথেষ্ট। নিচে এগুলো দুর্বল থেকে শক্তিশালী ক্রমে দেওয়া হলো।
roles/<name>/defaults/main.ymlনিচের দিকের একটি স্তরে থাকে। অন্য যেকোনো জায়গায় সেট করা প্রায় সব value এটিকে অতিক্রম করে। তাই role-এর পরিবর্তনযোগ্য parameter রাখার জন্য এটিই উপযুক্ত স্থান।group_vars/এবংhost_vars/মাঝামাঝি স্তরে থাকে। আপনার site-এর নিজস্ব value এখানে রাখা উচিত। এগুলো role defaults-কে সরাসরি override করে।roles/<name>/vars/main.yml,host_vars-এর উপরে থাকে। এখানে রাখা কোনো value inventory থেকে override করা যায় না। role-এর অভ্যন্তরীণ সামঞ্জস্য বজায় রাখতে প্রয়োজনীয় বিষয়ের জন্য এটি সংরক্ষণ করুন, যেমন এমন একটি package name, যা service name-এর সঙ্গে মিলতে হবে।- call site-এ দেওয়া role parameter
vars/main.yml-কে override করে। আর command line-এ দেওয়া-erole parameter-সহ সবকিছুকে override করে।
প্রায় এক মিনিটে এই precedence কীভাবে নির্ধারিত হয়, তা দেখা যায়। একটি ছোট role-এ একটি default এবং একটি role var দিন। এরপর একই নাম 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প্রথম run-এ tunable=from-hostvars internal=from-rolevars প্রদর্শিত হয়। Inventory role default-কে override করেছে, কিন্তু role var-এর কাছে হেরে গেছে। দ্বিতীয় run-এ internal=from-cli প্রদর্শিত হয়, কারণ extra vars সর্বোচ্চ স্তরে থাকে এবং এর নিচের কোনো value এগুলোকে override করতে পারে না। এই কারণেই একবারের run-এর জন্য -e ব্যবহার করা উপযুক্ত, কিন্তু স্থায়ী script-এ এটি ভুল। কারণ এটি আপনার repository-তে বিবেচিত প্রতিটি সিদ্ধান্তকে নীরবে override করে।
কার্যকর নিয়ম হলো: কোনো value পরিবর্তনযোগ্য রাখতে চাইলে সেটি defaults/-এ রাখুন। vars/-এ রাখার অর্থ হলো, role ব্যবহারকারী ভবিষ্যৎ প্রত্যেক ব্যক্তিকে জানানো যে inventory থেকে এটি পরিবর্তন করা যাবে না। কখনও এটি আপনার উদ্দেশ্য হতে পারে। তবে বেশিরভাগ ক্ষেত্রে এটি অনিচ্ছাকৃত হয়।
রোলটি idempotent প্রমাণ করুন: এটি দুইবার চালান
বিশ্বাসযোগ্য Ansible run দ্বিতীয়বার একই ফল তৈরি করে এবং জানায় যে কিছুই পরিবর্তন হয়নি। Playbook-টি দুইবার চালান এবং recap দেখুন।
ansible-playbook -i inventory.ini site.yml
ansible-playbook -i inventory.ini site.ymlদ্বিতীয় recap এমন হওয়া উচিত:
PLAY RECAP *********************************************************************
localhost : ok=4 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0changed=0-এর অর্থ হলো প্রতিটি module বর্তমান অবস্থা পরীক্ষা করে দেখেছে যে প্রয়োজনীয় কাজ ইতিমধ্যে সম্পন্ন হয়েছে। দ্বিতীয় run-এ changed=2 দেখা গেলে বোঝায়, দুটি task পার্থক্য শনাক্ত করতে পারছে না। তাই তারা বারবার file লিখবে এবং service restart করবে। এর সাধারণ কারণ হলো command অথবা shell, কারণ কোনো নির্বিচার command কী করেছে তা Ansible জানার উপায় নেই।
# 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.txtPlaybook-টি দুইবার চালান। এরপর wc -l /tmp/grow.txt /tmp/guarded.txt-যুক্ত line গুনুন। /tmp/grow.txt-এ দুটি line এবং /tmp/guarded.txt-এ একটি line থাকবে। দ্বিতীয় run-এ guarded task একেবারেই execute হয়নি। এর result-এ skipped, since /tmp/guarded.txt exists message থাকবে, কারণ creates module-কে প্রথমে খুঁজে দেখার মতো একটি দৃশ্যমান output দেয়। কোনো command এমন output না রাখলে তার output changed_when দিয়ে register করুন এবং নিজেই সিদ্ধান্ত নিন।
ansible-playbook --check --diff site.yml কোনো পরিবর্তন না করেই সম্ভাব্য পরিবর্তন দেখায়। --diff template পুনরায় লিখলে যে exact line-গুলো পরিবর্তন করবে, সেগুলো দেখায়। একটি বিষয় মনে রেখে output পড়ুন: check mode-এ shell এবং command task skipped থাকে। তাই পরিষ্কার দেখানো plan-এর আড়ালেও কাজ বাকি থাকতে পারে।
Ansible কেন জানায় যে role পাওয়া যায়নি
Ansible প্রথমে playbook ফাইলের পাশে থাকা roles/ directory-তে, তারপর roles_path-এ role খোঁজে। এই অনুসন্ধান আপনার shell নয়, playbook অনুসরণ করে।
ERROR! the role 'common' was not found in /home/deploy/lonely/roles:/home/deploy/lonelyএই বার্তার অর্থ হলো site.yml এবং roles/-এর অবস্থান মিলছে না। Ansible যে path-গুলো পরীক্ষা করেছে, সেগুলোও বার্তায় দেখায়। দুটি একই directory-তে রাখুন। Parent directory থেকে চালানো সমস্যা নয়, কারণ playbook-এর path-ই এখানে বিবেচ্য:
ansible-playbook -i infra/inventory.ini infra/site.ymlএকই সমস্যার একটি কম দৃশ্যমান রূপও আছে। বর্তমান directory world writable হলে Ansible সেখানে থাকা ansible.cfg উপেক্ষা করে। কারণ ওই সার্ভারের যেকোনো user সেখানে একটি config রেখে আপনার run-এর আচরণ পরিবর্তন করতে পারে।
[WARNING]: Ansible is being run in a world writable directory (/tmp/infra), ignoring it as an ansible.cfg source.তখন আপনার roles_path এবং inventory setting নীরবে অনুপস্থিত থাকে, এবং role lookup এমন একটি কারণে ব্যর্থ হয় যার সঙ্গে role-এর কোনো সম্পর্ক নেই। ansible --version প্রকৃতপক্ষে লোড করা config file দেখায়, আর ansible-config dump --only-changed built-in default থেকে ভিন্ন প্রতিটি setting দেখায়। কোনো run এমন আচরণ করলে যেন আপনার config বিদ্যমান নয়, তখন উভয়ই পরীক্ষা করুন।
Roles ভাগ করা: requirements.yml এবং নির্দিষ্ট সংস্করণ
অন্য কেউ লিখেছেন এমন role কপি করা হয় না; এটি install করা হয়। একবার declare করুন:
# 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_rolesসবসময় version নির্ধারণ করুন। এটি না করলে command চালানোর দিনের default branch-এ যা থাকে, সেটিই পাওয়া যায়। ফলে গত মাসে কাজ করা deployment আপনার নিজের repository-তে কোনো পরিবর্তন না হলেও ব্যর্থ হতে পারে। roles_path-কে download directory হিসেবে নির্ধারণ করুন এবং সেই directory-কে git-এর বাইরে রাখুন:
# ansible.cfg
[defaults]
inventory = inventory.ini
roles_path = ./galaxy_rolesPlaybook-এর পাশে থাকা roles/-এর role-গুলোও পাওয়া যায়, কারণ roles_path-এর পাশাপাশি ওই path-ও সবসময় search করা হয়। তাই আপনার নিজস্ব role-গুলো repository-তে commit ও review করা থাকে, আর third-party role-গুলো tag-এ pinned, reproducible download হিসেবে ব্যবহৃত হয়।
যেখানে role আর যথেষ্ট নয়
একটি role একই Ansible run-এর মধ্যে পুনর্ব্যবহারের একটি একক। এটি আপনার provider-এ server বা DNS record তৈরি করে না। role-কে দিয়ে এই কাজ করানোর চেষ্টা করলেই playbook এমন অবস্থায় যায়, যা কেউ আর রক্ষণাবেক্ষণ করতে চায় না। শুরু করার আগে Ansible এবং Terraform-এর মধ্যে কাজের বিভাজন পড়ে নেওয়া উপযোগী। role inventory design-এর বিকল্পও নয়। কয়েকটি machine-এর বেশি হলে কীভাবে সেই server-গুলোকে group করবেন এবং সেগুলোতে পৌঁছাবেন—এটি task কীভাবে সাজানো হয়েছে তার চেয়ে বেশি গুরুত্বপূর্ণ।
এই common role যে hardening প্রয়োগ করে, সেটির জন্যও আলাদা সিদ্ধান্ত দরকার। উপরের drop-in-এ মাত্র দুটি directive সেট করা হয়েছে। তাই নিজের নিয়ন্ত্রণাধীন প্রতিটি host-এর role-এ কী রাখা উচিত তা নির্ধারণের আগে কোন SSH setting সত্যিই পরিবর্তন করা মূল্যবান এবং কীভাবে Ubuntu-কে স্বয়ংক্রিয়ভাবে security update প্রয়োগ করাবেন পড়ে নিন।
FAQ
কখন একটি Ansible playbook-কে role-এ রূপান্তর করা উচিত?
যখন একই tasks-এর block দ্বিতীয় কোনো play-এ বা দ্বিতীয় কোনো host group-এর বিরুদ্ধে চালাতে হয়। Playbook-গুলোর মধ্যে tasks কপি করা শুরু হওয়াই এর সংকেত। কারণ তখন থেকে প্রতিটি সংশোধন দুই জায়গায় প্রয়োগ করতে হবে, এবং একদিন হয়তো তা শুধু এক জায়গাতেই প্রয়োগ হবে। প্রায় 100 lines-এর কম একটি playbook যদি সবসময় শুধু একটি group-কে target করে, তবে role ব্যবহার করে কোনো সুবিধা পাওয়া যায় না। অতিরিক্ত directory সেটি পড়া আরও কঠিন করে তোলে।
একই play-এর tasks-এর আগে কি role চালানো হয়?
হ্যাঁ। Ansible প্রথমে pre_tasks চালায়, তারপর roles:-এর অধীনে তালিকাভুক্ত সবকিছু চালায়, এরপর tasks:, এবং সবশেষে post_tasks: চালায়। আপনার file-এ key-গুলো যে ক্রমেই থাকুক, Ansible সেই ক্রম অনুসরণ করে না। tasks:-কে roles:-এর উপরে লিখলে ওই tasks আগে চালানো হবে না। কোনো কিছু role-এর আগে চালানো আবশ্যক হলে সেটি pre_tasks:-এ রাখুন।
আমার group_vars-এর value role-কে override করছে না কেন?
Variable-টি role-এর vars/main.yml-এ, defaults/main.yml-এ নয়, সেট করা আছে কি না পরীক্ষা করুন। Ansible-এর precedence order-এ vars/, group_vars এবং host_vars-এর উপরে থাকে। তাই inventory সেটিকে override করতে পারে না। Variable-টি defaults/main.yml-এ সরান। এটি precedence order-এর নিচের দিকে থাকে এবং caller-এর পরিবর্তন করতে পারা উচিত এমন যেকোনো variable রাখার জন্য এটিই সঠিক স্থান। Precedence-ই কারণ, typo নয়, তা নিশ্চিত করতে একবার -e name=value দিয়ে চালান। এটি অন্য সব source-এর চেয়ে বেশি precedence পায়।
Ansible role পাওয়া যায়নি বলে জানায় কেন?
Search playbook file-এর পাশের directory থেকে শুরু হয়। তাই site.yml এবং roles/-কে একই directory-তে থাকতে হবে। Error message-এ Ansible যে path-গুলো পরীক্ষা করেছে সেগুলো দেখায়, যেমন the role 'common' was not found in /home/deploy/lonely/roles:/home/deploy/lonely। Parent directory থেকে playbook চালানো সমস্যা নয়, কারণ search আপনার shell-এর working directory নয়, playbook path অনুসরণ করে। আপনি যদি ansible.cfg থেকে roles_path-এর ওপর নির্ভর করেন, তবে ansible --version দিয়ে সেই file load হয়েছে কি না নিশ্চিত করুন। কারণ world-writable working directory থাকলে Ansible এটি উপেক্ষা করে।
একটি role তৈরি করতে কি ansible-galaxy init প্রয়োজন?
না। Role হলো প্রত্যাশিত নামের directory-গুলোর একটি কাঠামো। তাই mkdir -p roles/common/tasks এবং একটি tasks/main.yml থাকলেই একটি কার্যকর role তৈরি হয়। ansible-galaxy init --init-path roles common typing কমায় এবং meta/main.yml-সহ সম্পূর্ণ skeleton ও একটি README stub তৈরি করে। যেসব directory খালি থাকবে সেগুলো মুছে ফেলুন। কারণ খালি vars/main.yml role-এ বাস্তবে কোন file কাজ করছে তা বোঝা কঠিন করে তোলে।