اصول اولیه ای که بدون آن کتاب های بازی شما یک تکه ماکارونی چسبناک خواهند بود

من بررسی های زیادی روی کد Ansible دیگران انجام می دهم و خودم خیلی می نویسم. در جریان تجزیه و تحلیل اشتباهات (هم اشتباهات دیگران و هم اشتباهات من) و همچنین تعدادی از مصاحبه ها، متوجه اشتباه اصلی کاربران Ansible شدم - آنها بدون تسلط بر موارد اساسی وارد چیزهای پیچیده می شوند.

برای اصلاح این بی عدالتی جهانی، تصمیم گرفتم مقدمه ای بر Ansible برای کسانی که قبلاً آن را می دانند بنویسم. من به شما هشدار می دهم، این بازگویی انسان نیست، این یک داستان قدیمی با حروف زیاد و بدون عکس است.

سطح مورد انتظار خواننده این است که چندین هزار خط یاملا قبلاً نوشته شده است، چیزی در حال تولید است، اما "به نوعی همه چیز کج است."

عنوان ها

اشتباه اصلی یک کاربر Ansible این است که نمی داند نام چیزی چیست. اگر اسامی را ندانید، نمی توانید بفهمید که اسناد چه می گوید. یک مثال زنده: در طول مصاحبه، شخصی که به نظر می‌رسید می‌گوید که در Ansible زیاد نوشته است، نمی‌تواند به این سؤال پاسخ دهد که "یک کتاب بازی از چه عناصری تشکیل شده است؟" و وقتی پیشنهاد دادم که «انتظار می‌رفت پاسخ این بود که کتاب بازی از بازی تشکیل شده است»، اظهار نظر نفرین‌آمیز «ما از آن استفاده نمی‌کنیم» دنبال شد. مردم برای پول Ansible می نویسند و از بازی استفاده نمی کنند. آنها در واقع از آن استفاده می کنند، اما نمی دانند چیست.

پس بیایید با یک چیز ساده شروع کنیم: نام آن چیست. شاید شما این را می دانید یا شاید هم نمی دانید، زیرا هنگام خواندن اسناد به آن توجه نکرده اید.

ansible-playbook playbook را اجرا می کند. playbook فایلی با پسوند yml/yaml است که داخل آن چیزی شبیه به این وجود دارد:

---
- hosts: group1
  roles:
    - role1

- hosts: group2,group3
  tasks:
    - debug:

ما قبلا متوجه شدیم که کل این فایل یک کتاب بازی است. ما می توانیم نشان دهیم که نقش ها کجا هستند و وظایف کجا هستند. اما بازی کجاست؟ و تفاوت بین بازی و نقش یا کتاب بازی چیست؟

همه اینها در اسناد موجود است. و دلشون تنگ میشه مبتدیان - زیرا خیلی زیاد است و همه چیز را به یکباره به خاطر نمی آورید. با تجربه - زیرا "چیزهای بی اهمیت". اگر باتجربه هستید، حداقل هر شش ماه یک بار این صفحات را دوباره بخوانید، کد شما در کلاس پیشرو خواهد بود.

بنابراین، به یاد داشته باشید: Playbook لیستی است که از بازی و import_playbook.
این یک نمایشنامه است:

- hosts: group1
  roles:
    - role1

و این هم یک نمایشنامه دیگر:

- hosts: group2,group3
  tasks:
    - debug:

بازی چیست؟ او چرا؟

بازی یک عنصر کلیدی برای یک کتاب بازی است، زیرا بازی و فقط بازی، فهرستی از نقش‌ها و/یا وظایف را با فهرستی از میزبان‌ها مرتبط می‌کند که باید روی آن‌ها اجرا شوند. در اعماق اسناد می توانید اشاره ای به آن پیدا کنید delegate_to، پلاگین های جستجوی محلی، تنظیمات خاص شبکه، میزبان های پرش و غیره. آنها به شما امکان می دهند مکان انجام وظایف را کمی تغییر دهید. اما، آن را فراموش کنید. هر یک از این گزینه های هوشمندانه کاربردهای بسیار خاصی دارند و قطعا جهانی نیستند. و ما در مورد چیزهای اساسی صحبت می کنیم که همه باید بدانند و استفاده کنند.

اگر می خواهید «چیزی» را «جایی» اجرا کنید، می نویسید بازی. نقش نیست. نه نقشی با ماژول ها و نمایندگان. شما آن را بگیرید و بنویسید بازی. که در آن، در قسمت میزبان، مکان اجرا و در نقش‌ها/وظایف - چه چیزی را باید اجرا کنید، فهرست می‌کنید.

ساده است، درست است؟ چگونه می تواند غیر از این باشد؟

یکی از لحظات مشخصی که افراد تمایل دارند این کار را نه از طریق بازی انجام دهند، «نقشی است که همه چیز را تنظیم می کند». من می خواهم نقشی داشته باشم که هم سرورهای نوع اول و هم سرورهای نوع دوم را پیکربندی کند.

یک مثال کهن الگویی، نظارت است. من می خواهم یک نقش نظارتی داشته باشم که نظارت را پیکربندی کند. نقش نظارت به میزبان های نظارت (بر اساس بازی) اختصاص داده شده است. اما معلوم می شود که برای نظارت باید بسته هایی را به هاست هایی که در حال نظارت هستیم تحویل دهیم. چرا از delegate استفاده نمی کنید؟ همچنین باید iptables را پیکربندی کنید. نماینده؟ همچنین باید یک پیکربندی برای DBMS بنویسید/تصحیح کنید تا نظارت را فعال کند. نماینده! و اگر خلاقیت کم است، می توانید هیئتی را تشکیل دهید include_role در یک حلقه تودرتو با استفاده از یک فیلتر پیچیده در لیستی از گروه ها و در داخل include_role شما می توانید بیشتر انجام دهید delegate_to از نو. و ما می رویم...

یک آرزوی خوب - داشتن یک نقش نظارتی واحد، که "همه کار را انجام می دهد" - ما را به جهنمی کامل هدایت می کند که اغلب تنها یک راه از آن وجود دارد: بازنویسی همه چیز از ابتدا.

اشتباه اینجا کجا بود؟ لحظه ای که متوجه شدید برای انجام وظیفه "x" در میزبان X باید به میزبان Y بروید و "y" را در آنجا انجام دهید، باید یک تمرین ساده را انجام دهید: بروید و play بنویسید، که در میزبان Y y را انجام می دهد. چیزی به "x" اضافه نکنید، بلکه آن را از ابتدا بنویسید. حتی با متغیرهای کدگذاری شده.

به نظر می رسد همه چیز در پاراگراف های بالا به درستی گفته شده است. اما این مورد شما نیست! زیرا می خواهید کدهای قابل استفاده مجدد بنویسید که DRY و کتابخانه مانند است و باید به دنبال روشی برای انجام آن باشید.

اینجاست که یک اشتباه جدی دیگر در کمین است. خطایی که بسیاری از پروژه‌ها را از نوشتن قابل تحمل (می‌توانست بهتر باشد، اما همه چیز کار می‌کند و به راحتی تمام می‌شود) را به یک وحشت کامل تبدیل کرد که حتی نویسنده هم نمی‌تواند آن را بفهمد. کار میکنه ولی خدا نکنه چیزی رو عوض کنی.

خطا این است: نقش یک تابع کتابخانه است. این قیاس آنقدر آغازهای خوب را خراب کرده است که تماشای آن غم انگیز است. نقش یک تابع کتابخانه نیست. او نمی تواند محاسبات انجام دهد و نمی تواند در سطح بازی تصمیم بگیرد. به من یادآوری کن که بازی چه تصمیماتی می گیرد؟

ممنون، حق با شماست. Play تصمیم می‌گیرد (به طور دقیق‌تر، حاوی اطلاعاتی است) در مورد وظایف و نقش‌هایی که در کدام میزبان انجام شود.

اگر این تصمیم را به نقشی بسپارید، و حتی با محاسبات، خود (و کسی که سعی می کند کد شما را تجزیه کند) را به یک وجود بدبخت محکوم می کنید. نقش تعیین نمی کند که کجا اجرا شود. این تصمیم با بازی گرفته می شود. نقش همان چیزی را که گفته می شود انجام می دهد، جایی که گفته می شود.

چرا برنامه نویسی در Ansible خطرناک است و چرا COBOL بهتر از Ansible است، در این فصل در مورد متغیرها و jinja صحبت خواهیم کرد. در حال حاضر، بیایید یک چیز بگوییم - هر یک از محاسبات شما ردی از تغییرات در متغیرهای سراسری به جا می گذارد و شما نمی توانید کاری در مورد آن انجام دهید. به محض اینکه این دو "رد" قطع شد، همه چیز از بین رفت.

توجه داشته باشید برای squeamish: نقش قطعا می تواند بر جریان کنترل تاثیر بگذارد. بخور delegate_to و کاربردهای معقولی دارد. بخور meta: end host/play. ولی! یادتان هست که ما اصول را آموزش می دهیم؟ فراموش کرده در مورد delegate_to. ما در مورد ساده ترین و زیباترین کد Ansible صحبت می کنیم. که خواندن آن آسان، نوشتن آسان، اشکال زدایی آسان، آزمایش آسان و تکمیل آسان است. بنابراین، یک بار دیگر:

بازی کنید و فقط بازی تصمیم می‌گیرد که چه میزبانی اجرا شود.

در این قسمت به تقابل بازی و نقش پرداختیم. حالا بیایید در مورد رابطه وظایف در مقابل نقش صحبت کنیم.

وظایف و نقش ها

بازی را در نظر بگیرید:

- hosts: somegroup
  pre_tasks:
    - some_tasks1:
  roles:
     - role1
     - role2
  post_tasks:
     - some_task2:
     - some_task3:

بیایید بگوییم که شما نیاز به انجام این کار دارید. و به نظر می رسد foo: name=foobar state=present. کجا باید این را بنویسم؟ در قبل؟ پست؟ نقش بسازید؟

...و وظایف به کجا رسید؟

ما دوباره با اصول اولیه شروع می کنیم - دستگاه پخش. اگر روی این موضوع شناور باشید، نمی توانید از بازی به عنوان مبنایی برای بقیه چیزها استفاده کنید و نتیجه شما "متزلزل" خواهد بود.

دستگاه پخش: دستور میزبان، تنظیمات مربوط به خود بازی و قسمت‌های پیش وظایف، وظایف، نقش‌ها، بخش‌های post_tasks. پارامترهای باقی مانده برای بازی اکنون برای ما مهم نیستند.

ترتیب بخش های آنها با وظایف و نقش ها: pre_tasks, roles, tasks, post_tasks. از آنجایی که از نظر معنایی ترتیب اجرا بین tasks и roles واضح نیست، سپس بهترین روش ها می گوید که ما در حال اضافه کردن یک بخش هستیم tasks، فقط اگر نه roles... اگر وجود دارد roles، سپس تمام وظایف پیوست شده در بخش ها قرار می گیرند pre_tasks/post_tasks.

تنها چیزی که باقی می ماند این است که همه چیز از نظر معنایی روشن است: اول pre_tasksسپس rolesسپس post_tasks.

اما هنوز به این سوال پاسخ نداده ایم: فراخوانی ماژول کجاست؟ foo نوشتن؟ آیا لازم است برای هر ماژول یک نقش کامل بنویسیم؟ یا بهتر است برای همه چیز نقش قطور داشته باشیم؟ و اگر نقش نیست، پس کجا باید بنویسم - قبل یا پست؟

اگر پاسخ مستدلی برای این سؤالات وجود نداشته باشد، پس این نشانه فقدان شهود است، یعنی همان «پایه های متزلزل». بیایید آن را بفهمیم. اول، یک سوال امنیتی: اگر بازی دارد pre_tasks и post_tasks (و هیچ کار یا نقشی وجود ندارد)، اگر من اولین وظیفه را از آن انجام دهم، ممکن است چیزی خراب شود post_tasks من آن را به آخر منتقل می کنم pre_tasks?

البته جمله بندی سوال حکایت از شکسته شدن آن دارد. اما دقیقا چی؟

... هندلرها. خواندن اصول اولیه یک واقعیت مهم را آشکار می کند: همه کنترل کننده ها پس از هر بخش به طور خودکار شستشو می شوند. آن ها تمام وظایف از pre_tasks، سپس به همه گردانندگانی که مطلع شدند. سپس تمام نقش‌ها و همه گرداننده‌هایی که در نقش‌ها مطلع شده‌اند اجرا می‌شوند. بعد از post_tasks و گردانندگان آنها

بنابراین، اگر یک کار را از آن بکشید post_tasks в pre_tasks، سپس به طور بالقوه آن را قبل از اجرای کنترل کننده اجرا خواهید کرد. به عنوان مثال، اگر در pre_tasks وب سرور نصب و پیکربندی شده است و post_tasks چیزی به آن ارسال می شود، سپس این وظیفه را به بخش منتقل کنید pre_tasks منجر به این واقعیت می شود که در زمان "ارسال" سرور هنوز کار نمی کند و همه چیز خراب می شود.

حالا بیایید دوباره فکر کنیم، چرا ما نیاز داریم pre_tasks и post_tasks? به عنوان مثال، به منظور تکمیل همه چیز لازم (از جمله کنترل کننده ها) قبل از ایفای نقش. آ post_tasks به ما اجازه می دهد تا با نتایج اجرای نقش ها (از جمله کنترل کننده ها) کار کنیم.

یک متخصص زیرک Ansible به ما می گوید که چیست. meta: flush_handlers، اما اگر بتوانیم به ترتیب اجرای بخش ها در بازی تکیه کنیم، چرا به flush_handler نیاز داریم؟ علاوه بر این، استفاده از متا: flush_handlers می‌تواند چیزهای غیرمنتظره‌ای را با کنترل‌کننده‌های تکراری به ما بدهد و هنگام استفاده هشدارهای عجیبی به ما بدهد. when у block و غیره. هر چه انحراف را بهتر بشناسید، نکات ظریف بیشتری را می توانید برای راه حل «مشکل» نام ببرید. و یک راه حل ساده - استفاده از یک تقسیم طبیعی بین قبل / نقش / پس - باعث ایجاد تفاوت های ظریف نمی شود.

و برگردیم به "فو" ما. کجا باید بذارمش؟ در قبل، پست یا نقش؟ بدیهی است که این بستگی به این دارد که آیا ما به نتایج کنترل کننده برای foo نیاز داریم یا خیر. اگر آنها وجود ندارند، پس نیازی به قرار دادن foo در پیش یا پس نیست - این بخش ها معنای خاصی دارند - اجرای وظایف قبل و بعد از بدنه اصلی کد.

اکنون پاسخ به سؤال "نقش یا وظیفه" به آنچه قبلاً در حال انجام است خلاصه می شود - اگر وظایفی در آنجا وجود دارد ، باید آنها را به وظایف اضافه کنید. اگر نقش هایی وجود دارد، باید یک نقش (حتی از یک کار) ایجاد کنید. اجازه دهید به شما یادآوری کنم که وظایف و نقش ها به طور همزمان مورد استفاده قرار نمی گیرند.

درک اصول اولیه Ansible پاسخ های معقولی به سؤالات ظاهراً سلیقه ای ارائه می دهد.

وظایف و نقش ها (قسمت دوم)

حالا بیایید در مورد وضعیت زمانی که شما تازه شروع به نوشتن یک کتاب بازی کرده اید بحث کنیم. باید غذا، بار و باز درست کنید. آیا این سه وظیفه، یک نقش هستند یا سه نقش؟ برای خلاصه کردن این سوال: از چه نقطه ای باید نوشتن نقش ها را شروع کنید؟ وقتی می توانی وظایف بنویسی چه فایده ای دارد نقش نویسی؟... نقش چیست؟

یکی از بزرگترین اشتباهات (من قبلاً در مورد آن صحبت کردم) این است که فکر کنید یک نقش مانند یک تابع در کتابخانه یک برنامه است. شرح عملکرد عمومی چگونه است؟ آرگومان های ورودی را می پذیرد، با علل جانبی تعامل می کند، عوارض جانبی را انجام می دهد و مقداری را برمی گرداند.

حالا توجه از این در نقش چه می توان کرد؟ شما همیشه می توانید عوارض جانبی را نام ببرید، این جوهر کل Ansible است - ایجاد عوارض جانبی. دلایل جانبی دارد؟ ابتدایی. اما با "یک مقدار ارسال کنید و آن را برگردانید" - اینجاست که کار نمی کند. اول اینکه شما نمی توانید به یک نقش ارزش بدهید. می توانید یک متغیر سراسری با اندازه مادام العمر بازی در بخش vars برای نقش تنظیم کنید. می‌توانید یک متغیر سراسری با یک عمر بازی در داخل نقش تنظیم کنید. یا حتی با طول عمر کتاب های بازی (set_fact/register). اما شما نمی توانید "متغیرهای محلی" داشته باشید. شما نمی توانید "یک ارزش را بگیرید" و "آن را برگردانید".

نکته اصلی از این نتیجه می شود: شما نمی توانید چیزی را در Ansible بدون ایجاد عوارض جانبی بنویسید. تغییر متغیرهای سراسری همیشه یک اثر جانبی برای یک تابع است. به عنوان مثال، در Rust، تغییر یک متغیر جهانی است unsafe. و در Ansible این تنها روشی است که بر مقادیر یک نقش تأثیر می گذارد. به کلمات استفاده شده توجه کنید: نه "ارسال یک مقدار به نقش"، بلکه "تغییر مقادیری که نقش استفاده می کند". هیچ جدایی بین نقش ها وجود ندارد. هیچ جدایی بین وظایف و نقش ها وجود ندارد.

مجموع: نقش یک کارکرد نیست.

چه چیزی در مورد نقش خوب است؟ ابتدا، نقش دارای مقادیر پیش فرض است (/default/main.yaml) ثانیاً، نقش دارای دایرکتوری های اضافی برای ذخیره فایل ها است.

مزایای مقادیر پیش فرض چیست؟ از آنجایی که در هرم مزلو، جدول نسبتاً تحریف شده اولویت‌های متغیر Ansible، پیش‌فرض‌های نقش کمترین اولویت را دارند (منهای پارامترهای خط فرمان Ansible). این بدان معناست که اگر نیاز به ارائه مقادیر پیش‌فرض دارید و نگران نباشید که ارزش‌های موجودی یا متغیرهای گروه را لغو کنند، پیش‌فرض‌های نقش تنها مکان مناسب برای شما هستند. (کمی دروغ می گویم - موارد بیشتری وجود دارد |d(your_default_here)، اما اگر در مورد مکان های ثابت صحبت کنیم، فقط نقش پیش فرض است).

چه چیز دیگری در مورد نقش ها عالی است؟ زیرا آنها کاتالوگ خود را دارند. اینها دایرکتوری هایی برای متغیرها هستند، هم ثابت (یعنی برای نقش محاسبه شده) و هم پویا (یک الگو یا یک ضد الگو وجود دارد - include_vars با {{ ansible_distribution }}-{{ ansible_distribution_major_version }}.yml.). این دایرکتوری ها برای files/, templates/. همچنین، به شما امکان می دهد ماژول ها و پلاگین های خود را داشته باشید (library/). اما، در مقایسه با وظایف موجود در یک کتاب بازی (که می تواند همه اینها را نیز داشته باشد)، تنها مزیت اینجا این است که فایل ها در یک شمع ریخته نمی شوند، بلکه چندین شمع جداگانه ریخته می شوند.

یک جزئیات دیگر: می توانید سعی کنید نقش هایی ایجاد کنید که برای استفاده مجدد (از طریق کهکشان) در دسترس باشند. با ظهور مجموعه ها، توزیع نقش را می توان تقریباً فراموش شده در نظر گرفت.

بنابراین، نقش‌ها دو ویژگی مهم دارند: آنها دارای پیش‌فرض هستند (یک ویژگی منحصر به فرد) و به شما امکان می‌دهند کد خود را ساختار دهید.

بازگشت به سوال اصلی: چه زمانی وظایف را انجام دهیم و چه زمانی نقش ها را انجام دهیم؟ وظایف در یک کتاب بازی اغلب به عنوان "چسب" قبل یا بعد از نقش ها یا به عنوان یک عنصر سازنده مستقل استفاده می شود (پس نباید هیچ نقشی در کد وجود داشته باشد). انبوهی از وظایف معمولی که با نقش ها آمیخته شده اند، شلختگی بی ابهام است. شما باید به یک سبک خاص پایبند باشید - یا یک وظیفه یا یک نقش. نقش ها جداسازی موجودیت ها و پیش فرض ها را فراهم می کنند، وظایف به شما امکان می دهد کد را سریعتر بخوانید. معمولاً کدهای ثابت (مهم و پیچیده) بیشتری در نقش ها قرار می گیرند و اسکریپت های کمکی به سبک وظیفه نوشته می شوند.

انجام import_role به عنوان یک کار امکان پذیر است، اما اگر این را می نویسید، آماده باشید تا به حس زیبایی خود توضیح دهید که چرا می خواهید این کار را انجام دهید.

یک خواننده زیرک ممکن است بگوید که نقش ها می توانند نقش ها را وارد کنند، نقش ها می توانند وابستگی هایی از طریق galaxy.yml داشته باشند، و همچنین یک چیز وحشتناک و وحشتناک وجود دارد. include_role - به شما یادآوری می‌کنم که ما در حال بهبود مهارت‌ها در Ansible اولیه هستیم و نه در ژیمناستیک فیگور.

گردانندگان و وظایف

بیایید یک چیز واضح دیگر را مورد بحث قرار دهیم: کنترل کننده ها. دانستن نحوه استفاده صحیح از آنها تقریباً یک هنر است. تفاوت بین هندلر و درگ چیست؟

از آنجایی که ما اصول اولیه را به خاطر می آوریم، در اینجا یک مثال آورده شده است:

- hosts: group1
  tasks:
    - foo:
      notify: handler1
  handlers:
     - name: handler1
       bar:

کنترلرهای نقش در rolename/handlers/main.yaml قرار دارند. کنترل‌کننده‌ها بین همه شرکت‌کنندگان در بازی جست‌وجو می‌کنند: کارهای قبل/پس از_تکلیف می‌تواند کنترل‌کننده‌های نقش را بکشد، و یک نقش می‌تواند کنترل‌کننده‌ها را از بازی بیرون بکشد. با این حال، فراخوانی‌های «مقطعی» به کنترل‌کننده‌ها باعث ایجاد wtf بسیار بیشتری نسبت به تکرار یک کنترل‌کننده بی‌اهمیت می‌شود. (یکی دیگر از عناصر بهترین شیوه ها این است که سعی کنید نام های کنترل کننده را تکرار نکنید).

تفاوت اصلی در این است که وظیفه همیشه (بدون توان) اجرا می شود (تگ های به علاوه/منهای و when، و کنترل کننده - با تغییر وضعیت (فقط در صورت تغییر آتش سوزی را مطلع کنید). این یعنی چی؟ به عنوان مثال، این واقعیت است که هنگامی که شما راه اندازی مجدد، اگر هیچ تغییری وجود ندارد، دیگر وجود نخواهد داشت. چرا ممکن است زمانی که هیچ تغییری در وظیفه تولید وجود ندارد، نیاز به اجرای کنترلر داشته باشیم؟ به عنوان مثال، به این دلیل که چیزی شکست و تغییر کرد، اما اجرا به دست گیرنده نرسید. به عنوان مثال، به دلیل قطع موقت شبکه. پیکربندی تغییر کرده است، سرویس راه اندازی مجدد نشده است. دفعه بعد که آن را شروع می کنید، پیکربندی دیگر تغییر نمی کند و سرویس با نسخه قدیمی پیکربندی باقی می ماند.

وضعیت پیکربندی قابل حل نیست (به طور دقیق تر، می توانید یک پروتکل راه اندازی مجدد ویژه با پرچم های فایل و غیره برای خود اختراع کنید، اما این دیگر به هیچ شکلی "پایه ای" نیست). اما یک داستان رایج دیگر وجود دارد: ما برنامه را نصب کردیم، آن را ضبط کردیم .service-file، و اکنون ما آن را می خواهیم daemon_reload и state=started. و مکان طبیعی برای این به نظر می رسد که کنترل کننده است. اما اگر آن را نه یک کنترلر، بلکه به عنوان یک وظیفه در انتهای یک لیست کاری یا نقش تبدیل کنید، آنگاه هر بار به صورت ناتوان اجرا می شود. حتی اگر کتاب بازی از وسط خراب شد. این به هیچ وجه مشکل راه‌اندازی مجدد را حل نمی‌کند (شما نمی‌توانید کاری را با ویژگی راه‌اندازی مجدد انجام دهید، زیرا idempotency از بین می‌رود)، اما قطعاً ارزش آن را دارد که state=started را انجام دهید، پایداری کلی کتاب‌های بازی افزایش می‌یابد، زیرا تعداد اتصالات و حالت پویا کاهش می یابد.

یکی دیگر از ویژگی های مثبت هندلر این است که خروجی را مسدود نمی کند. هیچ تغییری وجود نداشت - بدون حذف اضافی یا خوب در خروجی - خواندن آسان تر است. همچنین یک ویژگی منفی است - اگر در اولین اجرای یک کار خطی یک اشتباه تایپی پیدا کردید، کنترل کننده ها فقط در صورت تغییر اجرا می شوند، یعنی. تحت برخی شرایط - بسیار به ندرت. مثلاً برای اولین بار در زندگی من پنج سال بعد. و البته در نام اشتباه تایپی خواهد بود و همه چیز خراب می شود. و اگر بار دوم آنها را اجرا نکنید، تغییری ایجاد نمی شود.

به طور جداگانه، ما باید در مورد در دسترس بودن متغیرها صحبت کنیم. به عنوان مثال، اگر یک کار را با یک حلقه اعلان کنید، چه چیزی در متغیرها خواهد بود؟ شما می توانید به صورت تحلیلی حدس بزنید، اما همیشه بی اهمیت نیست، به خصوص اگر متغیرها از مکان های مختلف آمده باشند.

... بنابراین هندلرها بسیار کمتر از آنچه به نظر می رسد مفید هستند و بسیار مشکل ساز هستند. اگر می‌توانید چیزی را به زیبایی (بدون زواید) بدون کنترل‌کننده بنویسید، بهتر است آن را بدون آنها انجام دهید. اگر به زیبایی کار نمی کند، با آنها بهتر است.

خواننده خورنده به درستی اشاره می کند که ما بحث نکرده ایم listenکه یک handler می‌تواند برای handler دیگری با notify تماس بگیرد، که یک handler می‌تواند import_tasks را شامل شود (که می‌تواند include_role را با with_items انجام دهد)، که سیستم کنترل‌کننده در Ansible Turing-complete است، که کنترل‌کننده‌های include_role به روشی عجیب با handler‌های بازی تلاقی می‌کنند. و غیره .d. - همه اینها به وضوح "اصول" نیست).

اگرچه یک WTF خاص وجود دارد که در واقع یک ویژگی است که باید در نظر داشته باشید. اگر وظیفه شما با delegate_to و اعلان کرده است، سپس کنترل کننده مربوطه بدون آن اجرا می شود delegate_to، یعنی در میزبانی که بازی در آن اختصاص داده شده است. (البته کنترل کننده ممکن است داشته باشد delegate_to یکسان).

به طور جداگانه، می خواهم چند کلمه در مورد نقش های قابل استفاده مجدد بگویم. قبل از اینکه مجموعه ها ظاهر شوند، این ایده وجود داشت که می توانید نقش های جهانی بسازید که می تواند باشد ansible-galaxy install و رفت در همه شرایط در همه سیستم عامل ها از همه انواع کار می کند. بنابراین، نظر من: این کار نمی کند. هر نقش با جرم include_varsبا پشتیبانی از 100500 کیس، محکوم به ورطه باگ های گوشه ای است. آنها را می توان با آزمایش گسترده پوشش داد، اما مانند هر آزمایش دیگری، یا شما یک محصول دکارتی از مقادیر ورودی و یک تابع کل دارید، یا "سناریوهای فردی تحت پوشش" دارید. نظر من این است که اگر نقش خطی باشد (پیچیدگی سیکلوماتیک 1) خیلی بهتر است.

اگرهای کمتر (صریح یا اعلانی - در فرم when یا فرم include_vars با مجموعه ای از متغیرها)، نقش بهتر است. گاهی اوقات باید شاخه درست کرد، اما، تکرار می کنم، هر چه تعداد آنها کمتر باشد، بهتر است. بنابراین به نظر می رسد یک نقش خوب با کهکشان (این کار می کند!) با یک دسته از when ممکن است نسبت به نقش "خود" از پنج وظیفه کمتر ارجحیت داشته باشد. لحظه ای که نقش با کهکشان بهتر است، زمانی است که شروع به نوشتن چیزی می کنید. لحظه ای که بدتر می شود زمانی است که چیزی می شکند و شما مشکوک می شوید که این به دلیل "نقش با کهکشان" است. شما آن را باز می کنید، و پنج بخش، هشت برگه وظیفه و یک پشته وجود دارد when'ov... و ما باید این را بفهمیم. به جای 5 کار، یک لیست خطی که در آن چیزی برای شکستن وجود ندارد.

در قسمت های بعدی

  • کمی در مورد موجودی، متغیرهای گروه، افزونه host_group_vars، hostvars. چگونه گره گوردین را با اسپاگتی ببندیم. متغیرهای دامنه و تقدم، مدل حافظه Ansible. "پس نام کاربری پایگاه داده را کجا ذخیره کنیم؟"
  • jinja: {{ jinja }} — پلاستیکین نرم nosql notype nosense. همه جا هست، حتی جایی که انتظارش را ندارید. کمی در مورد !!unsafe و یامل خوشمزه

منبع: www.habr.com

اضافه کردن نظر