حالت تاریک
فصل ۲۰ — گردشکار تیم
استفاده از کد برای ساخت و تغییر زیرساخت روش کاری radically متفاوتی از رویکردهای سنتی است. تغییرات را در سرورهای مجازی و پیکربندی شبکه بهصورت غیرمستقیم میدهیم، نه با تایپ دستور در prompt یا ویرایش مستقیم پیکربندی زنده. نوشتن کد و سپس push کردن آن برای اعمال توسط سیستمهای خودکار تغییری بزرگتر از یادگیری ابزار یا مهارت جدید است.
Infrastructure as Code نحوه کار همه افراد درگیر در طراحی، ساخت و حاکمیت زیرساخت را بهعنوان فرد و گروه تغییر میدهد. این فصل هدف دارد توضیح دهد افراد مختلف چگونه روی کد زیرساخت کار میکنند. فرایندهای کار روی زیرساخت شامل طراحی، تعریف و اعمال کد است.
بعضی ویژگیهای فرایندهای مؤثر برای تیمهایی که Infrastructure as Code را مدیریت میکنند شامل موارد زیر است:
- فرایند خودکار آسانترین و طبیعیترین راه برای اعضای تیم برای دادن تغییرات است.
- افراد راه روشنی برای تضمین کیفیت، operability و همراستایی با سیاستها دارند.
- تیم سیستمهایش را با تلاش کم بهروز نگه میدارد. چیزها جایی که مناسب است سازگارند، و جایی که تغییرات لازم است، روشن و خوب مدیریتشدهاند.
- دانش تیم از سیستم در کد embedded است و روشهای کارشان در اتوماسیون بیان شده.
- خطاها بهسرعت قابل مشاهده و بهراحتی قابل اصلاحاند.
- تغییر کدی که سیستم را تعریف میکند و اتوماسیونی که آن کد را تست و تحویل میدهد آسان و امن است.
بهطور کلی، گردشکار خودکار خوب بهاندازه کافی سریع است تا fix در شرایط اضطراری به سیستمها برسد، تا افراد وسوسه نشوند دستی تغییر دهند و مشکل را برطرف کنند. و بهاندازه کافی قابل اعتماد است که افراد بیشتر از خودشان به آن اعتماد کنند تا دستکاری دستی پیکربندی روی سیستم زنده.
این فصل و فصل بعدی هر دو عناصری از نحوه کار تیم روی کد زیرساخت را بحث میکنند. این فصل روی آنچه افراد در گردشکارشان انجام میدهند تمرکز دارد، در حالی که فصل بعدی به روشهای سازماندهی و مدیریت codebaseهای زیرساخت میپردازد.
اندازهگیری اثربخشی گردشکار شما چهار معیار کلیدی از تحقیق Accelerate، همانطور که در «چهار معیار کلیدی» در صفحه ۹ ذکر شد، پایه خوبی برای تصمیم درباره نحوه اندازهگیری اثربخشی تیم شماست. شواهد نشان میدهد سازمانهایی که در این معیارها عملکرد خوبی دارند معمولاً در برابر اهداف سازمانی اصلیشان، مانند سودآوری و قیمت سهام، هم عملکرد خوبی دارند. تیم شما ممکن است از این معیارها برای ایجاد SLIها (Service Level Indicator)، یعنی چیزهایی برای اندازهگیری، SLOها (Service Level Objective)، یعنی اهدافی که تیم برای خودش استفاده میکند، و SLAها (Service Level Agreement)، یعنی تعهدات به افراد دیگر، استفاده کند.¹ چیزهای مشخصی که اندازهگیری میکنید به زمینه تیم و روشهای مشخصی که میخواهید نتایج سطح بالاتر را بهبود دهید بستگی دارد.
افراد
یک سیستم IT خودکار قابل اعتماد مانند Soylent Green است — ماده مخفی آن افراد است.² در حالی که دستهای انسان نباید برای عبور تغییر کد تا سیستمهای production لازم باشد، جز شاید بررسی نتایج تست و کلیک چند دکمه، افراد برای ساخت، رفع، تطبیق و بهبود مداوم سیستم لازماند.
چند نقش درگیر با بیشتر سیستمهای زیرساخت، خودکار یا غیره، وجود دارد. این نقشها اغلب یکبهیک با افراد map نمیشوند — بعضی افراد بیش از یک نقش دارند و بعضی نقشها را با دیگران share میکنند:
¹ برای اطلاعات بیشتر درباره SLO، SLA و SLI به «SRE Fundamentals» گوگل مراجعه کنید.
² Soylent Green محصول غذایی در فیلم کلاسیک علمیتخیلی dystopian همنام است. اسپویلر: «Soylent Green مردم است!» اگرچه وکلایم توصیه میکنند تأکید کنم که برای سیستم IT خودکار قابل اعتماد، ماده مخفی افراد زنده است.
Users (کاربران) چه کسانی مستقیماً از زیرساخت استفاده میکنند؟ در بسیاری سازمانها، تیمهای برنامه. این تیمها ممکن است برنامهها را توسعه دهند یا برنامههای third-party را پیکربندی و مدیریت کنند.
Governance specialists (متخصصان حاکمیت) بسیاری از افراد سیاستها را در حوزههای مختلف تعیین میکنند، از جمله امنیت، انطباق قانونی، معماری، performance، کنترل هزینه و صحت.
Designers (طراحان) افرادی که زیرساخت را طراحی میکنند. در بعضی سازمانها این افراد معمارند، شاید تقسیمشده به حوزههای مختلف مانند شبکه یا storage.
Toolmakers (سازندگان ابزار) افرادی که سرویسها، ابزارها و اجزایی که تیمهای دیگر برای ساخت یا اجرای محیطها استفاده میکنند فراهم میکنند. نمونهها شامل تیم مانیتورینگ یا توسعهدهندگانی که کتابخانههای کد زیرساخت قابل استفاده مجدد میسازند.
Builders (سازندگان) افرادی که زیرساخت را میسازند و تغییر میدهند. ممکن است این کار را دستی از طریق console یا رابطهای دیگر، با اجرای اسکریپت یا با اجرای ابزارهایی که کد زیرساخت را اعمال میکنند انجام دهند.
Testers (تستکنندگان) افرادی که زیرساخت را validate میکنند. این نقش محدود به QA (quality analyst) نیست. شامل افرادی است که سیستمها را برای حوزه حاکمیتی مانند امنیت یا performance تست یا بررسی میکنند.
Support (پشتیبانی) افرادی که مطمئن میشوند سیستم بهدرستی به اجرا ادامه میدهد و وقتی نمیدهد آن را رفع میکنند.
شکل ۲۰-۱ ساختار کلاسیکی را نشان میدهد، با تیم اختصاصی برای هر بخش گردشکار تغییر سیستم.
شکل ۲۰-۱. نگاشت کلاسیک تیم اختصاصی به هر بخش گردشکار
بسیاری از نقشها ممکن است در حوزههای مختلف زیرساخت تقسیم شوند، مانند شبکه، storage یا سرور. همچنین بالقوه در حوزههای حاکمیتی مانند امنیت، انطباق، معماری و performance تقسیم میشوند. بسیاری از سازمانهای بزرگتر ساختارهای سازمانی baroque از micro-specialty میسازند.³
³ با گروهی در یک بانک بینالمللی کار کردم که چهار محیط تست release جداگانه داشت، یکی برای هر مرحله در فرایند release. برای هر یک از این محیطها، یک تیم زیرساخت را پیکربندی میکرد، تیم دیگر برنامه را deploy و پیکربندی میکرد و سپس تیم سومی آن را تست میکرد. بعضی از این دوازده تیم نمیدانستند همتایانشان وجود دارند. نتیجه اشتراکگذاری دانش کم و نبود سازگاری در فرایند release بود.
با این حال، رایج است یک فرد یا تیم در چند نقش کار کند. مثلاً تیم infosec (information security) ممکن است استانداردها را تعیین کند، ابزار اسکن فراهم کند و ممیزی امنیتی انجام دهد. کمی بعد در این فصل به روشهای بازچینش مسئولیتها نگاه میکنیم (به «بازچینش مسئولیتها» در صفحه ۳۵۲ مراجعه کنید).
چه کسی کد زیرساخت مینویسد؟
چند روش مختلف که سازمانها به سؤال «چه کسی کد زیرساخت را مینویسد و ویرایش میکند» پاسخ میدهند:
Builders کد مینویسند بعضی سازمانها سعی میکنند فرایندها و ساختارهای تیمی سنتی را حفظ کنند. پس تیمی که زیرساخت را میسازد (و شاید پشتیبانی میکند) از ابزارهای Infrastructure as Code برای بهینهسازی کارش استفاده میکند. کاربران محیط درخواست میکنند و تیم build با ابزارها و اسکریپتهایش آن را برایشان میسازد. به «استفاده از Value Stream Mapping برای بهبود گردشکارها» در صفحه ۳۴۳ برای مثالی از اینکه چگونه بهینهسازی فرایند تیم build معمولاً فرایند end-to-end را — چه از نظر سرعت چه کیفیت — بهبود نمیدهد مراجعه کنید.
Users کد مینویسند بسیاری از سازمانها به تیمهای برنامه امکان میدهند زیرساختی که برنامههایشان استفاده میکنند را تعریف کنند. این نیازهای کاربر را با راهحل همراستا میکند. با این حال، یا نیاز دارد هر تیم افرادی با تخصص قوی زیرساخت داشته باشد یا ابزاری که تعریف زیرساخت را ساده کند. چالش با ابزار اطمینان از برآورده کردن نیازهای تیمهای برنامه است، نه محدود کردن آنها.
Toolmakers کد مینویسند تیمهای متخصص میتوانند پلتفرمها، کتابخانهها و ابزارهایی بسازند که به کاربران امکان تعریف زیرساخت مورد نیازشان را بدهند. در این موارد، کاربران بیشتر پیکربندی مینویسند تا کد. تفاوت بین toolmaker و builder در نوشتن کد self-service است. تیم builder کد مینویسد و در پاسخ به درخواستهای کاربران برای ایجاد یا تغییر محیط از آن استفاده میکند. تیم toolmaker کدی مینویسد که کاربران میتوانند برای ایجاد یا تغییر محیطهای خودشان استفاده کنند. به «ساخت لایه انتزاع» در صفحه ۲۸۴ برای مثالی از آنچه toolmakerها ممکن است بسازند مراجعه کنید.
Governance و testerها کد مینویسند افرادی که سیاستها و استانداردها را تعیین میکنند و کسانی که باید تغییرات را تضمین کنند میتوانند ابزارهایی بسازند که به دیگران کمک کند کد خود را verify کنند. این افراد ممکن است toolmaker شوند یا نزدیک toolmakerها کار کنند.
استفاده از Value Stream Mapping برای بهبود گردشکارها Value stream mapping راه مفیدی برای شکستن lead time شماست تا بفهمید زمان کجا میرود.⁴ با اندازهگیری زمان صرفشده روی فعالیتهای مختلف، از جمله انتظار، میتوانید بهبودها را روی حوزههایی متمرکز کنید که بیشترین تفاوت را میسازند. اغلب بخشهایی از فرایندمان را که بهظاهر ناکارآمدتریناند اما تأثیر کمی روی lead time کل دارند بهینه میکنیم. مثلاً تیمهایی را دیدهام اتوماسیون پیادهسازی کنند تا زمان provisioning سرور از هشت ساعت به ده دقیقه کاهش یابد. این کاهش ۹۸٪ عظیمی در زمان provisioning سرور است. اما اگر کاربران معمولاً ده روز برای گرفتن سرور جدیدشان منتظر بمانند، کاهش کل در lead time بسیار کمهیجانانگیزتر ۱۰٪ است. اگر ticketهای درخواست سرور بهطور میانگین هشت روز در صف منتظر بمانند، باید تلاشها را آنجا متمرکز کنید. Value stream mapping زمان تکمیل یک اقدام را visible میکند تا بهترین فرصتهای بهبود را پیدا کنید. به اندازهگیری lead time end-to-end و معیارهای دیگر مانند نرخ شکست ادامه دهید، در حالی که بهبود میدهید. این کمک میکند از بهینهسازیهایی که یک بخش فرایند را بهتر میکند اما جریان کامل را بدتر میکند اجتناب کنید.
⁴ کتاب Value Stream Mapping اثر Karen Martin و Mike Osterling (McGraw-Hill Education) مرجع خوبی است.
اعمال کد روی زیرساخت
گردشکار معمول برای دادن تغییر به زیرساخت با کد در repository منبع مشترک شروع میشود. عضوی از تیم آخرین نسخه کد را به محیط کاری خود میکشد و آنجا ویرایش میکند. وقتی آماده است، کد را به repository منبع push میکند و نسخه جدید کد را روی محیطهای مختلف اعمال میکند.
بسیاری از افراد هنگام شروع با اتوماسیون زیرساخت ابزارهایشان را از خط فرمان در محیط کاری اجرا میکنند. با این حال، این کار دام دارد.
اعمال کد از Workstation محلی
اعمال کد زیرساخت از خط فرمان میتواند برای نمونه تست زیرساختی که هیچکس دیگر استفاده نمیکند مفید باشد. اما اجرای ابزار از محیطهای کاری محلی برای نمونههای مشترک زیرساخت — چه محیط production چه محیط تحویل (به «محیطهای تحویل» در صفحه ۶۶ مراجعه کنید) — مشکل ایجاد میکند.
فرد ممکن است قبل از اعمال، تغییراتی در نسخه محلی کد بدهد. اگر کد را قبل از push تغییرات به repository مشترک اعمال کند، هیچکس دیگر به آن نسخه کد دسترسی ندارد. این میتواند مشکل ایجاد کند اگر کس دیگری نیاز به debug زیرساخت داشته باشد.
اگر فردی که نسخه محلی کد را اعمال کرده فوراً تغییراتش را push نکند، ممکن است کس دیگری نسخه قدیمیتر کد را بکشد و ویرایش کند. وقتی آن کد را اعمال کند، تغییرات فرد اول را revert میکند. این وضعیت بهسرعت گیجکننده و سخت برای untangle شدن میشود (شکل ۲۰-۲ را ببینید).
شکل ۲۰-۲. ویرایش و اعمال محلی کد به تعارض منجر میشود
توجه کنید راهحلهای locking، مانند state locking در Terraform، از این وضعیت جلوگیری نمیکنند. Locking دو نفر را از اعمال همزمان کدشان به همان نمونه متوقف میکند. اما، تا زمان نگارش این کتاب، راهحلهای locking از اعمال نسخههای divergent کد جلوگیری نمیکنند، تا زمانی که هر کدام نوبتشان را صبر کنند.
پس درس این است که برای هر نمونه زیرساخت، کد همیشه باید از همان مکان اعمال شود. میتوانید فردی را مسئول هر نمونه تعیین کنید. اما این دامهای زیادی دارد، از جمله وابستگی پرریسک به یک فرد و workstationش. راهحل بهتر داشتن سیستم مرکزی است که نمونههای مشترک زیرساخت را handle کند.
اعمال کد از سرویس متمرکز
میتوانید از سرویس متمرکز برای اعمال کد زیرساخت روی نمونهها استفاده کنید، چه برنامهای که خودتان host میکنید چه سرویس third-party. سرویس کد را از repository کد منبع یا repository artifact میکشد (به «بستهبندی کد زیرساخت بهعنوان Artifact» در صفحه ۳۲۳ مراجعه کنید) و روی زیرساخت اعمال میکند و فرایند روشن و کنترلشدهای برای مدیریت کدام نسخه کد اعمال میشود اعمال میکند.
اگر دو نفر کد را بکشند و ویرایش کنند، باید هر تفاوتی در کدشان هنگام یکپارچهسازی با branchی که ابزار استفاده میکند حل کنند. وقتی مشکلی هست، دیدن کدام نسخه کد اعمال شده و اصلاح آن آسان است (شکل ۲۰-۳ را ببینید).
شکل ۲۰-۳. یکپارچهسازی و اعمال متمرکز کد
سرویس مرکزی همچنین تضمین میکند ابزار زیرساخت بهطور سازگار اجرا شود، نه اینکه فرض شود فرد اشتباه نمیکند یا workflow را «بهبود» (انحراف) نمیدهد. هر بار همان نسخههای ابزار، اسکریپت و ابزارهای پشتیبان را استفاده میکند.
استفاده از سرویس مرکزی با مدل pipeline برای تحویل کد زیرساخت در محیطها («Pipelineهای تحویل زیرساخت» در صفحه ۱۱۹) همراستاست. هر ابزار یا سرویسی که برای orchestrate تغییرات در pipeline استفاده میکنید مسئولیت اجرای ابزار زیرساخت برای اعمال آخرین نسخه کد روی هر محیط را بر عهده میگیرد.
مزیت دیگر داشتن سرویس مرکزی که کد زیرساخت شما را اجرا میکند این است که شما و تیمتان را مجبور میکند کل فرایند را automate کنید. اگر ابزار را از workstation اجرا کنید، آسان است چند loose end باقی بگذارید — گامهایی که قبل یا بعد از اجرای ابزار باید دستی انجام دهید. سرویس مرکزی انتخابی جز اطمینان از automate بودن کامل وظیفه به شما نمیدهد.
ابزارها و سرویسهایی که ابزار زیرساخت شما را برایتان اجرا میکنند چند گزینه برای سرویس متمرکز اعمال کد زیرساخت وجود دارد. اگر از build server مانند Jenkins یا ابزار CD مانند GoCD یا ConcourseCI استفاده میکنید، میتوانید job یا stage برای اجرای ابزار زیرساخت پیادهسازی کنید. این ابزارها مدیریت نسخههای مختلف کد از repository منبع و ارتقای کد بین مراحل را پشتیبانی میکنند. این ابزارهای چندمنظوره همچنین یکپارچهسازی گردشکارها در برنامهها، زیرساخت و بخشهای دیگر سیستم را آسان میکنند. میتوانید از نمونههای self-hosted این سرویسها یا offering میزبانیشده استفاده کنید. برای اطلاعات بیشتر درباره سرورها و نرمافزار pipeline به «نرمافزار و سرویسهای Pipeline تحویل» در صفحه ۱۲۳ مراجعه کنید. چند vendor محصول یا سرویس تخصصی برای اجرای ابزارهای زیرساخت ارائه میدهند. نمونهها شامل Terraform Cloud، Atlantis و Pulumi for Teams است. WeaveWorks Weave Cloud را فراهم میکند که کد زیرساخت را روی clusterهای Kubernetes اعمال میکند.
نمونههای زیرساخت شخصی
در بیشتر گردشکارهای بحثشده در این کتاب، کد را میکشید، ویرایش میکنید و سپس به repository کد مشترک push میکنید.⁵ سپس فرایند تحویل pipeline آن را روی محیطهای مربوط اعمال میکند.
ایدهآل این است که بتوانید تغییرات کد را قبل از push به repository مشترک تست کنید. این راهی برای اطمینان از اینکه تغییر همانطور که انتظار دارید کار میکند و سریعتر از انتظار برای pipeline که کد را تا مرحله تست online اجرا کند میدهد (به «مراحل تست Online برای Stackها» در صفحه ۱۳۴ مراجعه کنید). همچنین کمک میکند از شکستن build وقتی یکی از تغییرات شما مرحله pipeline را fail میکند و همه کسانی که روی codebase کار میکنند را مختل میکند، اجتناب کنید.
تیم شما میتواند چند کار برای آسانتر کردن تست تغییرات کد قبل از push انجام دهد.
اول، مطمئن شوید هر فردی که روی کد زیرساخت کار میکند میتواند نمونه خودش از زیرساخت ایجاد کند. محدودیتی در آنچه افراد میتوانند بهصورت محلی تست کنند بدون پلتفرم ابری شما وجود دارد، همانطور که در «مراحل تست Offline برای Stackها» در صفحه ۱۳۱ بحث شد.
ممکن است وسوسه شوید نمونههای مشترک «dev» زیرساخت را اجرا کنید. اما همانطور که قبلاً توضیح داده شد، داشتن چند نفر که کد ویرایششده محلی را روی نمونه مشترک اعمال میکنند messy میشود. پس راهی برای spin up نمونه زیرساخت خودشان و destroy کردن وقتی فعال استفاده نمیکنند ایجاد کنید.
دوم، قطعات زیرساخت را کوچک نگه دارید. این البته یکی از سه practice اصلی این کتاب است (فصل ۱۵ را ببینید). باید بتوانید نمونه هر جزء سیستم را بهتنهایی spin up کنید، شاید با استفاده از test fixture برای handle وابستگیها («استفاده از Test Fixture برای مدیریت وابستگیها» در صفحه ۱۳۷ را ببینید). برای افراد سخت است روی نمونههای شخصی کار کنند اگر نیاز به spin up کل سیستم دارند، مگر سیستم استثنائاً کوچک باشد.
سوم، افراد باید همان ابزارها و اسکریپتهایی را برای اعمال و تست نمونههای زیرساختشان استفاده کنند که با نمونههای مشترک، مثلاً در pipeline، استفاده میشود. کمک میکند بستههایی برای ابزار و اسکریپتهایی که در این مکانهای مختلف استفاده میکنید بسازید.⁶
⁵ بهویژه در فصلهای ۸ و ۹.
⁶ batect و Dojo نمونه ابزارهایی هستند که container قابل تکرار و shareable برای توسعه برنامهها و زیرساخت میسازند.
نمونههای شخصی مدیریتشده متمرکز برای افراد امنتر است کد را روی نمونههای شخصی از workstation اعمال کنند تا برای نمونههای مشترک. اما ممکن است مزایایی در استفاده از سرویس متمرکز برای نمونههای شخصی باشد. تیمی را دیدم که برای tear down نمونه شخصی که کسی هنگام رفتن به تعطیلات روشن گذاشته بود مشکل داشت. نمونه را با نسخه محلی کد زیرساخت که به repository push نکرده بود ایجاد کرده بود و destroy کردن را سخت میکرد. پس بعضی تیمها practiceای برقرار میکنند که هر فرد تغییرات را به branch شخصی push کند و سرویس مرکزی آن را روی نمونه زیرساخت شخصی که میتواند تست کند اعمال کند. در این ترتیب، branch شخصی کد محلی را emulate میکند، پس افراد تغییر را committed نمیدانند تا زمانی که به branch مشترک یا trunk merge کرده باشند. اما کد بهصورت مرکزی برای دیگران در دسترس است تا ببینند و در غیابشان استفاده کنند.
Branchهای کد منبع در گردشکارها
Branchها ویژگی قدرتمندی از repositoryهای منبع مشترک هستند که برای افراد آسانتر میکنند تغییرات را روی کپیهای مختلف codebase — branchها — بدهند و سپس وقتی آمادهاند کارشان را یکپارچه کنند. استراتژیها و الگوهای زیادی برای استفاده از branchها بهعنوان بخشی از گردشکار تیم وجود دارد. بهجای توسعه آنها اینجا، شما را به مقاله Martin Fowler، «Patterns for Managing Source Code Branches» ارجاع میدهم.
ارزش دارد چند تمایز استراتژی branching در زمینه Infrastructure as Code را برجسته کنیم. یکی تفاوت بین الگوهای path to production و الگوهای یکپارچهسازی برای branching است. دیگری اهمیت integration frequency است.
تیمها از الگوهای branching path to production برای مدیریت کدام نسخههای کد روی محیطها اعمال شوند استفاده میکنند.⁷ الگوهای معمول path to production شامل release branch و environment branch است (environment branch در «تحویل کد از repository کد منبع» در صفحه ۳۲۵ بحث شده).
الگوهای یکپارچهسازی برای branching روشهایی برای افرادی که روی codebase کار میکنند توصیف میکند که چه زمانی و چگونه کارشان را یکپارچه کنند.⁸ بیشتر تیمها از الگوی mainline integration استفاده میکنند، چه با feature branching چه continuous integration.
الگو یا استراتژی مشخص کماهمیتتر از نحوه استفاده شماست. مهمترین عامل در اثربخشی استفاده تیم از branchها integration frequency است — چند وقت یکبار همه کدشان را به همان branch (اصلی) repository مرکزی merge میکنند.⁹ تحقیق DORA Accelerate نشان میدهد یکپارچهسازی مکررتر همه کد درون تیم با عملکرد تجاری بالاتر همبستگی دارد. نتایجشان پیشنهاد میکند همه در تیم باید همه کدشان را با هم یکپارچه کنند — مثلاً به main یا trunk — حداقل یکبار در روز.
⁷ بخش path to production مقاله Fowler، «Patterns for Managing Source Code Branches» را ببینید.
⁸ Fowler همچنین الگوهای یکپارچهسازی را در مقاله توصیف میکند.
⁹ بخش integration frequency را برای بررسی دقیق ببینید.
Merge کردن یکپارچهسازی نیست گاهی افراد اجرای خودکار تستها توسط build server روی branchها را با continuous integration اشتباه میگیرند. practice continuous integration و همبستگی با عملکرد بالاتر تیم بر اساس یکپارچهسازی کامل همه تغییراتی است که همه روی آن کار میکنند در codebase. اگرچه کسی که از الگوی feature branch استفاده میکند ممکن است مکرراً branch اصلی فعلی را به branch خود merge کند، معمولاً کار خودش را به main برنمیگرداند تا feature را تمام کرده باشد. و اگر افراد دیگر همینطور روی feature branchهای خودشان کار میکنند، کد تا وقتی همه feature را تمام نکرده و تغییراتشان را به branch اصلی merge نکردهاند کاملاً یکپارچه نیست. یکپارچهسازی شامل merge در هر دو جهت است — افراد merge تغییرات خود به branch اصلی و همچنین merge main به branch یا کپی محلی کد. بنابراین continuous integration یعنی همه این کار را هنگام کار انجام دهند، حداقل یکبار در روز.
جلوگیری از Configuration Drift
فصل ۲ خطرات configuration drift را توصیف کرد (به «Configuration Drift» در صفحه ۱۷ مراجعه کنید)، جایی که عناصر زیرساخت مشابه با گذشت زمان ناسازگار میشوند. configuration drift اغلب وقتی رخ میدهد که تیمها از ابزارهای کدنویسی زیرساخت برای automate کردن بخشهایی از روشهای قدیمیتر کار استفاده میکنند، نه اینکه کاملاً روشهای کارشان را تطبیق دهند.
چند کار در گردشکارها برای اجتناب از configuration drift میتوانید انجام دهید.
به حداقل رساندن Automation Lag
Automation lag زمان بین نمونههای اجرای فرایند خودکار، مانند اعمال کد زیرساخت، است. هرچه از آخرین بار اجرای فرایند بیشتر گذشته باشد، احتمال fail شدن بیشتر است.¹⁰ چیزها با گذشت زمان تغییر میکنند، حتی وقتی کسی آگاهانه تغییری نداده.
حتی اگر کد تغییر نکرده باشد، اعمال آن بعد از فاصله طولانی ممکن است باز هم fail شود، به دلایل مختلف:
- کسی بخش دیگری از سیستم، مانند وابستگی، را به روشی تغییر داده که فقط وقتی کد شما دوباره اعمال میشود میشکند.
- upgrade یا تغییر پیکربندی ابزار یا سرویسی که برای اعمال کد استفاده میشود ممکن است با کد شما ناسازگار باشد.
- اعمال کد بدون تغییر ممکن است با این حال بهروزرسانیهای وابستگیهای transitive، مانند بستههای سیستمعامل، بیاورد.
- کسی ممکن است fix یا بهبود دستی داده باشد که فراموش کرده به کد برگرداند. اعمال مجدد کد شما fix را revert میکند.
نتیجه automation lag این است: هرچه مکررتر کد زیرساخت را اعمال کنید، احتمال fail شدن کمتر است. وقتی شکستها رخ میدهند، میتوانید علت را سریعتر کشف کنید، چون از آخرین اجرای موفق کمتر تغییر کرده.
اجتناب از Apply Ad Hoc
یکی از عادتهایی که بعضی تیمها از روشهای کار عصر آهن حمل میکنند فقط اعمال کد برای تغییر مشخص است. ممکن است فقط از کد زیرساخت برای provisioning زیرساخت جدید استفاده کنند، نه برای تغییر سیستمهای موجود. یا ممکن است کد زیرساخت بنویسند و اعمال کنند برای تغییرات ad hoc به بخشهای مشخص سیستم. مثلاً تغییر پیکربندی one-off برای یکی از application serverها را کد میزنند. حتی وقتی تیمها از کد برای تغییر استفاده میکنند و کد را روی همه نمونهها اعمال میکنند، گاهی فقط وقتی کد را تغییر میدهند اعمال میکنند.
این عادتها میتوانند configuration drift یا automation lag ایجاد کنند.
اعمال مداوم کد
استراتژی اصلی برای حذف configuration drift اعمال مداوم کد زیرساخت روی نمونههاست، حتی وقتی کد تغییر نکرده. بسیاری از ابزارهای پیکربندی سرور، از جمله Chef و Puppet، برای اعمال مجدد پیکربندی در برنامهای، معمولاً ساعتی، طراحی شدهاند.¹¹
¹⁰ automation lag به انواع دیگر اتوماسیون هم اعمال میشود. مثلاً اگر فقط در پایان چرخه release طولانی test suite خودکار برنامه را اجرا کنید، روزها یا هفتهها صرف بهروزرسانی test suite برای تطبیق با تغییرات کد میکنید. اگر تستها را هر بار که تغییر کد commit میکنید اجرا کنید، فقط چند تغییر برای تطبیق با کد لازم است، پس test suite کامل همیشه آماده اجراست.
¹¹ ConfigurationSynchronization را برای بیان اولیه این مفهوم ببینید.
متدولوژی GitOps (به «GitOps» در صفحه ۳۵۱ مراجعه کنید) شامل اعمال مداوم کد از branch کد منبع به هر محیط است. باید بتوانید از سرویس مرکزی برای اعمال کد (همانطور که در «اعمال کد از سرویس متمرکز» در صفحه ۳۴۵ توضیح داده شد) برای اعمال مجدد مداوم کد روی هر نمونه استفاده کنید.
زیرساخت Immutable
زیرساخت immutable مشکل configuration drift را به روش دیگری حل میکند. بهجای اعمال مکرر کد پیکربندی روی نمونه زیرساخت، فقط یکبار هنگام ایجاد نمونه اعمال میکنید. وقتی کد تغییر میکند، نمونه جدید میسازید و جایگزین قدیمی میکنید.
ایجاد تغییر با ساخت نمونه جدید به تکنیکهای پیچیده برای اجتناب از downtime («تغییرات Zero Downtime» در صفحه ۳۷۵) نیاز دارد و ممکن است برای همه use caseها قابل اجرا نباشد. automation lag همچنان بالقوه مسئله است، پس تیمهایی که زیرساخت immutable استفاده میکنند تمایل دارند نمونهها را مکرراً rebuild کنند، مانند phoenix server.¹²
GitOps GitOps نوعی از Infrastructure as Code است که شامل همگامسازی مداوم کد از branchهای کد منبع به محیطها میشود. GitOps بر تعریف سیستمها بهعنوان کد تأکید دارد (به «Practice اصلی: همه چیز را بهعنوان کد تعریف کنید» در صفحه ۱۰ مراجعه کنید). GitOps رویکردی برای تست و تحویل کد زیرساخت تجویز نمیکند، اما با استفاده از pipeline برای تحویل کد («Pipelineهای تحویل زیرساخت» در صفحه ۱۱۹) سازگار است. با این حال، GitOps استفاده از artifactهای تحویل («بستهبندی کد زیرساخت بهعنوان Artifact» در صفحه ۳۲۳) را discourage میکند و در عوض تغییرات کد را با merge به branchهای کد منبع promote میکند (به «تحویل کد از repository کد منبع» در صفحه ۳۲۵ مراجعه کنید). عنصر کلیدی دیگر GitOps همگامسازی مداوم کد با سیستمهاست («اعمال مداوم کد» در صفحه ۳۵۰). بهجای داشتن job build server یا stage pipeline که کد را هنگام تغییر اعمال میکند («اجتناب از Apply Ad Hoc» در صفحه ۳۵۰)، GitOps از سرویسی استفاده میکند که مداوم کد را با سیستم مقایسه میکند و configuration drift را کاهش میدهد (به «Configuration Drift» در صفحه ۱۷ مراجعه کنید). بعضی تیمها فرایندشان را GitOps توصیف میکنند، اما فقط practice branch برای محیطها را بدون همگامسازی مداوم کد با محیطها پیادهسازی میکنند. این آسان است به فرایند تغییر ad hoc و عادتهای بد کپی، paste و ویرایش تغییرات کد برای هر محیط بیفتید، مطابق ضدالگوی copy-paste (به «ضدالگو: Copy-Paste Environments» در صفحه ۷۰ مراجعه کنید).
¹² phoenix server مکرراً rebuild میشود تا فرایند provisioning قابل تکرار باشد. این با سازههای زیرساخت دیگر، از جمله stackهای زیرساخت، هم قابل انجام است.
حاکمیت در گردشکار مبتنی بر Pipeline
حاکمیت نگرانی برای بیشتر سازمانهاست، بهویژه بزرگترها و کسانی که در صنایع تنظیمشده مانند مالی و بهداشت کار میکنند. بعضی افراد حاکمیت را کلمه کثیفی میبینند که به معنای افزودن اصطکاک غیرضروری به انجام کار مفید است. اما حاکمیت فقط یعنی اطمینان از انجام مسئولانه کارها مطابق سیاستهای سازمان.
فصل ۱ توضیح داد کیفیت — حاکمیت جنبهای از کیفیت است — میتواند سرعت تحویل را enable کند و توانایی تحویل سریع تغییرات میتواند کیفیت را بهبود دهد (به «از Infrastructure as Code برای بهینهسازی تغییر استفاده کنید» در صفحه ۴ مراجعه کنید). Compliance as Code¹³ اتوماسیون و practiceهای کاری مشارکتیتر را leverage میکند تا این حلقه مثبت کار کند.
بازچینش مسئولیتها
تعریف سیستمها بهعنوان کد فرصتهایی برای بازچینش مسئولیتهای افراد درگیر در کار روی زیرساخت (افراد فهرستشده در «افراد» در صفحه ۳۴۰) و نحوه engagement آنها با کارشان ایجاد میکند. بعضی عواملی که این فرصتها را ایجاد میکنند:
Reuse (استفاده مجدد) کد زیرساخت میتواند طراحی، بررسی و در چند محیط و سیستم استفاده مجدد شود. اگر از کدی که قبلاً از آن فرایند عبور کرده استفاده کنید، به تمرین طراحی، بررسی و signoff طولانی برای هر سرور یا محیط جدید نیاز ندارید.
Working code (کد در حال کار) چون نوشتن کد سریع است، افراد میتوانند بر اساس کد در حال کار و زیرساخت نمونهای بررسی و تصمیم بگیرند. این حلقههای بازخورد سریعتر و دقیقتر از چانهزنی روی نمودارها و مشخصات میسازد.
Consistency (سازگاری) کد شما محیطها را بسیار سازگارتر از انسانهایی که checklist دنبال میکنند ایجاد میکند. پس تست و بررسی زیرساخت در محیطهای زودتر بازخورد سریعتر و بهتری نسبت به انجام این کارها دیرتر در فرایند میدهد.
Automated testing (تست خودکار) تست خودکار، از جمله برای نگرانیهای حاکمیتی مانند امنیت و انطباق، به افراد کارکننده روی کد زیرساخت بازخورد سریع میدهد. میتوانند بسیاری از مشکلات را هنگام کار اصلاح کنند، بدون نیاز به درگیر کردن متخصصان برای مسائل routine.
¹³ برای مقالات درباره compliance as code به وبسایت O'Reilly مراجعه کنید.
Democratize quality (دموکراتیک کردن کیفیت) افرادی که متخصص نیستند میتوانند تغییراتی در کد برای حوزههای بالقوه حساس زیرساخت، مانند شبکه و سیاستهای امنیتی، بدهند. میتوانند از ابزارها و تستهایی که متخصصان ساختهاند برای sanity check تغییراتشان استفاده کنند. و متخصصان همچنان میتوانند تغییرات را قبل از اعمال به سیستمهای production بررسی و تأیید کنند. بررسی اینطور کارآمدتر است چون متخصص میتواند مستقیماً کد، گزارش تست و نمونههای تست در حال کار را ببیند.
Governance channels (کانالهای حاکمیت) codebase زیرساخت و pipelineهایی که برای تحویل تغییرات به نمونههای production استفاده میشوند میتوانند بر اساس نیازهای حاکمیتیشان سازماندهی شوند. پس تغییر در سیاستهای امنیتی از مرحله بررسی و signoffی عبور میکند که لزوماً برای تغییرات در حوزههای کمحساستر لازم نیست.
بسیاری از روشهایی که میتوانیم نحوه مدیریت سیستمها را تغییر دهیم شامل shift کردن مسئولیتها به چپ در فرایند است.
Shift Left
فصل ۸ اصول و practiceها برای پیادهسازی تست خودکار و pipeline برای تحویل تغییرات کد به محیطها را توضیح میدهد. اصطلاح shift left توصیف میکند این چگونه بر گردشکارها و practiceهای تحویل تأثیر میگذارد.
کد در حین پیادهسازی، در انتهای «چپ» جریان نشاندادهشده در بیشتر نمودارهای فرایند، بهشدت تست میشود. پس سازمانها میتوانند زمان کمتری روی فرایندهای heavyweight در انتهای «راست»، درست قبل از اعمال کد به production، صرف کنند.
افراد درگیر در حاکمیت و تست روی آنچه در پیادهسازی اتفاق میافتد تمرکز میکنند، با تیمها کار میکنند، ابزار فراهم میکنند و practiceها را برای تست زود و مکرر enable میکنند.
نمونه فرایندی برای Infrastructure as Code با حاکمیت
ShopSpinner stack قابل استفاده مجدد دارد («الگو: Reusable Stack» در صفحه ۷۲) که میتواند زیرساخت application server برای host کردن نمونه سرویسش برای مشتری ایجاد کند. وقتی کسی کد این stack را تغییر میدهد، میتواند روی همه مشتریانش تأثیر بگذارد.
گروه رهبری فنی آن، مسئول تصمیمات معماری، CFRها را تعریف میکند (همانطور که در «چه چیزهایی را با زیرساخت تست کنیم؟» در صفحه ۱۰۸ توضیح داده شد) که زیرساخت application server باید پشتیبانی کند. این CFRها شامل تعداد و فرکانس سفارشهایی که کاربران میتوانند روی نمونه مشتری ثبت کنند، زمان پاسخ رابط و زمان بازیابی برای شکست سرور است.
تیم زیرساخت و تیم برنامه با جفت Site Reliability Engineer (SRE) و QA برای پیادهسازی تستهای خودکاری که performance stack application server را در برابر CFRها بررسی میکند همکاری میکنند. این تستها را در چند مرحله pipeline میسازند و بهتدریج اجزای مختلف stack را تست میکنند (مطابق «تست تدریجی» در صفحه ۱۱۵).
وقتی این تستها جا افتادند، افراد نیازی به ارسال تغییرات زیرساخت برای بررسی توسط گروه رهبری فنی، SREها یا کس دیگر ندارند. وقتی مهندسی پیکربندی شبکه را تغییر میدهد، مثلاً، pipeline بهطور خودکار بررسی میکند آیا زیرساخت حاصل هنوز CFRها را برآورده میکند قبل از اینکه بتواند آن را روی نمونههای production مشتری اعمال کند. اگر مهندس اشتباهی کند که CFR را میشکند، ظرف چند دقیقه وقتی مرحله pipeline قرمز میشود میفهمد و فوراً اصلاح میکند.
در بعضی موارد، تغییر ممکن است مشکلی در نمونه مشتری ایجاد کند که تستهای خودکار نگرفته. گروه میتواند blameless postmortem انجام دهد تا بررسی کند چه اتفاقی افتاد. شاید مشکل این بود که هیچیک از CFRها آن وضعیت را پوشش نمیداد، پس باید CFR را در فهرستشان تغییر دهند یا اضافه کنند. یا تستشان gap داشت که مسئله را از دست داد، که در آن صورت test suite را بهبود میدهند.
نرمالسازی فرایند Fix اضطراری بسیاری از تیمها فرایند جداگانهای برای تغییرات اضطراری دارند تا fixها را سریع تحویل دهند. نیاز به فرایود جداگانه برای fixهای سریعتر نشانهای است که فرایند تغییر عادی میتواند بهبود یابد. فرایند تغییر اضطراری در یکی از دو روش سرعت میدهد. یکی حذف گامهای غیرضروری است. دیگری حذف گامهای ضروری است. اگر بتوانید گامی را در اضطراری، وقتی فشار است و stakes بالاست، با امنیت حذف کنید، احتمالاً میتوانید آن را از فرایند عادی هم حذف کنید. اگر رد کردن گامی ریسک غیرقابل قبول دارد، راهی برای handle کارآمدتر پیدا کنید و هر بار انجام دهید.¹⁴
¹⁴ Steve Smith این را ضدالگوی dual value streams تعریف میکند.
جمعبندی
وقتی سازمانی Infrastructure as Code خود را تعریف میکند، افرادش باید زمان کمتری صرف انجام فعالیتهای routine و نقش gatekeeper کنند. در عوض باید زمان بیشتری صرف بهبود مداوم تواناییشان برای بهبود خود سیستم کنند. تلاشهایشان در چهار معیار تحویل نرمافزار و عملکرد عملیاتی منعکس خواهد شد.