آموزش کار با check mode و --diff در Ansible
در این راهنما بررسی میکنیم که چگونه با استفاده از --check و --diff تغییرات را قبل از اجرا شبیهسازی کنید. همچنین محدودیتهای ماژولها در گزارشدهی را بررسی میکنیم.
عملکرد حالت check mode در Ansible
حالت check mode در Ansible یک اجرای آزمایشی (dry run) است: ansible-playbook --check به تمام میزبانهای موجود در play متصل میشود، از هر ماژول میپرسد که آیا وضعیت فعلی با وضعیت مورد نظر شما مطابقت دارد یا خیر، و بدون نوشتن هیچ تغییری، گزارش میدهد که چه چیزی تغییر خواهد کرد. با افزودن --diff، این ابزار محتوای فایلهایی که قرار است تغییر کنند را نیز قبل و بعد از اعمال تغییرات نمایش میدهد. این دو در کنار هم به پرسشی پاسخ میدهند که پیش از هر اجرای واقعی باید مطرح شود: چه چیزی قرار است روی این سرورها تغییر کند؟
حالت check mode شبیهسازی playbook شما نیست. هیچ مدلی از سرور در هیچجایی وجود ندارد. از هر ماژول صرفاً خواسته میشود که به جای نوشتن، فقط وضعیت را بررسی کند. ماژولی که بتواند به صورت فقطخواندنی پاسخ دهد، changed را گزارش کرده و به کار خود ادامه میدهد. ماژولی که نتواند پاسخ دهد، هیچ کاری انجام نمیدهد و چیزی گزارش نمیکند. مستندات Ansible این موضوع را در یک جمله خلاصه کرده است: «ماژولهایی که از حالت check mode پشتیبانی نمیکنند، هیچ چیزی گزارش نمیدهند و هیچ کاری انجام نمیدهند.» این شکاف همان جایی است که اجرای آزمایشی ممکن است پاسخ اشتباهی به شما بدهد، بنابراین بخش عمدهای از این راهنما به بررسی همین شکاف اختصاص دارد.
اجرای آزمایشی: --check و --diff
ansible-playbook -i inventory.ini site.yml --check --diff --limit web1-C و -D شکلهای کوتاه دو فلگ هستند. استفاده از --limit عمدی است. تفاوت (diff) یک میزبان چیزی است که میتوانید بخوانید، اما تفاوت بیست میزبان چیزی است که فقط از آن عبور میکنید.
چهار واژه نتیجه، کل گزارش را تشکیل میدهند.
ok: [web1]به این معنی است که تسک اجرا شده و تغییری گزارش نشده است. برای ماژولی که وضعیت (state) را مدیریت میکند، مانندaptیاtemplate، این یعنی وضعیت فعلی با وضعیت مطلوب مطابقت دارد. برایdebugیاset_fact، این فقط به معنای اجرای تسک است.changed: [web1]به این معنی است که ماژول پیشبینی میکند که تغییری ایجاد میکرد. با--diff، خطوط بالای آن نشان میدهند که چه تغییری رخ میداد. اکثر ماژولها دقیق پیشبینی میکنند، اما تعداد کمی که پشتیبانی محدودی از حالت check دارند، در مستندات خود هشدار میدهند:get_urlدر حالت check فقط یک درخواست HEAD ارسال میکند و اعلام میکند که وضعیت changed را بهدرستی گزارش نخواهد کرد.skipping: [web1]به این معنی است که تسک اجرا نشده است. یا شرطwhenآن ارزیابی شده و false بوده، یا ماژول قابلیت اجرا در حالت check را ندارد.fatal: [web1]به این معنی است که تسک هنگام بررسی با خطا مواجه شده است. پیش از آنکه فرض کنید playbook خراب است، پیام خطا را بخوانید.
--diff یک diff یکپارچه برای ماژولهای فایل چاپ میکند، که در آن خطوط حذف شده با - و خطوط اضافه شده با + مشخص میشوند؛ این خروجی زیر سرآیندی قرار میگیرد که خطوط آن با --- before و +++ after شروع شده و مسیر مقصد را نام میبرند. ماژولهایی که فایل نمینویسند، وضعیت قبل و بعد خود را چاپ میکنند؛ بنابراین ansible.builtin.user ویژگیهایی را که تغییر میداد نشان میدهد، نه محتوای فایل را.
برای اینکه هرگز استفاده از این فلگ را فراموش نکنید، diff را بهطور دائمی در ansible.cfg فعال کنید:
[diff]
always = true
context = 5دو بررسی کمهزینهتر باید پیش از حالت check انجام شوند. ansible-playbook site.yml --syntax-check فایل YAML و ساختار play را بدون تماس با هیچ میزبانی تحلیل میکند. ansible-playbook site.yml --list-tasks تسکهایی را که قرار است اجرا شوند چاپ میکند؛ این همان روشی است که متوجه میشوید نقشی (role) که فکر میکردید تگ شده است، در واقع تگ نشده است. هیچکدام از این دو دستور به میزبان متصل نمیشوند، بنابراین هر دو آنی هستند.
خودِ حالت check متصل میشود. این حالت برای هر میزبان در الگو، یک اتصال SSH برقرار کرده و فکتها (facts) را جمعآوری میکند؛ بنابراین میزبانی که در دسترس نیست، باعث شکست اجرای آزمایشی میشود. این خود یک سیگنال مفید است و به همین دلیل است که تصمیمگیری درباره رفتار playbook با میزبانهای غیرقابلدسترس پیش از قرار دادن اجرای آزمایشی در CI اهمیت دارد.
چرا حالت check در یک سرور تازه نصبشده با خطا مواجه میشود
این پلیبوک صحیح است. آن را با --check روی سروری اجرا کنید که هنوز Nginx ندارد؛ در این صورت، بخش بزرگی از آن با خطا مواجه میشود.
- name: Install nginx
ansible.builtin.apt:
name: nginx
state: present
- name: Write the site config
ansible.builtin.template:
src: site.conf.j2
dest: /etc/nginx/conf.d/site.conf
- name: Start and enable nginx
ansible.builtin.service:
name: nginx
state: started
enabled: trueتسک apt وضعیت changed را گزارش میدهد و این درست است: بسته مورد نظر وجود ندارد، بنابراین اجرای واقعی آن را نصب خواهد کرد. حالت check آن را نصب نکرده است. سپس تسک template با خطا مواجه میشود، زیرا /etc/nginx/conf.d/ روی این میزبان وجود ندارد و هیچچیز آن را ایجاد نکرده است. تسک service نیز شکست میخورد، زیرا واحد nginx برای پرسوجو وجود ندارد. هیچکدام از این خطاها باگ پلیبوک نیستند. اجرای آزمایشی (dry run) به دلیل نبود وضعیت مورد نیاز متوقف شد؛ این همان چیزی است که مستندات هنگام هشدار درباره ناتوانی حالت check در ارائه خروجی مفید برای تسکهایی که ورودیشان به تغییرات تسکهای قبلی وابسته است، بیان میکنند.
بنابراین نسخه صادقانه این قانون چنین است: حالت check روی میزبانی که پلیبوک قبلاً روی آن همگرا (converge) شده، دقیقترین نتیجه را دارد و روی یک میزبان تازه، پر از نویز است. یک اجرای --check که در آن تمام تسکها ok را گزارش میدهند، گواهی واقعی بر همگرا بودن میزبان است، زیرا به این معنی است که هیچ تغییری رخ نخواهد داد. البته با دو شرط که در هر میزبانی صادق است: یک تسک command که نادیده گرفته شده (skipped)، یک فضای خالی است نه یک پاسخ، و یک ماژول با پشتیبانی ناقص از حالت check، مانند get_url، همچنان میتواند وضعیت تغییرات خود را اشتباه گزارش دهد. روی یک میزبان کاملاً جدید، --check عمدتاً به شما میگوید که میزبان جدید است. هنگامی که اولین پلیبوک Ansible خود را برای یک VPS مینویسید، انتظار داشته باشید که اولین اجرای آزمایشی با انبوهی از خطاها (رنگ قرمز) مواجه شود؛ پلیبوک را بر اساس اجرای دوم قضاوت کنید.
چرا وظایف command و shell در حالت check mode نادیده گرفته میشوند
ماژولهای ansible.builtin.command و ansible.builtin.shell نمیدانند دستور شما چه کاری انجام میدهد. هیچ روشی برای اجرای یک باینری دلخواه به صورت read-only وجود ندارد، بنابراین در حالت check mode، این ماژول از اجرای آن خودداری میکند. نتیجهٔ وظیفه شامل skipped: true است و پیام Command would have run if not in check mode را در بر دارد، و خروجی شما skipping: [web1] را نشان میدهد.
مستندات ماژول، پشتیبانی آن از حالت check mode را "جزئی" (partial) مینامد و راهکار پیشنهادی آن استفاده از creates و removes است. اگر به وظیفه یک مسیر creates بدهید، check mode حداقل میتواند تست فایل را ارزیابی کند:
- name: Extract the release bundle
ansible.builtin.command: /usr/bin/tar xf /tmp/app.tar.gz -C /opt/app
args:
creates: /opt/app/bin/appاگر /opt/app/bin/app از قبل وجود داشته باشد، check mode وضعیت Would not run command since '/opt/app/bin/app' exists را گزارش میدهد که یک پاسخ واقعی است. اگر مسیر وجود نداشته باشد، شما Command would have run if not in check mode را دریافت میکنید که آن هم یک پاسخ واقعی است. بدون creates، آن وظیفه در اجرای آزمایشی (dry run) شما یک فضای خالی باقی میماند.
اثر جانبی این موضوع بدتر از یک فضای خالی است. یک وظیفه command که نادیده گرفته شده، همچنان یک نتیجه ثبت میکند و آن نتیجه شامل stdout است، اما چون هیچ دستوری اجرا نشده، این رشته خالی است. شرط وظیفهٔ بعدی بر اساس آن رشته خالی ارزیابی میشود و بیسروصدا مسیر اشتباه را انتخاب میکند: یک بررسی نسخه، هیچ نسخهای پیدا نمیکند و تستی مانند 'active' in svc.stdout نادرست (false) از آب در میآید. پلیبوک شما در یک اجرای واقعی یک پاسخ و در اجرای آزمایشی پاسخی متفاوت میدهد، بدون اینکه خطایی برای اشاره به آن وجود داشته باشد؛ این گیجکنندهترین نوع شکست در کل این قابلیت است. خطای 'dict object' has no attribute 'stdout' به نوع متفاوتی از نادیدهگرفتن تعلق دارد: وظیفهای که به دلیل نادرست بودن when آن نادیده گرفته شده، نتیجهای ثبت میکند که اصلاً کلید stdout را ندارد.
check_mode: false و تنها جایی که به آن تعلق دارد
check_mode: false در یک task به معنای «اجرای واقعی، حتی تحت --check» است. این راهکار مشکل دستورات نادیده گرفتهشده (skipped) است و تنها برای taskهایی که عملیات خواندن انجام میدهند، ایمن است.
- name: Read the installed app version
ansible.builtin.command: /usr/local/bin/app --version
register: app_version
check_mode: false
changed_when: falseآن task در هر دو حالت صادقانه عمل میکند. این task یک نسخه را میخواند و هرگز چیزی نمینویسد؛ changed_when: false مانع از گزارش تغییراتی میشود که رخ ندادهاند و check_mode: false باعث میشود app_version.stdout در طول یک اجرای آزمایشی (dry run)، به جای رشته خالی، نسخه واقعی را نگه دارد تا شرطهای مبتنی بر آن همچنان بهدرستی ارزیابی شوند.
پیش از آنکه این کلمه کلیدی را در جای دیگری کپی کنید، معنای آن را دقیق درک کنید. یک task با check_mode: false در طول ansible-playbook --check روی سرورهای شما تغییراتی اعمال میکند. اگر آن را روی یک task از نوع apt یا template قرار دهید، اجرای آزمایشی شما مرتبتر به نظر میرسد، اما دیگر یک اجرای آزمایشی واقعی نخواهد بود. زمانی که نمیتوان یک taskِ دارای عملیات نوشتن را ایمن کرد، به جای آن از محافظ استفاده کنید:
- name: Apply the database migration
ansible.builtin.command: /usr/local/bin/app migrate --apply
when: not ansible_check_modeansible_check_mode یک متغیر جادویی است که Ansible در طول اجرای آزمایشی (check run) آن را روی true تنظیم میکند. کلمه کلیدی معکوس آن نیز وجود دارد. check_mode: true یک task را همیشه در حالت check mode قفل میکند، حتی در طول یک اجرای واقعی؛ این کار آن را به یک ابزار تشخیص انحراف (drift probe) تبدیل میکند: نتیجه را ثبت کنید، و یک گزارش changed به این معناست که وضعیت میزبان دیگر با آنچه task درخواست میکند، مطابقت ندارد.
چرا یک تسک در هر اجرا وضعیت changed را گزارش میدهد
پلیبوک را دو بار پشت سر هم و بدون هیچ تغییری در محیط اجرا کنید. در اجرای دوم، تمام تسکها باید وضعیت ok را گزارش دهند. هر تسکی که همچنان changed را گزارش میکند، یکی از دو مورد زیر را نشان میدهد: یا ماژول نمیتواند وضعیت فعلی منبعی که مدیریت میکند را تشخیص دهد، یا ورودیهایی که به آن میدهید پایدار نیستند. هر دو مورد قابلرفع هستند و هیچکدام نویز محسوب نمیشوند که بخواهید نادیدهشان بگیرید.
commandوshellبدونcreates،removesیاchanged_whenدر هر بار اجراchangedرا گزارش میدهند، زیرا ماژول راهی برای تشخیص اینکه آیا تغییری رخ داده است یا خیر ندارد. ازcreatesاستفاده کنید یاchanged_whenرا بر اساس یک رشته در خروجی تنظیم نمایید.ansible.builtin.fileباstate: touchطبق طراحی در هر اجراchangedرا گزارش میدهد، زیرا دستور touch کردن یک فایل، مُهر زمانی (timestamp) آن را بهروز میکند. اگر تنها هدف شما تنظیم مالک (owner) یا دسترسی (mode) فایل است، ازstate: fileاستفاده کنید.- یک
templateکه خروجی رندر شدهاش تغییر میکند، فایل را در هر اجرا بازنویسی میکند. وجود یک مُهر زمانی ازansible_date_time، فراخوانیnow()یا تولید رمز عبور جدید در هر بار اجرا، باعث ایجاد بایتهای متفاوت میشود و در نتیجه ماژول بهدرستی وضعیت تغییر را گزارش میدهد. مقادیر متغیر را از قالب (template) خارج کنید. ansible.builtin.userباpassword: "{{ pw | password_hash('sha512') }}"در هر اجرا تغییر میکند، زیراpassword_hashهر بار یک salt تصادفی انتخاب میکند و هش حاصل هرگز با هش موجود در/etc/shadowمطابقت پیدا نمیکند. یک salt صریح که از یک منبع پایدار مشتق شده است را به آن بدهید.state: latestدر یک ماژول پکیج، هر زمان که نسخه جدیدی در دسترس باشد،changedرا گزارش میدهد. این گزارش صادقانه است. به همین دلیل است کهstate: latestمنجر به پلیبوکی میشود که نتیجه آن قابل پیشبینی نیست. ازstate: presentاستفاده کنید و ارتقا را بهصورت آگاهانه انجام دهید.ansible.builtin.unarchiveکه به یک URL بدونcreatesاشاره دارد، در هر اجرا آرشیو را مجدداً دانلود میکند و برای انواع آرشیوهایی که نمیتواند با مقصد مقایسه کند، عملیات استخراج (unpack) را نیز دوباره انجام میدهد. یک مسیرcreatesبه آن بدهید.
--diff سریعترین راه برای تشخیص این موارد است. اگر تسک وضعیت changed را نشان میدهد و diff بایتهای متفاوتی را نمایش میدهد، ورودی شما ناپایدار است. اگر وضعیت changed را نشان میدهد و diff هیچ چیزی را نمایش نمیدهد، ماژول نمیتواند تغییرات خود را بیان کند که معمولاً به معنای یک تسک command یا نوشتن متاداده (مانند مُهر زمانی) است.
برای ساکت کردن یک تسک پرصدا، به سراغ changed_when: false نروید. این کار گزارش را سرکوب میکند، بنابراین notify هرگز فعال نمیشود و هندلری که سرویس را ریاستارت میکند اجرا نخواهد شد. در عوض، خودِ تسک را اصلاح کنید.
کاهش شعاع انفجار: --limit، --tags و --step
حالت Check mode به شما میگوید چه تغییراتی اعمال خواهد شد. این پرچمها تعیین میکنند که همزمان چند ماشین تحت تأثیر قرار بگیرند.
--limit اجرا را به زیرمجموعهای از inventory محدود میکند. این پرچم همان الگوهایی را میپذیرد که hosts: میپذیرد، بنابراین هر دو دستور --limit web1 و --limit 'webservers:!web3' کار میکنند. الگو را داخل کوتیشن قرار دهید. یک ! بدون کوتیشن در یک نشست تعاملی bash باعث گسترش تاریخچه روی علامت تعجب میشود و shell شما دستور را پیش از آنکه Ansible آن را ببیند، بازنویسی میکند.
پیش از اعتماد به الگو، آن را تأیید کنید. ansible-playbook site.yml --limit 'webservers:!web3' --list-hosts میزبانهای منطبق را چاپ کرده و بدون اتصال به هیچکدام از آنها خارج میشود. الگویی که با هیچچیز منطبق نشود ایمن است، زیرا Ansible به کل inventory بازنمیگردد. این ابزار هشداری مبنی بر عدم تطابق الگوی میزبان چاپ کرده و سپس با خطایی مبنی بر اینکه inventory، الگوی میزبان و --limit هیچ میزبانی را برای هدفگیری باقی نگذاشتهاند، خارج میشود. دانستن نحوه تعریف آن گروهها در فایل inventory همان چیزی است که باعث میشود یک الگو در وهله اول قابل پیشبینی باشد.
--tags deploy فقط تسکهای دارای تگ را اجرا میکند و --skip-tags packages هر چیز دیگری را اجرا میکند. --list-tags تگهای موجود را چاپ میکند. تگها زمانی ارزش خود را نشان میدهند که یک play از نقطهای فراتر رود که مایل باشید تمام آن را اجرا کنید؛ این موضوع همچنین یکی از دلایل تقسیم یک playbook طولانی به نقشها (roles) است.
--start-at-task "Write the site config" اجرای ناموفق را از یک تسک نامگذاریشده از سر میگیرد. از آن برای بازیابی استفاده کنید و هزینه آن را درک کنید: همه چیز پیش از آن تسک نادیده گرفته میشود، از جمله تسکهایی که فکتها را تنظیم کرده یا متغیرهایی را ثبت میکنند که تسکهای بعدی به آنها نیاز دارند.
--step پیش از هر تسک از شما پرسش میکند و منتظر میماند تا پاسخ yes، no یا continue بدهید. این کار کند است، اما برای اولین باری که یک عملیات مخرب را اجرا میکنید ابزار مناسبی است، زیرا میتوانید به جای توقف پس از بیست تسک، بین دو تسک متوقف شوید.
اعمال تغییرات با استفاده از serial
بهصورت پیشفرض، Ansible پیش از شروع تسک بعدی، یک تسک را روی تمام میزبانهای موجود در play اجرا میکند. این روش سریع است، اما باعث میشود یک تسک مخرب در همان ثانیه به کل ناوگان سرایت کند. تا زمانی که شما خطا را بخوانید و Ctrl-C را فشار دهید، تغییرات در همه جا اعمال شده است.
serial یک play را به دستههای کوچکتر تقسیم میکند. کل play ابتدا روی دسته اول اجرا میشود و سپس به سراغ دسته بعدی میرود.
- name: Roll out the web tier
hosts: webservers
serial: [1, 5, "30%"]
max_fail_percentage: 0
tasks:
- name: Deploy the release
ansible.builtin.include_role:
name: webappدسته اول شامل یک میزبان است. اگر آن میزبان با موفقیت عبور کند، دسته دوم شامل پنج میزبان خواهد بود و تمام دستههای بعدی شامل 30 درصد از کل میزبانهای play هستند. max_fail_percentage: 0 به محض شکست خوردن هر میزبان در یک دسته، بقیه play را متوقف میکند، زیرا آستانه خطا باید رعایت شود و هرگونه شکست، از حد مجاز صفر فراتر میرود. تضمینِ تست روی یک ماشین، از دسته اول ناشی میشود، نه از آن تنظیمات: نسخهای که همهجا را مختل میکند، در همان تکمیزبانِ دسته اول شکست میخورد و متوقف میشود. خطایی که فقط در دسته پنجتایی ظاهر میشود، قبلاً به سایر میزبانهای آن دسته سرایت کرده است، زیرا Ansible هر تسک را روی کل دسته اجرا میکند و سپس به تسک بعدی میرود. any_errors_fatal: true نسخه سختگیرانهتری است که با اولین شکست در یک میزبان، play را برای همه متوقف میکند.
اجرا کردن ابتدا روی یک میزبان، بدبینی نیست و دلیل مشخصی دارد. گروههای موجودی (Inventory groups) دچار انحراف میشوند. سروری که شش ماه پس از بقیه اضافه شده است، ممکن است نسخه توزیع متفاوتی داشته باشد، یا سرویسی داشته باشد که شخصی بهصورت دستی نصب کرده است، یا چیدمان دیسکهایش متفاوت باشد. playbook برای آن گروه درست است اما برای آن یک میزبان خاص اشتباه است، و هیچ اجرای آزمایشی (dry run) روی یک میزبان همگامسازیشده، این موضوع را نشان نخواهد داد. مدیریت ناوگانی از سرورهای لینوکس تا حد زیادی تمرینِ پیدا کردن آن میزبانِ متفاوت پیش از اعمال تغییرات است.
ترتیب اجرای عملیات
- دستور
ansible-playbook site.yml --syntax-checkخطاهای ساختاری و YAML را بدون نیاز به شبکه شناسایی میکند. - دستور
ansible-playbook site.yml --limit web1 --list-hostsتأیید میکند که الگوی شما دقیقاً با آنچه مد نظر دارید مطابقت دارد. - دستور
ansible-playbook site.yml --limit web1 --check --diffاجرای آزمایشی (dry run) است. خروجی diff را بررسی کنید. - دستور
ansible-playbook site.yml --limit web1 --diffتغییرات را روی همان یک میزبان اعمال میکند. - مرحله 4 را دوباره اجرا کنید. همه چیز باید وضعیت
okرا گزارش دهد. هر موردی که همچنانchangedباشد، وظیفهای است که باید پیش از اعمال تغییرات روی کل ناوگان، اصلاح شود. - دستور
ansible-playbook site.yml --check --diffاکنون در کل inventory پاسخ معناداری ارائه میدهد، زیرا میزبانهای همگراشده (converged) ساکت هستند و آنچه باقی میماند، دلتای واقعی است.
یک هشدار درباره مرحله 3: دستور --diff محتوای فایلها را در ترمینال و لاگ CI شما چاپ میکند؛ بنابراین قالبی که رمز عبور دیتابیس را رندر میکند، آن رمز را در لاگ نیز نمایش میدهد. برای جلوگیری از این خروجی، گزینه diff: false را روی آن task تنظیم کنید یا از no_log: true برای مخفیسازی کامل نتیجه استفاده نمایید. همچنین مقدار اصلی را به جای مخزن کد، در یک فایل رمزنگاریشده Ansible Vault نگهداری کنید.
FAQ
آیا اجرای ansible-playbook --check تغییری در سرور ایجاد میکند؟
خیر، با یک استثنا که کنترل آن در دست شماست. در حالت check mode، از هر ماژول خواسته میشود بهجای اعمال تغییرات، فقط گزارش دهد؛ ماژولهایی که قادر به این کار نیستند، هیچ کاری انجام نمیدهند و چیزی گزارش نمیکنند. استثنای این مورد، کلمه کلیدی check_mode: false در تسک است که باعث میشود آن تسک خاص حتی در حین اجرای --check نیز بهطور واقعی اجرا شود. پیش از اعتماد به یک اجرای آزمایشی (dry run)، در پلیبوکها و نقشهای خود عبارت check_mode: false را جستجو کنید و مطمئن شوید هر مورد یافتشده، تسکی است که فقط وضعیت را میخواند.
تفاوت بین --check و --diff چیست؟
--check تعیین میکند که آیا تغییری بهصورت واقعی اعمال شود یا خیر. --diff تعیین میکند که چه میزان جزئیات مشاهده کنید. استفاده از --check بهتنهایی به شما میگوید که یک فایل تغییر خواهد کرد. استفاده از --diff بهتنهایی تغییر را اعمال کرده و خطوط تغییریافته را به شما نشان میدهد. برای یک اجرای آزمایشی که بتوانید آن را بهدرستی بخوانید، این دو را با هم به کار ببرید و برای اجراهای واقعی نیز با تنظیم always = true در بخش [diff] در فایل ansible.cfg، گزینه --diff را همیشه فعال نگه دارید.
چرا تسک Ansible من در هر بار اجرا، وضعیت changed را گزارش میدهد؟
به این دلیل که ماژول نمیتواند وضعیتی که مدیریت میکند را تشخیص دهد، یا مقداری که به آن میدهید هر بار متفاوت است. ماژولهای command و shell همیشه وضعیت changed را گزارش میکنند، مگر اینکه creates یا changed_when را به آنها اضافه کنید. ماژول file همراه با state: touch طبق طراحی، همیشه تغییر ایجاد میکند. قالبی (template) که یک timestamp یا رمز عبور تازه تولید میکند، در هر بار اجرا بایتهای متفاوتی تولید میکند، بنابراین فایل واقعاً بازنویسی میشود. پلیبوک را دو بار پشت سر هم اجرا کنید: هر تسکی که در اجرای دوم همچنان changed گزارش میشود، همان تسکی است که نیاز به اصلاح دارد.
چرا تسکهای command و shell من در حین اجرای آزمایشی (dry run) نادیده گرفته میشوند؟
به این دلیل که هیچ روش "فقط خواندنی" برای اجرای یک دستور دلخواه وجود ندارد. در حالت check mode، ماژول command وضعیت skipped: true را با پیام Command would have run if not in check mode تنظیم میکند. از creates یا removes استفاده کنید تا حالت check mode بتواند بهجای آن، تست فایل را ارزیابی کند. برای تسکی که فقط وضعیت را میخواند، check_mode: false را همراه با changed_when: false تنظیم کنید تا نتیجه ثبتشده (registered result) در حین اجرای آزمایشی، خروجی واقعی را نگه دارد و شرطهای مبتنی بر آن همچنان کار کنند.
چرا حالت check mode روی یک سرور جدید با خطا مواجه میشود اما روی سرور موجود موفق است؟
به این دلیل که حالت check mode وضعیتی که تسکهای بعدی به آن وابستهاند را ایجاد نمیکند. اجرای آزمایشی روی میزبانی که nginx ندارد، نصب را changed گزارش میکند و سپس در تسکی که در مسیر /etc/nginx/conf.d/ مینویسد با خطا مواجه میشود، زیرا آن دایرکتوری هرگز ایجاد نشده است. این رفتار مورد انتظار است. حالت check mode ابزاری برای تشخیص انحراف (drift) در میزبانهایی است که پلیبوک قبلاً روی آنها همگرا شده است. این حالت نمیتواند اجرای اول را اعتبارسنجی کند. روی یک میزبان جدید، پلیبوک را روی یک ماشین اعمال کنید و نتیجه را در اجرای دوم بررسی کنید.