حالت تاریک
فصل ۱۱ — ساخت سرورها بهصورت کد
Infrastructure as Code ابتدا بهعنوان روشی برای پیکربندی سرورها ظهور کرد. مدیران سیستم shell، batch و اسکریپت Perl مینوشتند. CFEngine استفاده از DSLهای declarative و idempotent برای نصب بستهها و مدیریت فایلهای پیکربندی روی سرورها را پیشگام کرد، و Puppet و Chef دنبال کردند. این ابزارها فرض میکردند با سرور موجود شروع میکنید — اغلب سرور فیزیکی در rack، گاهی ماشین مجازی با VMware، و بعدتر instance ابری.
اکنون یا روی پشتههای زیرساختی تمرکز داریم که سرورها فقط بخشی از آناند، یا با کلاسترهای کانتینر کار میکنیم که سرورها جزئی زیرین هستند.
اما سرورها هنوز بخش ضروری بیشتر محیطهای زمان اجرای برنامه هستند. بیشتر سیستمهایی که بیش از چند سال قدمت دارند حداقل بخشی از برنامهها را روی سرور اجرا میکنند. حتی تیمهایی که کلاستر اجرا میکنند معمولاً باید سرورها را برای host nodeها بسازند و اجرا کنند.
سرورها از انواع دیگر زیرساخت مثل شبکه و ذخیرهسازی پیچیدهترند. قطعات و تنوع بیشتری دارند، پس بیشتر تیمهای سیستم هنوز زمان زیادی را در سیستمعامل، بستهها و فایلهای پیکربندی سپری میکنند.
این فصل رویکردهای ساخت و مدیریت پیکربندی سرور بهصورت کد را توضیح میدهد. با محتوای سرورها (چه چیزهایی باید پیکربندی شوند) و چرخه عمر سرور (فعالیتهای پیکربندی چه زمانی رخ میدهند) شروع میکند. سپس به نمای کد و ابزار پیکربندی سرور میرود. محتوای مرکزی این فصل روشهای مختلف ایجاد نمونه سرور، prebuild سرورها برای ایجاد چند نمونه یکنواخت، و رویکردهای اعمال پیکربندی سرور در طول چرخه عمر سرور را بررسی میکند.
شکل ۱۱-۱. چرخه عمر پایه سرور
مفید است چرخه عمر سرور را با چند فاز گذار در نظر بگیرید، همانطور که در شکل ۱۱-۱ نشان داده شده.
چرخه عمر پایه نشاندادهشده سه فاز گذار دارد:
- ایجاد و پیکربندی نمونه سرور
- تغییر نمونه سرور موجود
- نابود کردن نمونه سرور
این فصل ایجاد و پیکربندی سرورها را توضیح میدهد. فصل ۱۲ نحوه اعمال تغییرات روی سرورها را، و فصل ۱۳ ایجاد و بهروزرسانی image سرور که میتوانید از آن نمونه سرور بسازید را بحث میکند.
چه چیزهایی روی سرور است
مفید است به چیزهای مختلف روی سرور و منشأ هر کدام فکر کنید. یک روش تقسیم محتوای سرور به نرمافزار، پیکربندی و داده است. این دستهها، همانطور که در جدول ۱۱-۱ توضیح داده شده، برای درک اینکه ابزارهای configuration management باید فایل یا مجموعه فایل خاصی را چگونه treat کنند مفیدند.
تفاوت بین پیکربندی و داده این است که آیا ابزارهای اتوماسیون محتوای داخل فایل را خودکار مدیریت میکنند یا نه. پس حتی اگر log سیستم برای زیرساخت ضروری است، ابزار پیکربندی خودکار آن را بهعنوان داده treat میکند. بههمینترتیب، اگر برنامه چیزهایی مثل حسابها و ترجیحات کاربران را در فایل روی سرور ذخیره کند، ابزار پیکربندی سرور آن فایل را داده treat میکند.
جدول ۱۱-۱. انواع چیزها روی سرور
| نوع | توضیح | نحوه برخورد configuration management |
|---|---|---|
| نرمافزار (Software) | برنامهها، کتابخانهها و کد دیگر. لازم نیست فایل اجرایی باشد؛ میتواند تقریباً هر فایل ایستایی باشد که بین سیستمها متغیر نیست. مثال: فایلهای داده منطقه زمانی روی Linux. | اطمینان از یکسان بودن روی هر سرور مرتبط؛ به محتوای داخل اهمیت نمیدهد. |
| پیکربندی (Configuration) | فایلهایی که نحوه کار سیستم و/یا برنامهها را کنترل میکنند. محتوا ممکن است بین سرورها بر اساس نقش، محیط، نمونه و غیره متفاوت باشد. این فایلها بخشی از زیرساخت مدیریت میشوند، نه پیکربندی که خود برنامهها مدیریت میکنند. مثلاً اگر برنامه UI برای مدیریت پروفایل کاربر دارد، فایلهای داده پروفایل از دید زیرساخت داده محسوب میشوند؛ اما فایل پیکربندی برنامه که روی filesystem ذخیره و توسط زیرساخت مدیریت میشود، در این معنا پیکربندی است. | ساخت محتوای فایل روی سرور؛ اطمینان از سازگاری. |
| داده (Data) | فایلهای تولید و بهروزشده توسط سیستم و برنامهها. زیرساخت ممکن است مسئولیتهایی مثل توزیع، پشتیبانگیری یا replication داشته باشد، اما محتوای فایلها را black box treat میکند. فایلهای داده پایگاه داده و logfile نمونه داده در این معنا هستند. | طبیعی و در حال تغییر؛ ممکن است نیاز به حفظ باشد، اما محتوای داخل را مدیریت نمیکند. |
منشأ چیزها
نرمافزار، پیکربندی و دادهای که نمونه سرور را تشکیل میدهند ممکن است هنگام ایجاد و پیکربندی سرور، یا هنگام تغییر سرور اضافه شوند. چند منبع ممکن برای این عناصر وجود دارد (شکل ۱۱-۲ را ببینید):
سیستمعامل پایه (Base operating system) image نصب سیستمعامل میتواند دیسک فیزیکی، فایل ISO یا image سرور stock باشد. فرایند نصب OS ممکن است اجزای اختیاری را انتخاب کند.
مخازن بسته OS (OS package repositories) نصب OS، یا گام پیکربندی پس از نصب، میتواند ابزاری اجرا کند که بستهها را از یک یا چند مخزن دانلود و نصب کند (برای قالبهای بسته OS به جدول ۱۰-۱ مراجعه کنید). فروشندگان OS معمولاً مخزنی با بستههای پشتیبانیشده ارائه میدهند. میتوانید از مخازن third-party برای بستههای open source یا تجاری استفاده کنید. همچنین ممکن است مخزن داخلی برای بستههای توسعهیافته یا curated درونسازمانی داشته باشید.
مخازن زبان، فریمورک و بستر (Language, framework, and other platform repositories) علاوه بر بستههای OS، ممکن است بستههای زبان یا فریمورک مثل کتابخانههای Java یا Ruby gems نصب کنید. مانند بستههای OS، ممکن است از مخازن مدیریتشده توسط فروشندگان زبان، third party یا گروههای داخلی بکشید.
بستههای غیراستاندارد (Nonstandard packages) برخی فروشندگان و گروههای درونسازمانی نرمافزار با installer اختصاصی، یا با چند گام غیر از اجرای ابزار مدیریت بسته استاندارد ارائه میدهند.
مواد جدا (Separate material) ممکن است فایلها را خارج از برنامه یا جزء اضافه یا تغییر دهید — مثلاً افزودن حساب کاربری یا تنظیم قوانین فایروال محلی.
شکل ۱۱-۲. بستهها و عناصر دیگر نمونه سرور
سؤال بعدی این است که هنگام ایجاد یا تغییر نمونه سرور چگونه چیزها را اضافه کنید.
کد پیکربندی سرور
نسل اول ابزارهای Infrastructure as Code روی پیکربندی خودکار سرور متمرکز بود. برخی ابزارها در این فضا:
- Ansible
- CFEngine
- Chef
- Puppet
- Saltstack
بسیاری از این ابزارها از الگوی pull configuration با agent نصبشده روی هر سرور استفاده میکنند (به «الگو: Pull Server Configuration» در صفحه ۲۰۰ مراجعه کنید). agentای ارائه میدهند که میتوانید بهعنوان سرویس نصب کنید یا دورهای از cron job اجرا کنید.
ابزارهای دیگر برای اجرا از سرور متمرکز و اتصال به هر سرور مدیریتشده طراحی شدهاند و الگوی push را دنبال میکنند («الگو: Push Server Configuration» در صفحه ۱۹۸).
میتوانید الگوی push یا pull را با بیشتر این ابزارها پیادهسازی کنید. اگر از ابزاری مثل Ansible که برای مدل push طراحی شده استفاده میکنید، میتوانید آن را از قبل روی سرورها نصب و از cron اجرا کنید. برعکس، اگر از ابزاری مثل Chef یا Puppet با agent برای مدل pull استفاده میکنید، میتوانید از سرور متمرکز دستوری اجرا کنید که login کرده و client را روی هر ماشین اجرا کند. پس ابزار محدودیت انتخاب الگو نیست.
بسیاری از سازندگان ابزار پیکربندی سرور repository server برای میزبانی کد پیکربندی ارائه میدهند. نمونهها: Ansible Tower، Chef Server و Puppetmaster. ممکن است قابلیتهای اضافی مثل registry پیکربندی (به «Registry پیکربندی» در صفحه ۹۹ مراجعه کنید)، dashboard، لاگبرداری یا اجرای متمرکز داشته باشند.
بحثبرانگیز است که انتخاب فروشنده با اکوسیستم all-in-one ابزارها برای تیم زیرساخت کار را ساده میکند. با این حال، مفید است اگر عناصر اکوسیستم قابل تعویض با ابزارهای دیگر باشند تا تیم بهترین قطعات متناسب با نیاز را انتخاب کند. مثلاً اگر چند ابزار با registry پیکربندی یکپارچه میشوند، ممکن است registry عمومی مستقل را به registry وابسته به ابزار پیکربندی سرور ترجیح دهید.
codebase بخش مهمی از زندگی تیم زیرساخت مدرن است. اصول و راهنماییهای فصل ۴ برای کد سرور، کد پشته و غیره هم اعمال میشوند.
ماژولهای کد پیکربندی سرور
کد پیکربندی سرور، مانند هر کدی، تمایل دارد با گذشت زمان به آشفتگی گسترده تبدیل شود. برای اجتناب از این، انضباط و عادتهای خوب لازم است. خوشبختانه این ابزارها راههایی برای سازماندهی و ساختاردهی کد در واحدهای مختلف میدهند.
بیشتر ابزارهای پیکربندی سرور اجازه میدهند کد را در ماژول سازماندهی کنید. مثلاً Ansible playbook دارد، Chef recipeها را در cookbook گروهبندی میکند، و Puppet ماژول با manifest دارد. میتوانید این ماژولها را جداگانه سازماندهی، نسخهگذاری و release کنید.
نقشها (Roles) روشی برای علامتگذاری گروهی از ماژولها برای اعمال روی سرور و تعریف هدف آن هستند. برخلاف مفاهیم دیگر، بیشتر فروشندگان ابزار در استفاده از اصطلاح role توافق دارند.[۱]
[۱] کاملاً درخور بود که افراد Chef نقش را hat بنامند تا بتوانند درباره سرورهایی که chef hat دارند صحبت کنند. خوشحالم که نکردند.
بسیاری از این ابزارها همچنین از extension به مدل منبع هسته پشتیبانی میکنند. زبان ابزار مدلی از موجودیتهای منبع سرور مثل user، package و file ارائه میدهد. مثلاً میتوانید Chef Lightweight Resource Provider (LWRP) بنویسید تا منبع Java application اضافه کند که برنامههای نوشتهشده توسط تیم توسعه را نصب و پیکربندی کند. این extensionها شبیه ماژولهای پشته هستند (فصل ۱۶ را ببینید). فصل ۱۵ بحث عمومیتری درباره ماژولار کردن زیرساخت، از جمله راهنمایی طراحی خوب، دارد.
طراحی ماژولهای کد پیکربندی سرور
هر ماژول کد پیکربندی سرور (مثلاً هر cookbook یا playbook) را باید حول یک concern منسجم واحد طراحی و بنویسید. این توصیه از اصل separation of concerns در طراحی نرمافزار پیروی میکند. رویکرد رایج داشتن ماژول جدا برای هر برنامه است.
مثلاً ممکن است ماژولی برای مدیریت application server مثل Tomcat بسازید. کد ماژول نرمافزار Tomcat، حسابها و گروههای کاربری برای اجرا، و پوشهها با مجوزهای درست برای log و فایلهای دیگر را نصب میکند. فایلهای پیکربندی Tomcat، از جمله پورتها و تنظیمات را میسازد. کد ماژول همچنین Tomcat را با سرویسهایی مثل تجمیع log، نظارت و مدیریت فرایند یکپارچه میکند.
بسیاری از تیمها طراحی ماژولهای پیکربندی سرور را بر اساس کاربرد متفاوت میکنند. مثلاً میتوانید ماژولها را به ماژول کتابخانه و ماژول برنامه تقسیم کنید (در Chef این cookbook کتابخانه و cookbook برنامه میشود).
ماژول کتابخانه مفهوم هستهای را مدیریت میکند که ماژولهای برنامه میتوانند reuse کنند. با مثال ماژول Tomcat، میتوانید ماژول را طوری بنویسید که پارامتر بگیرد تا برای اهداف مختلف بهینه شود.
ماژول برنامه، که wrapper module هم نامیده میشود، یک یا چند ماژول کتابخانه را import میکند و پارامترهای آنها را برای هدف خاصتر تنظیم میکند. تیم ShopSpinner میتواند یک ماژول Servermaker برای نصب Tomcat برای برنامه کاتالوگ محصول و دومی برای مدیریت مشتری داشته باشد.[۲] هر دو از کتابخانه مشترکی که Tomcat نصب میکند استفاده میکنند.
[۲] از فصل ۴ به یاد دارید Servermaker ابزار پیکربندی سرور فرضی مشابه Ansible، Chef و Puppet است.
نسخهگذاری و ارتقای کد سرور
مانند هر کد، باید بتوانید کد پیکربندی سرور را بین محیطها آزمایش و پیش ببرید قبل از اعمال روی سیستمهای production. برخی تیمها همه ماژولهای کد سرور را با هم بهعنوان واحد واحد نسخهگذاری و ارتقا میدهند — یا با build با هم (به «الگو: Build-Time Project Integration» در صفحه ۳۲۷ مراجعه کنید)، یا با build و test جداگانه قبل از ترکیب برای production (به «الگو: Delivery-Time Project Integration» در صفحه ۳۳۰ مراجعه کنید). برخی هر ماژول را مستقل نسخهگذاری و تحویل میدهند (به «الگو: Apply-Time Project Integration» در صفحه ۳۳۳ مراجعه کنید).
اگر هر ماژول را بهعنوان واحد جدا مدیریت میکنید، باید وابستگیهای بین آنها را مدیریت کنید. بسیاری از ابزارها اجازه میدهند وابستگی ماژول را در descriptor مشخص کنید. در Chef cookbook مثلاً وابستگیها را در فیلد depends فایل metadata cookbook فهرست میکنید. ابزار از این مشخصات برای دانلود و اعمال ماژولهای وابسته روی نمونه سرور استفاده میکند. مدیریت وابستگی برای ماژولهای پیکربندی سرور مانند سیستمهای مدیریت بسته نرمافزار مثل RPM و Python pip کار میکند.
همچنین باید نسخههای مختلف کد پیکربندی سرور را ذخیره و مدیریت کنید. اغلب یک نسخه روی production اعمال شده و نسخههای دیگر در حال توسعه و آزمایش هستند.
فصلهای ۱۸ و ۱۹ بحث عمیقتری درباره سازماندهی، بستهبندی و تحویل کد زیرساخت دارند.
نقشهای سرور (Server Roles)
همانطور که گفته شد، نقش سرور روشی برای تعریف گروهی از ماژولهای پیکربندی سرور برای اعمال روی سرور است. نقش ممکن است پارامترهای پیشفرض هم تنظیم کند. مثلاً ممکن است نقش application-server بسازید:
role: application-server
server_modules:
- tomcat
- monitoring_agent
- logging_agent
- network_hardening
parameters:
- inbound_port: 8443اختصاص این نقش به سرور، پیکربندی Tomcat، agentهای نظارت و لاگ، و سختسازی شبکه را اعمال میکند. همچنین پارامتر پورت ورودی را تنظیم میکند — احتمالاً چیزی که ماژول network_hardening برای باز کردن آن پورت در فایروال محلی و قفل کردن بقیه استفاده میکند.
نقشها میتوانند نامرتب شوند، پس باید در نحوه استفاده عمدی و سازگار باشید. ممکن است نقشهای fine-grained بسازید که برای ترکیب سرورهای خاص compose میکنید. چند نقش به یک سرور اختصاص میدهید، مثل Application Server، MonitoredServer و PublicFacingServer. هر نقش تعداد کمی ماژول سرور برای هدف باریک دارد.
یا ممکن است نقشهای سطح بالاتر با ماژولهای بیشتر داشته باشید. هر سرور احتمالاً فقط یک نقش دارد — شاید بسیار خاص مثل ShoppingServiceServer یا JiraServer.
رویکرد رایج استفاده از role inheritance است. نقش پایهای تعریف میکنید که نرمافزار و پیکربندی مشترک همه سرورها را شامل میشود — شاید سختسازی شبکه، حسابهای کاربری مدیریتی، و agentهای نظارت و لاگ. نقشهای خاصتر، مثل application server یا host کانتینر، نقش پایه را include میکنند و چند ماژول و پارامتر اضافه میکنند:
role: base-role
server_modules:
- monitoring_agent
- logging_agent
- network_hardening
role: application-server
include_roles:
- base_role
server_modules:
- tomcat
parameters:
- inbound_port: 8443
role: shopping-service-server
include_roles:
- application-server
server_modules:
- shopping-service-applicationاین مثال کد سه نقش در سلسلهمراتب تعریف میکند. نقش shopping-service-server همه چیز را از application-server به ارث میبرد و ماژولی برای نصب برنامه خاص اضافه میکند. نقش application-server از base-role به ارث میبرد و Tomcat و پیکربندی پورت شبکه اضافه میکند. base-role مجموعه هسته ماژولهای پیکربندی عمومی را تعریف میکند.
آزمایش کد سرور
فصل ۸ توضیح داد چگونه آزمایش خودکار و نظریه CD به زیرساخت اعمال میشود، و فصل ۹ رویکردهای پیادهسازی با پشتههای زیرساخت را. بسیاری از مفاهیم هر دو فصل برای آزمایش کد سرور هم اعمال میشوند.
آزمایش تدریجی کد سرور
بین طراحی کد و آزمایش پویایی خودتقویتکننده وجود دارد. برای codebase ساختاریافته تمیز نوشتن و نگهداری test آسانتر است. نوشتن test و نگه داشتن همه passing، ساختار تمیز را حفظ میکند. push هر تغییر به pipeline که testها را اجرا میکند به تیم کمک میکند انضباط refactor مداوم برای کمینه کردن technical debt و design debt را حفظ کند.
ساختار توضیحدادهشده — نقشهای سرور متشکل از ماژولهای پیکربندی سرور که خود ممکن است به ماژول کتابخانه و برنامه سازماندهی شوند — با استراتژی آزمایش تدریجی (به «آزمایش تدریجی» در صفحه ۱۱۵ مراجعه کنید) همخوان است. مجموعهای از مرحلههای pipeline میتواند هر کدام را در سطوح فزاینده یکپارچگی آزمایش کند، همانطور که در شکل ۱۱-۳ نشان داده شده.
شکل ۱۱-۳. آزمایش تدریجی ماژولهای کد سرور
مرحله جدا هر ماژول کد را هر وقت کسی تغییری commit میکند آزمایش میکند. نقش سرور هم مرحله آزمایش دارد. این مرحله هر وقت یکی از ماژولهای مورد استفاده نقش تغییر کند و مرحله خودش را pass کند اجرا میشود. مرحله آزمایش نقش وقتی کسی تغییری در کد نقش commit کند — مثلاً افزودن یا حذف ماژول، یا تغییر پارامتر — هم اجرا میشود.
چه چیزهایی را با کد سرور آزمایش کنیم
تصمیم درباره آنچه با کد سرور آزمایش شود دشوار است. این به سؤال ارزش آزمایش کد declarative برمیگردد (به «چالش: test برای کد declarative اغلب ارزش کم دارد» در صفحه ۱۱۰ مراجعه کنید). ماژولهای کد سرور، بهویژه در codebase خوب طراحیشده، معمولاً کوچک، ساده و متمرکزند. ماژولی که JVM Java نصب میکند ممکن است یک statement با چند پارامتر باشد:
package:
name: java-${JAVA_DISTRIBUTION}
version: ${JAVA_VERSION}در عمل، حتی ماژولهای نصب package بهظاهر ساده ممکن است کد بیشتری داشته باشند — سفارشیسازی مسیر فایل، فایل پیکربندی، شاید افزودن حساب کاربری. اما اغلب چیز زیادی برای آزمایش نیست که خود کد را بازگو نکند.
testها باید روی مسائل رایج، نتایج متغیر و ترکیب کد تمرکز کنند. مسائل رایجی که در عمل خراب میشوند و sanity check را در نظر بگیرید. برای نصب package ساده، ممکن است بخواهید دستور در مسیر پیشفرض user در دسترس باشد. پس test دستور را invoke میکند و اجرا را بررسی میکند:
given command 'java -version' {
its(exit_status) { should_be 0 }
}اگر package بسته به پارامترها نتایج radically متفاوت دارد، test بنویسید که در حالتهای مختلف درست رفتار کند. برای نصب JVM، test را با مقادیر مختلف distribution Java اجرا کنید و مطمئن شوید دستور java با هر distribution در دسترس است.
در عمل، ارزش آزمایش با یکپارچهسازی بیشتر عناصر بالاتر است. پس ممکن است test بیشتری برای نقش application server بنویسید تا ماژولهایی که نقش include میکند.
بهویژه وقتی ماژولها با هم integrate و interact میکنند. ماژول نصب Tomcat احتمالاً با ماژول agent نظارت clash نمیکند، اما ماژول سختسازی امنیتی ممکن است مشکل ایجاد کند. در این صورت test روی نقش application server داشته باشید تا تأیید کند application server بالا است و درخواست میپذیرد حتی بعد از قفل شدن پورتها.
چگونه کد سرور را آزمایش کنیم
بیشتر testهای خودکار کد سرور با اجرای دستور روی نمونه سرور یا کانتینر و بررسی نتیجه کار میکنند. ممکن است وجود و وضعیت منابع مثل package، file، حساب کاربری و فرایند در حال اجرا را assert کنند. testها ممکن است نتایج را هم ببینند — مثلاً اتصال به پورت شبکه برای اثبات سرویس نتیجه مورد انتظار برمیگرداند.
ابزارهای محبوب برای آزمایش شرایط روی سرور: Inspec، Serverspec و Terratest.
استراتژیهای آزمایش پشته کامل زیرساخت شامل اجرای test آفلاین و آنلاین است (به «مراحل آزمایش آفلاین برای پشتهها» در صفحه ۱۳۱ و «مراحل آزمایش آنلاین برای پشتهها» در صفحه ۱۳۴ مراجعه کنید). آزمایش آنلاین شامل spin up روی بستر زیرساخت است. معمولاً میتوانید کد سرور را آفلاین با کانتینر یا ماشین مجازی محلی آزمایش کنید.
توسعهدهنده زیرساخت که محلی کار میکند میتواند نمونه کانتینر یا VM محلی با نصب حداقلی OS بسازد، کد پیکربندی سرور را اعمال کند و testها را اجرا کند.
مرحلههای pipeline که کد سرور را آزمایش میکنند همین کار را میکنند — اجرای نمونه کانتینر یا VM روی agent (مثلاً node Jenkins که job را اجرا میکند). یا مرحله میتواند نمونه کانتینر standalone روی کلاستر کانتینر spin up کند. وقتی orchestration pipeline خود containerized است خوب کار میکند.
میتوانید راهنمای پشتهها را برای orchestrate کردن آزمایش کد سرور دنبال کنید (به «هماهنگسازی آزمایش» در صفحه ۱۴۹ مراجعه کنید). شامل نوشتن اسکriptهایی برای آمادهسازی پیشنیازهای آزمایش مثل نمونه کانتینر، قبل از اجرای test و گزارش نتیجه. همان اسکriptهایی که محلی آزمایش میکنید را از سرویس pipeline استفاده کنید تا نتایج سازگار باشند.
ایجاد نمونه سرور جدید
چرخه عمر پایه سرور توضیحدادهشده با ایجاد نمونه سرور جدید شروع میشود. چرخه گستردهتر گامهای ایجاد و بهروزرسانی image سرور را شامل میشود که از آن نمونه سرور میسازید، اما آن موضوع را برای فصل دیگر میگذاریم (فصل ۱۳). فعلاً چرخه عمر با ایجاد نمونه شروع میشود، همانطور که در شکل ۱۱-۴ نشان داده شده.
شکل ۱۱-۴. ایجاد نمونه سرور
فرایند کامل ایجاد سرور شامل provisioning نمونه سرور تا آماده کامل استفاده باشد. برخی فعالیتهای ایجاد و provisioning نمونه سرور:
- تخصیص منابع زیرساخت برای instantiate کردن نمونه سرور. برای این کار، سرور فیزیکی از pool انتخاب میشود یا host server برای اجرا بهعنوان ماشین مجازی. برای VM، hypervisor روی host حافظه و منابع دیگر را تخصیص میدهد. فرایند ممکن است ذخیرهسازی برای volume دیسک نمونه هم تخصیص دهد.
- نصب سیستمعامل و نرمافزار اولیه. OS ممکن است روی volume دیسک کپی شود، مثل boot از image سرور مثل AMI. یا نمونه جدید فرایند نصب را اجرا میکند که فایلها را انتخاب و کپی میکند — شاید با installer قابل اسکریپت. نمونه installerهای OS اسکریپتشده: Red Hat Kickstart، Solaris JumpStart، Debian Preseed و Windows installation answer file.
- پیکربندی اضافی روی نمونه سرور اعمال میشود. در این گام، ابزار پیکربندی سرور اجرا میشود، طبق الگوی «چگونه کد پیکربندی سرور را اعمال کنیم» در صفحه ۱۹۸.
- منابع و سیاستهای شبکه پیکربندی و متصل میشوند. شامل اختصاص سرور به بلوک آدرس شبکه، ایجاد route و افزودن قوانین فایروال.
- نمونه سرور در سرویسها ثبت میشود. مثلاً افزودن سرور جدید به سیستم نظارت.
اینها mutually exclusive نیستند — فرایند ایجاد سرور ممکن است یک یا چند روش برای اجرای این فعالیتها استفاده کند.
چند مکانیزم برای trigger کردن ایجاد نمونه سرور وجود دارد. هر کدام را مرور میکنیم.
ساخت دستی نمونه سرور جدید
بسترهای زیرساخت ابزار برای ایجاد سرور جدید دارند — معمولاً web UI، ابزار command-line و گاهی برنامه GUI. هر بار سرور جدید میسازید، گزینهها را انتخاب میکنید، از جمله image منبع، منابع تخصیصی و جزئیات شبکه:
$ mycloud server new \
--source-image=stock-linux-1.23 \
--memory=2GB \
--vnet=appserversآزمایش با UI و ابزار command-line برای آشنایی با بستر مفید است، اما روش خوبی برای ایجاد سرورهایی که مردم نیاز دارند نیست. همان اصول ایجاد و پیکربندی پشتهها (به «الگوها برای پیکربندی پشتهها» در صفحه ۸۰ مراجعه کنید) برای سرورها هم اعمال میشود. تنظیم دستی گزینهها (همانطور که در «ضدالگو: پارامترهای دستی پشته» در صفحه ۸۱ توضیح داده شد) به اشتباه تشویق میکند و به سرورهای ناهمگون، سیستمهای غیرقابل پیشبینی و کار نگهداری زیاد منجر میشود.
استفاده از اسکریپت برای ایجاد سرور
میتوانید اسکریپتهایی بنویسید که سرورها را یکنواخت ایجاد کنند. اسکریپت ابزار command-line را wrap میکند یا از API بستر زیرساخت برای ایجاد نمونه سرور استفاده میکند و گزینههای پیکربندی را در کد اسکریپت یا فایل پیکربندی تنظیم میکند. اسکریپت ایجاد سرور reusable، یکنواخت و شفاف است. همان مفهوم الگوی scripted parameters برای پشتهها (به «الگو: پارامترهای اسکریپتشده» در صفحه ۸۴ مراجعه کنید):
mycloud server new \
--source-image=stock-linux-1.23 \
--memory=2GB \
--vnet=appserversاین اسکript همان مثال command line قبلی است. اما چون در اسکریپت است، بقیه تیم میبینند چگونه سرور را ساختم. میتوانند سرورهای بیشتری بسازند و مطمئن باشند مثل سرور من رفتار میکنند.
قبل از ظهور Terraform و ابزارهای مدیریت پشته، بیشتر تیمهایی که باهاشان کار کردم اسکریپت برای ایجاد سرور مینوشتند. معمولاً اسکریپتها را با فایل پیکربندی configurable میکردیم، مانند الگوی stack configuration (به «الگو: فایلهای پیکربندی پشته» در صفحه ۸۷ مراجعه کنید). اما زمان زیادی صرف بهبود و رفع این اسکریپتها میکردیم.
استفاده از ابزار مدیریت پشته برای ایجاد سرور
با ابزار مدیریت پشته، همانطور که در فصل ۵ بحث شد، میتوانید سرور را در context منابع زیرساختی دیگر تعریف کنید، همانطور که در مثال ۱۱-۱ نشان داده شده. ابزار از API بستر برای ایجاد یا بهروزرسانی نمونه سرور استفاده میکند.
مثال ۱۱-۱. کد پشته که سرور را تعریف میکند
server:
source_image: stock-linux-1.23
memory: 2GB
vnet: ${APPSERVER_VNET}چند دلیل دارد که استفاده از ابزار پشته برای ایجاد سرور بسیار handy است. یکی اینکه منطقی که در اسکریپت خودتان پیاده میکردید — مثل error checking — را ابزار انجام میدهد. مزیت دیگر اینکه پشته یکپارچگی با عناصر زیرساخت دیگر را مدیریت میکند — مثلاً اتصال سرور به ساختارهای شبکه و ذخیرهسازی تعریفشده در پشته. کد مثال ۱۱-۱ پارامتر vnet را با متغیر ${APPSERVER_VNET} تنظیم میکند که احتمالاً به ساختار شبکهای در بخش دیگر کد پشته ارجاع میدهد.
پیکربندی بستر برای ایجاد خودکار سرورها
بیشتر بسترهای زیرساخت میتوانند در شرایط خاص خودکار نمونه سرور جدید ایجاد کنند. دو مورد رایج auto-scaling — افزودن سرور برای افزایش بار — و auto-recovery — جایگزینی نمونه وقتی از کار میافتد. معمولاً میتوانید این را با کد پشته تعریف کنید، مثل مثال ۱۱-۲.
مثال ۱۱-۲. کد پشته برای مقیاسدهی خودکار
server_cluster:
server_instance:
source_image: stock-linux-1.23
memory: 2GB
vnet: ${APPSERVER_VNET}
scaling_rules:
min_instances: 2
max_instances: 5
scaling_metric: cpu_utilization
scaling_value_target: 40%
health_check:
type: http
port: 8443
path: /health
expected_code: 200
wait: 90sاین مثال به بستر میگوید حداقل ۲ و حداکثر ۵ نمونه سرور در حال اجرا نگه دارد. بستر نمونه اضافه یا حذف میکند تا CPU utilization روی آنها نزدیک ۴۰٪ بماند.
تعریف health check هم دارد. درخواست HTTP به /health روی پورت ۸۴۴۳ میزند و سرور را سالم میداند اگر پاسخ کد ۲۰۰ HTTP برگردد. اگر بعد از ۹۰ ثانیه کد مورد انتظار برنگردد، بستر فرض میکند سرور از کار افتاده، آن را destroy میکند و نمونه جدید میسازد.
استفاده از ابزار provisioning شبکهای برای ساخت سرور
در فصل ۳، bare-metal cloudها را ذکر کردم که سرورهای سختافزاری را بهصورت پویا provision میکنند. فرایند معمولاً این گامها را دارد:
- انتخاب سرور فیزیکی بلااستفاده و trigger boot در حالت «network install» که firmware سرور پشتیبانی میکند (مثلاً PXE boot).[۳]
- network installer سرور را از image bootstrap OS ساده boot میکند تا نصب OS آغاز شود.
- image نصب OS دانلود و روی hard drive اصلی کپی میشود.
- reboot سرور برای boot OS در حالت setup و اجرای OS installer اسکریپتشده بدون نظارت.
[۳] اغلب trigger کردن PXE boot برای boot image شبکهای نیاز به فشردن function key هنگام start سرور دارد. انجام unattended دشوار است. با این حال، بسیاری از فروشندگان سختافزار lights-out management (LOM) دارند که انجام remote را ممکن میکند.
ابزارهای متعددی برای مدیریت این فرایند وجود دارد:
- Crowbar
- Cobbler
- FAI، یا Fully Automatic Installation
- Foreman
- MAAS
- Rebar
- Tinkerbell
بهجای boot image نصب OS، میتوانید image سرور آماده boot کنید. این فرصت پیادهسازی برخی روشهای دیگر آمادهسازی سرور را میدهد، همانطور که در بخش بعد توضیح داده میشود.
رویدادهای FaaS میتوانند در provision سرور کمک کنند
کد FaaS بدون سرور میتواند در provision سرور جدید نقش داشته باشد. بستر میتواند کد را در نقاط مختلف فرایند — قبل، حین و بعد از ایجاد نمونه — اجرا کند. نمونهها: اختصاص سیاست امنیتی به سرور جدید، ثبت در سرویس نظارت، یا اجرای ابزار پیکربندی سرور.
Prebuild سرورها
همانطور که گفته شد (به «منشأ چیزها» در صفحه ۱۷۱ مراجعه کنید)، چند منبع محتوا برای سرور جدید وجود دارد — از جمله نصب OS، بستههای دانلودشده از مخازن، و فایلهای پیکربندی و برنامه سفارشی کپیشده روی سرور.
میتوانید همه اینها را هنگام ایجاد سرور سرهم کنید، اما چند روش برای آمادهسازی محتوای سرور از قبل هم هست. این رویکردها فرایند ساخت سرور را بهینه میکنند — سریعتر و سادهتر — و ایجاد چند سرور یکنواخت را آسانتر میکنند. در ادامه چند رویکرد آمده. بخش بعد گزینههای اعمال پیکربندی قبل، حین و بعد از فرایند provisioning را توضیح میدهد.
Hot-cloning سرور
بیشتر بسترهای زیرساخت duplicate کردن سرور در حال اجرا را ساده میکنند. hot-cloning سرور به این روش سریع و آسان است و سرورهایی یکنواخت در لحظه clone میدهد.
clone سرور در حال اجرا وقتی میخواهید بدون مزاحمت عملکرد، سرور را کاوش یا troubleshoot کنید مفید است. اما ریسکهایی دارد. یکی اینکه کپی application server production برای آزمایش ممکن است production را تحت تأثیر قرار دهد. مثلاً اگر application server cloneشده برای استفاده از پایگاه داده production پیکربندی شده، ممکن است تصادفاً داده production را آلوده یا آسیب بزنید.
سرورهای clone شده در production معمولاً داده تاریخی از سرور اصلی دارند، مثل ورودی logfile. این آلودگی داده troubleshooting را گیجکننده میکند. دیدهام مردم روی پیام خطایی وقت بگذارند که بعداً معلوم شد از سروری که debug میکردند نبوده.
و سرورهای clone شده واقعاً reproducible نیستند. دو سرور clone شده از همان parent در زمانهای مختلف متفاوتند، و نمیتوانید برگردید و سرور سوم بسازید و کاملاً مطمئن باشید چگونه و آیا با بقیه متفاوت است. سرورهای clone شده منبع configuration drift هستند (به «Configuration Drift» در صفحه ۱۷ مراجعه کنید).
استفاده از snapshot سرور
بهجای ساخت سرور جدید با clone مستقیم سرور در حال اجرا، میتوانید snapshot از سرور در حال اجرا بگیرید و سرورها را از آن بسازید. باز هم بیشتر بسترها دستور و API برای snapshot آسان سرور دارند و image ایستا میسازند. اینطور میتوانید هر تعداد سرور بسازید و مطمئن باشید هر کدام با image شروع یکسان است.
ایجاد سرور از snapshot گرفتهشده از سرور live بسیاری از معایب hot-cloning را دارد. snapshot ممکن است با log، پیکربندی و داده دیگر از سرور اصلی آلوده باشد. مؤثرتر است image سرور تمیز از صفر بسازید.
ایجاد image سرور تمیز
image سرور snapshotی است که از منابع تمیز و شناختهشده میسازید تا چند نمونه سرور یکنواخت ایجاد کنید. ممکن است از همان قابلیتهای بستر زیرساخت که برای snapshot سرور live استفاده میکنید استفاده کنید، اما نمونه سرور اصلی هرگز بخشی از سیستمهای کلی شما نمیشود. این اطمینان میدهد هر سرور جدید تمیز است.
فرایند معمول ساخت image سرور:
- ایجاد نمونه سرور جدید از منبع شناختهشده — مثل image نصب فروشنده OS، یا imageی که بستر زیرساخت برای این منظور ارائه میدهد.
- اعمال کد پیکربندی سرور یا اجرای اسکریپتهای دیگر روی سرور. ممکن است بستهها و agentهای استاندارد، سختسازی امنیتی و همه patchهای آخر را نصب کنند.
- snapshot سرور و ایجاد image برای ساخت چند نمونه سرور. ممکن است گامهایی برای علامتگذاری snapshot بهعنوان image برای سرورهای جدید لازم باشد. همچنین tag و نسخهگذاری برای مدیریت کتابخانه چند image سرور.
گاهی imageهای سرور را golden image مینامند. برخی تیمها این imageها را دستی — شاید با checklist نوشته — میسازند، اما خوانندگان این کتاب فوراً مزایای اتوماسیون این فرایند و مدیریت image سرور بهصورت کد را میبینند. ساخت و تحویل image سرور موضوع فصل ۱۳ است.
پیکربندی نمونه سرور جدید
این فصل عناصر سرور، منشأ آنها، روشهای ایجاد نمونه سرور جدید و ارزش prebuild image سرور را توضیح داد. آخرین قطعه فرایند ایجاد و provisioning سرور، اعمال کد پیکربندی خودکار سرور روی سرورهای جدید است. چند نقطه در فرایند وجود دارد که میتوانید این کار را انجام دهید، همانطور که در شکل ۱۱-۵ نشان داده شده.
شکل ۱۱-۵. محل اعمال پیکربندی در چرخه عمر سرور
پیکربندی میتواند هنگام ایجاد image سرور، هنگام ایجاد نمونه سرور از image، و وقتی سرور در حال اجراست اعمال شود:
پیکربندی image سرور (Configuring a server image) پیکربندی هنگام ساخت image سرور که برای ایجاد چند نمونه سرور استفاده میشود اعمال میشود. یک بار پیکربندی، چند بار استفاده. اغلب baking image سرور نامیده میشود.
پیکربندی نمونه سرور جدید (Configuring a new server instance) پیکربندی هنگام ایجاد نمونه سرور جدید اعمال میشود. چند بار پیکربندی. گاهی frying نمونه سرور نامیده میشود.
پیکربندی نمونه سرور در حال اجرا (Configuring a running server instance) پیکربندی روی سروری که قبلاً در حال استفاده است اعمال میشود. یک دلیل رایج اعمال patch امنیتی است. دلیل دیگر revert تغییرات خارج از پیکربندی خودکار برای enforce سازگاری. برخی تیمها هم برای transform سرور موجود — مثلاً تبدیل web server به application server — پیکربندی اعمال میکنند.
آخرین مورد، پیکربندی نمونه در حال اجرا، معمولاً برای تغییر سرور است — موضوع فصل ۱۲. دو مورد اول گزینههای اعمال پیکربندی هنگام ایجاد سرور جدید هستند و در محدوده این فصلاند. سؤال اصلی تعیین زمان درست اعمال پیکربندی برای سرور جدید است — frying در هر نمونه جدید، یا baking در image سرور؟
Frying نمونه سرور
همانطور که توضیح داده شد، frying یعنی اعمال پیکربندی هنگام ایجاد نمونه سرور جدید. میتوانید تا حد extreme بروید — هر image سرور را حداقلی نگه دارید و همه چیز خاص هر سرور را در image live بسازید.
این یعنی سرورهای جدید همیشه آخرین تغییرات را دارند — از جمله patch سیستم، جدیدترین نسخه بسته نرمافزار و گزینههای پیکربندی بهروز. Frying سرور نمونه delivery-time integration است (به «الگو: Delivery-Time Project Integration» در صفحه ۳۳۰ مراجعه کنید).
این رویکرد مدیریت image را ساده میکند. image زیاد نیست — احتمالاً فقط یکی برای هر ترکیب سختافزار و نسخه OS — مثلاً یکی برای Windows 2019 64-bit و یکی برای Ubuntu 18.x 32-bit و 64-bit. imageها زیاد بهروز نمیشوند چون چیز زیادی روی آنها نیست که تغییر کند. در هر صورت میتوانید آخرین patchها را هنگام provision هر سرور اعمال کنید.
برخی تیمهایی که باهاشان بودم در آغاز پذیرش اتوماسیون زیرساخت روی frying تمرکز کردند. راهاندازی ابزار و فرایند مدیریت image سرور کار زیادی است. آن را در backlog گذاشتیم تا بعد از ساخت هسته مدیریت زیرساخت.
در موارد دیگر frying منطقی است چون سرورها بسیار متغیرند. شرکت hosting که میشناسم به مشتریان انتخاب از customizations زیاد برای سرور میدهد. image پایه minimalist نگه میدارد و بیشتر روی اتوماسیون پیکربندی هر سرور جدید تمرکز میکند.
چند مسئله احتمالی با نصب و پیکربندی عناصر سرور هنگام ایجاد هر نمونه:
سرعت (Speed) فعالیتهای هنگام ساخت سرور به زمان ایجاد اضافه میکنند. برای spin up سرور برای spike بار یا recovery از failure مشکلساز است.
کارایی (Efficiency) پیکربندی سرور اغلب شامل دانلود بسته از مخازن روی شبکه است. میتواند اتلاف و کند باشد. اگر باید ۲۰ سرور در زمان کوتاه spin up کنید، دانلود patch و installer یکسان توسط هر کدام اتلاف است.
وابستگیها (Dependencies) پیکربندی سرور معمولاً به repository artifact و سیستمهای دیگر وابسته است. اگر offline یا unreachable باشند، نمیتوانید سرور جدید بسازید. در سناریوی emergency که باید تعداد زیادی سرور سریع rebuild کنید، ممکن است دستگاه شبکه یا مخزن هم down باشند — گراف مرتب پیچیدهای از اینکه کدام سیستم را اول restart یا rebuild کنید تا بعدی بالا بیاید.
Baking image سرور
در انتهای دیگر طیف ایجاد سرور، تقریباً همه چیز در image سرور پیکربندی میشود. ساخت سرور جدید بسیار سریع و ساده است چون فقط پیکربندی خاص نمونه اعمال میشود. Baking image سرور نمونه build-time integration است (به «الگو: Build-Time Project Integration» در صفحه ۳۲۷ مراجعه کنید).
مزایای baking را از معایب frying میبینید. Baking پیکربندی در image سرور بهویژه برای سیستمهایی با تعداد زیاد نمونه سرور مشابه و نیاز به ایجاد مکرر و سریع سرور مناسب است.
یک چالش baking این است که باید ابزار و فرایند خودکار برای بهروز و rollout نسخههای جدید راه بیندازید. مثلاً اگر patch امنیتی مهم برای OS یا بستههای کلیدی baked در image سرور منتشر شد، باید image جدید بسازید و سریع با disruption کم روی سرورهای موجود rollout کنید. این در فصل ۱۳ پوشش داده میشود.
مسئله دیگر baking سرعت است. حتی با فرایند خودکار بالغ، ساخت و release image جدید ممکن است ۱۰ تا ۶۰ دقیقه طول بکشد. میتوانید با rollout تغییرات روی سرورهای در حال اجرا (موضوع فصل ۱۲) یا فرایندی که baking و frying را ترکیب میکند mitigate کنید.
ترکیب Baking و Frying
در عمل، بیشتر تیمها ترکیبی از baking و frying برای پیکربندی سرورهای جدید استفاده میکنند. میتوانید تعادل کنید کدام فعالیتها در image سرور و کدام هنگام ایجاد نمونه سرور پیکربندی شوند. ممکن است برخی عناصر پیکربندی در هر دو مرحله اعمال شوند.
ملاکهای اصلی برای تصمیم زمان اعمال پیکربندی خاص، زمان لازم و فراوانی تغییر است. چیزهایی که اعمال طولانیتر و کمتر تغییر میکنند، کاندیدای واضح baking در image سرورند. مثلاً میتوانید نرمافزار application server را روی image نصب کنید — spin up چند نمونه سرور سریعتر و پهنای باند شبکه صرفهجویی میشود.
در طرف دیگر trade-off، چیزی که نصب سریعتر است یا بیشتر تغییر میکند بهتر است fry شود. مثال رایج برنامههای توسعه درونسازمانی. یکی از use caseهای رایج spin up سرور جدید on demand، آزمایش در فرایند release نرمافزار است.
تیمهای توسعه بسیار productive ممکن است دهها build جدید برنامه در روز push کنند و به CI برای deploy و test خودکار هر build تکیه کنند. Baking image سرور جدید برای هر build برنامه برای این سرعت کار خیلی کند است — کارآمدتر است برنامه را هنگام ایجاد سرور test deploy کنید.
روش دیگر ترکیب: تا حد ممکن bake روی image، اما نسخههای بهروز را fry کنید. تیم ممکن است image بهروز را آهستهتر bake کند — هفتگی یا ماهانه. وقتی چیزی که معمولاً bake میکنید — مثل patch امنیتی یا بهبود پیکربندی — باید بهروز شود، میتواند در فرایند ایجاد سرور fry شود روی image baked.
وقتی وقت bake image بهروز رسید، بهروزرسانیها را در آن fold میکنند و از فرایند ایجاد حذف میکنند. این روش تغییرات جدید را سریع با overhead کمتر incorporate میکند. تیمها اغلب با اعمال مداوم کد (به «الگو: Continuous Configuration Synchronization» در صفحه ۱۹۴) ترکیب میکنند تا سرورهای موجود بدون rebuild بهروز شوند.
اعمال پیکربندی سرور هنگام ایجاد سرور
بیشتر ابزارهایی که سرور را به روشهای بحثشده ایجاد میکنند (به «ایجاد نمونه سرور جدید» در صفحه ۱۷۹ مراجعه کنید) — چه command-line، API بستر یا ابزار مدیریت پشته — راهی برای اعمال کد پیکربندی سرور دارند. مثلاً ابزار مدیریت پشته باید syntax برای ابزارهای محبوب یا اجرای دستور دلخواه روی نمونه سرور جدید داشته باشد، مثل مثال ۱۱-۳.
مثال ۱۱-۳. کد پشته که ابزار پیکربندی سرور فرضی من را اجرا میکند
server:
source_image: stock-linux-1.23
memory: 2GB
vnet: ${APPSERVER_VNET}
configure:
tool: servermaker
code_repo: servermaker.shopspinner.xyz
server_role: appserver
parameters:
app_name: catalog_service
app_version: 1.2.3این کد ابزار Servermaker را اجرا میکند و hostname سرور میزبان کد پیکربندی، نقش اعمالشده (appserver) و پارامترهایی (app_name و app_version) را به آن میدهد.
برخی ابزارها اجازه میدهند کد پیکربندی سرور را مستقیم در کد پشته embed کنید، یا shell command اجرا کنید. وسوسهانگیز است از این برای منطق پیکربندی سرور استفاده کنید — برای نیازهای ساده شاید کافی باشد. اما در بیشتر موارد این کد در اندازه و پیچیدگی رشد میکند. پس بهتر است کد را extract کنید تا codebase تمیز و قابل نگهداری بماند.
جمعبندی
این فصل جنبههای مختلف ایجاد و provisioning سرورهای جدید را پوشش داد. انواع چیزها روی سرور شامل نرمافزار، پیکربندی و داده است. اینها معمولاً از نصب OS پایه و بستههای مخازن مختلف — OS، زبان، third party و تیمهای داخلی — میآیند. معمولاً سرور را با ترکیب محتوا از image سرور و ابزار پیکربندی سرور برای اعمال بسته و پیکربندی اضافی میسازید.
برای ایجاد سرور میتوانید command-line یا UI اجرا کنید، اما ترجیحاً فرایند code-driven است. امروز کمتر اسکریپت سفارشی مینویسید و بیشتر از ابزار مدیریت پشته استفاده میکنید. با وجود رویکردهای مختلف ساخت سرور، معمولاً ساخت image سرور را توصیه میکنم.