حالت تاریک
فصل ۲ — اصول زیرساخت عصر ابری
منابع محاسباتی در عصر آهن IT بهشدت به سختافزار فیزیکی coupled بودند. CPU، حافظه و hard drive را در یک case سرهم میکردیم، در rack نصب میکردیم و به switch و router کابل میزدیم. سیستمعامل و نرمافزار برنامه را نصب و پیکربندی میکردیم. میتوانستیم بگوییم application server کجای data center است: کدام طبقه، کدام ردیف، کدام rack، کدام slot.
عصر ابری منابع محاسباتی را از سختافزار فیزیکی که روی آن اجرا میشوند decouple میکند. سختافزار البته هنوز وجود دارد، اما سرورها، hard driveها و routerها روی آن شناورند. دیگر چیزهای فیزیکی نیستند؛ به سازههای مجازی تبدیل شدهاند که میتوانیم بهمیل خود بسازیم، duplicate کنیم، تغییر دهیم و destroy کنیم.
این دگرگونی مجبورمان کرده دربارهٔ منابع محاسباتی، طراحی و استفاده از آنها متفاوت فکر کنیم. نمیتوانیم به attributeهای فیزیکی application server خود برای ثابت ماندن تکیه کنیم. باید بتوانیم instanceهای سیستم را بدون تشریفات اضافه و حذف کنیم، و حتی با گسترش سریع مقیاس، consistency و کیفیت سیستمها را بهراحتی حفظ کنیم.
چند اصل برای طراحی و پیادهسازی زیرساخت روی پلتفرمهای ابری وجود دارد. این اصول استدلال استفاده از سه شیوهٔ اصلی (تعریف همهچیز بهصورت کد، تست و تحویل مداوم، ساخت قطعات کوچک) را بیان میکنند. چند pitfall رایج که تیمها با زیرساخت پویا مرتکب میشوند را هم فهرست میکنم.
این اصول و pitfalls زیر توصیههای مشخصتر پیادهسازی شیوههای زیرساخت بهعنوان کد در سراسر کتاب قرار دارند.
اصل: فرض کنید سیستمها unreliable هستند
در عصر آهن فرض میکردیم سیستمها روی سختافزار reliable اجرا میشوند. در عصر ابری باید فرض کنید سیستم روی سختافزار unreliable اجرا میشود.[^1]
زیرساخت در مقیاس ابری صدها هزار دستگاه — اگر نه بیشتر — را در بر میگیرد. در این مقیاس، حتی با سختافزار reliable هم خرابی رخ میدهد — و بیشتر cloud vendorها از سختافزار ارزان و کمتر reliable استفاده میکنند و وقتی میشکند آن را detect و replace میکنند.
باید بخشهایی از سیستم را بهدلایلی غیر از خرابیهای برنامهریزینشده offline کنید. باید سیستمها را patch و upgrade کنید. resize میکنید، load را redistribute میکنید و مشکلات را troubleshoot میکنید.
با زیرساخت static، انجام این کارها یعنی offline کردن سیستمها. اما در بسیاری از سازمانهای مدرن، offline کردن سیستمها یعنی offline کردن کسبوکار. پس نمیتوانید زیرساختی که سیستم روی آن اجرا میشود را foundation پایدار بدانید. در عوض باید برای سرویس بدون وقفه وقتی منابع زیرین تغییر میکنند طراحی کنید.[^2]
اصل: همهچیز را reproducible کنید
یکی از راههای recoverable کردن سیستم این است که مطمئن شوید میتوانید قطعاتش را effortlessly و reliably rebuild کنید.
Effortlessly یعنی نیازی به تصمیمگیری دربارهٔ نحوهٔ ساخت چیزها نیست. باید چیزهایی مانند تنظیمات پیکربندی، نسخههای نرمافزار و وابستگیها را بهصورت کد تعریف کنید. rebuild سپس تصمیم سادهٔ «بله/خیر» است.
reproducibility نهتنها بازیابی سیستم شکستخورده را آسان میکند، بلکه به شما کمک میکند:
- محیطهای تست را با production سازگار کنید
- سیستمها را در regionهای مختلف replicate کنید تا availability داشته باشید
- instanceها را on demand برای مقابله با load بالا اضافه کنید
- سیستمها را replicate کنید تا به هر مشتری instance اختصاصی بدهید
البته سیستم data، content و log تولید میکند که نمیتوانید از پیش تعریف کنید. باید آنها را شناسایی کنید و راههایی برای نگهداشتنشان در استراتژی replication پیدا کنید. شاید بهسادگی data را به backup کپی یا stream کنید و هنگام rebuild restore کنید. گزینهها را در «Data Continuity in a Changing System» (صفحهٔ ۳۸۲) توصیف میکنم.
توانایی ساخت و rebuild effortless هر بخش زیرساخت قدرتمند است. ریسک و ترس تغییر را برمیدارد و میتوانید با اطمینان با خرابیها برخورد کنید. میتوانید سریع سرویسها و محیطهای جدید provision کنید.
Pitfall: سیستمهای Snowflake
snowflake نمونهای از یک سیستم یا بخشی از سیستم است که rebuild آن سخت است. ممکن است محیطی هم باشد که باید شبیه محیطهای دیگر — مانند staging — باشد، اما بهشکلی متفاوت است که تیمش کاملاً درک نمیکند.
مردم قصد ساخت سیستمهای snowflake را ندارند. occurrence طبیعی هستند. اولین بار که چیزی را با ابزار جدید میسازید، در مسیر درس میگیرید که شامل اشتباه کردن است. اما اگر مردم به چیزی که ساختهاید تکیه میکنند، شاید وقت نداشته باشید برگردید و با آنچه یاد گرفتهاید rebuild یا بهبودش دهید. بهبود آنچه ساختهاید بهویژه سخت است اگر mechanism و شیوههایی که تغییر را آسان و ایمن میکنند ندارید.
علت دیگر snowflake وقتی است که مردم تغییراتی روی یک instance سیستم میدهند که روی دیگران نمیدهند. ممکن است تحت فشار رفع مشکلی باشند که فقط در یک سیستم ظاهر میشود، یا upgrade بزرگی را در محیط test شروع کنند اما وقت roll out به دیگران تمام شود.
وقتی مطمئن نیستید میتوانید با ایمنی تغییر یا upgrade دهید، میدانید سیستم snowflake است. بدتر، اگر سیستم بشکند، رفع آن سخت است. پس مردم از تغییر سیستم اجتناب میکنند و آن را out of date، unpatched و شاید حتی تا حدی broken رها میکنند.
سیستمهای snowflake ریسک ایجاد میکنند و وقت تیمهایی که آنها را مدیریت میکنند را هدر میدهند. تقریباً همیشه ارزش دارد آنها را با سیستمهای reproducible جایگزین کنید. اگر snowflake ارزش بهبود ندارد، شاید ارزش نگهداشتن هم نداشته باشد.
بهترین راه جایگزینی سیستم snowflake نوشتن کدی است که بتواند سیستم را replicate کند، و اجرای سیستم جدید بهصورت موازی تا آماده شود. از تستها و pipelineهای خودکار برای اثبات درستی و reproducibility و اینکه میتوانید بهراحتی تغییرش دهید استفاده کنید.
اصل: چیزهای disposable بسازید
ساخت سیستمی که با زیرساخت پویا کنار بیاید یک سطح است. سطح بعدی ساخت سیستمی است که خودش پویا باشد. باید بتوانید قطعات سیستم را gracefully اضافه، حذف، start، stop، تغییر و جابهجا کنید. انجام این کار operational flexibility، availability و scalability ایجاد میکند. تغییرات را هم سادهتر و کمریسکتر میکند.
malleable کردن قطعات سیستم ایدهٔ اصلی نرمافزار cloud native است. ابر منابع زیرساخت (compute، networking و storage) را از سختافزار فیزیکی abstract میکند. نرمافزار cloud native functionality برنامه را کاملاً از زیرساختی که روی آن اجرا میشود decouple میکند.[^3]
Cattle، نه Pets
«سرورهایتان را مثل cattle رفتار کنید، نه pets»، عبارت محبوبی دربارهٔ disposability است.[^4] دادن نامهای fun به هر سرور جدید را miss میکنم. اما miss نمیکنم که مجبور باشم هر سرور estate را دستی tweak و coddle کنم.
اگر سیستمهایتان پویا هستند، ابزارهایی که برای مدیریت آنها استفاده میکنید باید با این کنار بیایند. مثلاً monitoring نباید هر بار که بخشی از سیستم را rebuild میکنید alert بدهد. اما باید warning بدهد اگر چیزی در loop rebuild خودش گیر کند.
مورد File Server ناپدیدشونده
مردم ممکن است مدتی طول بکشد به زیرساخت ephemeral عادت کنند. یک تیمی که با آن کار کردم زیرساخت خودکار با VMware و Chef راهاندازی کرد. تیم virtual machineها را در صورت نیاز delete و replace میکرد.
یک developer جدید برای share فایل با همتیمیها به web server نیاز داشت، پس HTTP server را دستی روی development server نصب کرد و فایلها را آنجا گذاشت. چند روز بعد VM را rebuild کردم و web server او ناپدید شد.
پس از کمی سردرگمی، developer فهمید چرا این اتفاق افتاد. web server را به کد Chef اضافه کرد و فایلها را روی SAN persist کرد. تیم اکنون سرویس reliable file-sharing داشت.
اصل: variation را minimize کنید
با رشد سیستم، فهم، تغییر و رفع آن سختتر میشود. کار درگیر با تعداد قطعات رشد میکند، و همچنین با تعداد انواع مختلف قطعات. پس راه مفید برای manageable نگه داشتن سیستم، داشتن انواع کمتر قطعات — یعنی variation پایین — است. مدیریت صد سرور یکسان از پنج سرور کاملاً متفاوت آسانتر است.
اصل reproducibility (بخش «اصل: همهچیز را reproducible کنید») این ایده را تکمیل میکند. اگر component سادهای تعریف کنید و instanceهای یکسان زیادی بسازید، میتوانید بهراحتی آن را بفهمید، تغییر دهید و رفع کنید.
برای کار کردن این رویکرد، هر تغییری که میدهید باید روی همهٔ instanceهای component اعمال شود. وگرنه configuration drift ایجاد میکنید.
انواع variation که ممکن است در سیستم داشته باشید:
- چند سیستمعامل، application runtime، پایگاه داده و فناوریهای دیگر. هر کدام نیاز دارد افراد تیم مهارت و دانششان را بهروز نگه دارند.
- چند نسخه از نرمافزار مانند سیستمعامل یا پایگاه داده. حتی اگر فقط یک سیستمعامل استفاده کنید، هر نسخه ممکن است پیکربندی و tooling متفاوت بخواهد.
- نسخههای مختلف یک package. وقتی برخی سرورها نسخهٔ جدیدتری از package، utility یا library دارند، ریسک دارید. دستورات ممکن است روی آنها یکسان اجرا نشوند، یا نسخههای قدیمیتر vulnerability یا bug داشته باشند.
در سازمانها تنش بین اجازه دادن به هر تیم برای انتخاب فناوری و راهحل مناسب نیازش و نگه داشتن variation سازمان در سطح manageable وجود دارد.
حکمرانی Lightweight
سازمانهای مدرن و دیجیتال ارزش حکمرانی Lightweight در IT را برای تعادل autonomy و کنترل متمرکز میآموزند. این عنصر کلیدی مدل EDGE برای سازمانهای agile است. برای بیشتر، کتاب EDGE: Value-Driven Digital Transformation اثر Jim Highsmith، Linda Luu و David Robinson (Addison-Wesley Professional) یا سخنرانی Jonny LeRoy «The Goldilocks Zone of Lightweight Architectural Governance» را ببینید.
Configuration Drift
configuration drift variationی است که در طول زمان بین سیستمهایی که یکبار یکسان بودند رخ میدهد. شکل ۲-۱ این را نشان میدهد. تغییرات دستی میتواند configuration drift ایجاد کند. اگر از ابزارهای اتوماسیون برای تغییرات ad hoc فقط روی برخی instanceها استفاده کنید هم همینطور. configuration drift نگهداشت automation سازگار را سختتر میکند.
شکل ۲-۱. configuration drift وقتی است که instanceهای یک چیز در طول زمان متفاوت میشوند.
بهعنوان نمونهٔ diverge شدن زیرساخت در طول زمان، سفر تیم نمونهٔ ما ShopSpinner[^5] را در نظر بگیرید.
ShopSpinner instance جداگانهای از برنامه برای هر فروشگاه اجرا میکند، هر instance برای branding سفارشی و محتوای catalog محصول پیکربندی شده. در روزهای اول، تیم ShopSpinner script مینوشت تا application server جدید برای هر فروشگاه بسازد. تیم زیرساخت را دستی مدیریت میکرد یا script مینوشت و هر بار که تغییر لازم بود tweak میکرد.
یکی از مشتریان، Water Works،[^6] ترافیک بسیار بیشتری به برنامهٔ order management دارد، پس تیم پیکربندی سرور Water Works را tweak کرد. تیم تغییرات را روی مشتریان دیگر اعمال نکرد چون مشغول بود و لازم به نظر نمیرسید.
بعداً تیم ShopSpinner Servermaker[^7] را برای خودکارسازی پیکربندی application server پذیرفت. تیم ابتدا با سرور Palace Pens[^8] — مشتری low-volume — تست کرد و سپس به دیگر مشتریان roll out کرد. متأسفانه کد شامل بهینهسازیهای عملکرد Water Works نبود، پس آن بهبودها را حذف کرد. سرور Water Works تا وقتی تیم اشتباه را catch و fix کرد به crawl کند شد.
تیم ShopSpinner با parameterize کردن کد Servermaker این را حل کرد. اکنون میتواند سطح منابع را برای هر مشتری متفاوت تنظیم کند. اینطور همان کد را روی همهٔ مشتریان اعمال میکند و در عین حال برای هر کدام بهینه میماند. فصل ۷ الگوها و antipatternهای parameterize کردن کد زیرساخت برای instanceهای مختلف را توصیف میکند.
Automation Fear Spiral
automation fear spiral توصیف میکند چگونه بسیاری از تیمها در configuration drift و بدهی فنی فرو میروند.
در یک Open Space دربارهٔ configuration automation در کنفرانس DevOpsDays از گروه پرسیدم چند نفر از ابزارهای اتوماسیون مانند Ansible، Chef یا Puppet استفاده میکنند. اکثریت دست بلند کردند. پرسیدم چند نفر این ابزارها را unattended و با schedule خودکار اجرا میکنند. بیشتر دستها پایین آمد.
بسیاری همان مشکل روزهای اول استفاده از ابزارهای اتوماسیون را دارند. اتوماسیون را selective استفاده میکردم — مثلاً برای ساخت سرور جدید یا یک تغییر پیکربندی خاص. هر بار که اجرا میکردم پیکربندی را tweak میکردم تا با کار خاصی که انجام میدادم بخواند.
میترسیدم پشت به ابزارهای اتوماسیون بدهم چون به آنچه انجام میدهند اطمینان نداشتم.
به اتوماسیون اطمینان نداشتم چون سرورها consistent نبودند.
سرورها consistent نبودند چون اتوماسیون را مکرر و consistent اجرا نمیکردم.
این automation fear spiral است، همانطور که در شکل ۲-۲ نشان داده شده. تیمهای زیرساخت باید این spiral را بشکنند تا اتوماسیون را موفق استفاده کنند. مؤثرترین راه شکستن spiral این است که با ترسهایتان روبهرو شوید. با یک مجموعه سرور شروع کنید. مطمئن شوید میتوانید کد زیرساخت را apply و سپس reapply کنید. سپس process ساعتی schedule کنید که مداوم کد را روی آن سرورها apply کند. مجموعهٔ دیگری انتخاب کنید و تکرار کنید. تا وقتی هر سرور بهطور مداوم بهروز نشده ادامه دهید. monitoring خوب و تست خودکار اطمینان برای synchronize مداوم کد میسازد. این configuration drift را همانطور که رخ میدهد expose میکند تا فوراً fix کنید.
شکل ۲-۲. automation fear spiral
اصل: مطمئن شوید هر فرایندی قابل تکرار است
بر پایهٔ اصل reproducibility، باید بتوانید هر کاری که روی زیرساخت انجام میدهید تکرار کنید. تکرار اقدامات با script و ابزارهای configuration management از دست آسانتر است. اما اتوماسیون کار زیادی میطلبد، بهویژه اگر به آن عادت ندارید.
مثلاً فرض کنید باید hard drive را partition کنم بهعنوان کار one-off. نوشتن و تست script خیلی بیشتر از login و اجرای دستور fdisk کار میخواهد. پس دستی انجام میدهم.
مشکل بعداً میآید، وقتی کس دیگری در تیم، Priya، باید disk دیگری partition کند. او به همان نتیجهٔ من میرسد و کار را دستی انجام میدهد نه نوشتن script. اما تصمیمات کمی متفاوت دربارهٔ partition گرفته. من partition 80 GB /var ext3 روی سرورم ساختم، اما Priya /var را 100 GB xfs روی سرورش ساخت. configuration drift ایجاد میکنیم که توانایی اتوماسیون با اطمینان را erode میکند.
تیمهای زیرساخت مؤثر فرهنگ scripting قوی دارند. اگر میتوانید کاری را script کنید، script کنید.[^9] اگر script کردنش سخت است، عمیقتر بروید. شاید technique یا toolی کمک کند، یا شاید بتوانید کار را سادهتر یا متفاوت handle کنید. شکستن کار به taskهای scriptable معمولاً آن را سادهتر، تمیزتر و reliableتر میکند.
جمعبندی
اصول زیرساخت عصر ابری تفاوتهای زیرساخت سنتی static و زیرساخت مدرن پویا را تجسم میکنند:
- فرض کنید سیستمها unreliable هستند
- همهچیز را reproducible کنید
- چیزهای disposable بسازید
- variation را minimize کنید
- مطمئن شوید هر action قابل تکرار است
این اصول کلید بهرهبرداری از ماهیت پلتفرمهای ابری هستند. بهجای مقاومت در برابر توانایی تغییر با تلاش minimal، از آن توانایی برای دستیابی به کیفیت و reliability بهره ببرید.
[^1]: این ایده را از مقالهٔ Sam Johnson «Simplifying Cloud: Reliability» یاد گرفتم.
[^2]: اصل فرض unreliable بودن سیستمها، chaos engineering را پیش میبرد که در شرایط کنترلشده failure inject میکند تا reliability سرویسها را تست و بهبود دهد. بیشتر در «Chaos Engineering» (صفحهٔ ۳۷۹) میگویم.
[^3]: «Cloud Native and Application-Driven Infrastructure» (صفحهٔ ۱۵۶) را ببینید.
[^4]: این عبارت را اول در ارائهٔ Gavin McCance «CERN Data Centre Evolution» شنیدم. Randy Bias به ارائهٔ Bill Baker «Architectures for Open and Scalable Clouds» credit میدهد. هر دو ارائه مقدمهٔ عالی این اصول هستند.
[^5]: ShopSpinner شرکت فرضی است که به کسبوکارها اجازه میدهد فروشگاه آنلاین راه بیندازند و اجرا کنند. در سراسر کتاب برای illustrate کردن مفاهیم و شیوهها از آن استفاده میکنم.
[^6]: Water Works هر ماه بطری آب آشامیدنی craft متفاوت برایتان میفرستد.
[^7]: Servermaker ابزار فرضی پیکربندی سرور است، شبیه Ansible، Chef یا Puppet.
[^8]: Palace Pens ظرافترین وسایل نوشتن luxury دنیا را میفروشد.
[^9]: همکارم Florian Sellmayr میگوید: «اگر ارزش document کردن دارد، ارزش automate کردن هم دارد.»