ProHoster > وبلاگ > اداره > مشکل تمیز کردن "هوشمند" تصاویر ظروف و راه حل آن در ورف
مشکل تمیز کردن "هوشمند" تصاویر ظروف و راه حل آن در ورف
این مقاله مشکلات تمیز کردن تصاویری را که در رجیستری کانتینر انباشته میشوند (رجیستری داکر و آنالوگهای آن) در واقعیتهای خطوط لوله CI/CD مدرن برای برنامههای کاربردی ابری تحویل داده شده به Kubernetes مورد بحث قرار میدهد. معیارهای اصلی برای مرتبط بودن تصاویر و مشکلات ناشی از آن در تمیز کردن خودکار، صرفه جویی در فضا و برآوردن نیازهای تیم ها ارائه شده است. در نهایت، با استفاده از مثال یک پروژه منبع باز خاص، به شما خواهیم گفت که چگونه می توان بر این مشکلات غلبه کرد.
معرفی
تعداد تصاویر در یک رجیستری کانتینر می تواند به سرعت رشد کند، فضای ذخیره سازی بیشتری را اشغال کند و در نتیجه هزینه آن را به طور قابل توجهی افزایش دهد. برای کنترل، محدود کردن یا حفظ رشد قابل قبول فضای اشغال شده در رجیستری، پذیرفته می شود:
استفاده از تعداد ثابتی از برچسب ها برای تصاویر.
تصاویر را به نوعی پاک کنید.
اولین محدودیت گاهی اوقات برای تیم های کوچک قابل قبول است. اگر توسعه دهندگان برچسب های دائمی کافی داشته باشند (latest, main, test, boris و غیره)، اندازه رجیستری متورم نخواهد شد و برای مدت طولانی دیگر لازم نیست به تمیز کردن آن فکر کنید. از این گذشته ، تمام تصاویر نامربوط پاک می شوند و به سادگی هیچ کاری برای تمیز کردن باقی نمی ماند (همه چیز توسط یک زباله جمع کن معمولی انجام می شود).
با این حال، این رویکرد تا حد زیادی توسعه را محدود می کند و به ندرت برای پروژه های مدرن CI/CD قابل استفاده است. بخشی جدایی ناپذیر از توسعه بود اتوماسیون، که به شما امکان می دهد تا عملکردهای جدید را بسیار سریعتر آزمایش، استقرار و به کاربران ارائه دهید. به عنوان مثال، در تمام پروژه های ما، یک خط لوله CI به طور خودکار با هر commit ایجاد می شود. در آن، تصویر مونتاژ میشود، آزمایش میشود، برای اشکالزدایی و بررسیهای باقیمانده به مدارهای مختلف Kubernetes فرستاده میشود، و اگر همه چیز خوب باشد، تغییرات به کاربر نهایی میرسد. و این دیگر علم موشک نیست، بلکه یک اتفاق روزمره برای بسیاری است - به احتمال زیاد برای شما، زیرا در حال خواندن این مقاله هستید.
از آنجایی که رفع اشکالات و توسعه عملکردهای جدید به صورت موازی انجام می شود و انتشار می تواند چندین بار در روز انجام شود، بدیهی است که روند توسعه با تعداد قابل توجهی از commit ها همراه است. تعداد زیادی عکس در رجیستری. در نتیجه، موضوع سازماندهی پاکسازی مؤثر رجیستری مطرح می شود، یعنی. حذف تصاویر نامربوط
اما چگونه می توان تشخیص داد که یک تصویر مرتبط است؟
معیارهای مربوط به تصویر
در اکثریت قریب به اتفاق موارد، معیارهای اصلی عبارتند از:
1. اولین (بدیهی ترین و انتقادی ترین از همه) تصاویری است که در حال حاضر در Kubernetes استفاده می شود. حذف این تصاویر می تواند منجر به هزینه های قابل توجهی در زمان توقف تولید شود (به عنوان مثال، تصاویر ممکن است برای تکرار مورد نیاز باشند) یا تلاش های تیم برای رفع اشکال در هر یک از حلقه ها را خنثی کند. (به همین دلیل حتی یک برنامه ویژه ساختیم صادرکننده پرومتئوس، که عدم وجود چنین تصاویری را در هر خوشه Kubernetes ردیابی می کند.)
2. دوم (کمتر واضح است، اما همچنین بسیار مهم است و دوباره به بهره برداری مربوط می شود) - تصاویری که برای برگشت در صورت تشخیص مشکلات جدی مورد نیاز است در نسخه فعلی به عنوان مثال، در مورد Helm، اینها تصاویری هستند که در نسخه های ذخیره شده نسخه استفاده می شوند. (به هر حال، به طور پیش فرض در Helm محدودیت 256 ویرایش است، اما بعید است که کسی واقعاً نیاز به ذخیره داشته باشد چنین تعداد زیادی نسخه؟..) بالاخره ما مخصوصاً نسخه ها را ذخیره می کنیم تا بتوانیم بعداً از آنها استفاده کنیم. در صورت لزوم به آنها "برگردید".
3. سوم - نیازهای توسعه دهنده: تمامی تصاویری که مربوط به کار فعلی آنهاست. به عنوان مثال، اگر ما یک PR را در نظر می گیریم، منطقی است که یک تصویر مربوط به آخرین commit و مثلاً commit قبلی باقی بگذاریم: به این ترتیب توسعه دهنده می تواند به سرعت به هر کاری بازگردد و با آخرین تغییرات کار کند.
4. چهارم - تصاویری که با نسخه های برنامه ما مطابقت دارد، یعنی محصول نهایی هستند: v1.0.0، 20.04.01/XNUMX/XNUMX، sierra و غیره.
توجه: معیارهای تعریف شده در اینجا بر اساس تجربه تعامل با ده ها تیم توسعه از شرکت های مختلف فرموله شده است. البته، بسته به ویژگیهای فرآیندهای توسعه و زیرساخت مورد استفاده (مثلاً از Kubernetes استفاده نمیشود)، این معیارها ممکن است متفاوت باشند.
واجد شرایط بودن و راه حل های موجود
سرویس های محبوب با ثبت کانتینر، به عنوان یک قاعده، سیاست های پاکسازی تصویر خود را ارائه می دهند: در آنها می توانید شرایطی را تعریف کنید که تحت آن یک برچسب از رجیستری حذف می شود. با این حال، این شرایط توسط پارامترهایی مانند نام، زمان ایجاد، و تعداد تگ ها * محدود می شود.
* به پیاده سازی رجیستری کانتینر خاص بستگی دارد. ما امکانات راه حل های زیر را در نظر گرفتیم: Azure CR، Docker Hub، ECR، GCR، GitHub Packages، GitLab Container Registry، Harbor Registry، JFrog Artifactory، Quay.io - از سپتامبر 2020.
این مجموعه از پارامترها برای برآورده کردن معیار چهارم - یعنی انتخاب تصاویری که مطابق با نسخه ها هستند - کاملاً کافی است. با این حال، برای همه معیارهای دیگر، فرد باید نوعی راه حل سازش را انتخاب کند (سیاست سخت تر یا برعکس، سیاست ملایم تر) - بسته به انتظارات و توانایی های مالی.
به عنوان مثال، سومین معیار - مربوط به نیازهای توسعه دهندگان - را می توان با سازماندهی فرآیندها در تیم ها حل کرد: نامگذاری خاص تصاویر، حفظ لیست های مجاز ویژه و توافقات داخلی. اما در نهایت هنوز باید خودکار شود. و اگر قابلیت های راه حل های آماده کافی نیست، باید کاری از خودتان انجام دهید.
وضعیت دو معیار اول مشابه است: آنها نمی توانند بدون دریافت داده از یک سیستم خارجی - سیستمی که برنامه ها در آن مستقر هستند (در مورد ما، Kubernetes) ارضا شوند.
تصویر گردش کار در Git
فرض کنید شما در Git چیزی شبیه به این کار می کنید:
نماد با سر در نمودار، تصاویر ظرفی را نشان میدهد که در حال حاضر در Kubernetes برای هر کاربر (کاربران نهایی، آزمایشکنندگان، مدیران و غیره) مستقر شدهاند یا توسط توسعهدهندگان برای اشکالزدایی و اهداف مشابه استفاده میشوند.
چه اتفاقی میافتد اگر خطمشیهای پاکسازی فقط اجازه دهند تصاویر حفظ شوند (نه حذف شوند) با نام تگ های داده شده?
بدیهی است که چنین سناریویی هیچ کس را خوشحال نخواهد کرد.
اگر خطمشیها اجازه دهند تصاویر حذف نشوند، چه چیزی تغییر میکند؟ با توجه به بازه زمانی معین / تعداد آخرین تعهدات?
نتیجه بسیار بهتر شده است، اما هنوز با ایده آل فاصله دارد. از این گذشته، ما هنوز توسعه دهندگانی داریم که برای رفع اشکال به تصاویر در رجیستری (یا حتی مستقر در K8s) نیاز دارند...
برای خلاصه کردن وضعیت فعلی بازار: عملکردهای موجود در رجیستری کانتینر انعطاف کافی را هنگام تمیز کردن ارائه نمی دهند و دلیل اصلی این امر این است که هیچ راهی برای تعامل با دنیای خارج وجود ندارد. به نظر می رسد که تیم هایی که به چنین انعطاف پذیری نیاز دارند مجبور هستند به طور مستقل حذف تصویر "از بیرون" را با استفاده از Docker Registry API (یا API بومی پیاده سازی مربوطه) اجرا کنند.
با این حال، ما به دنبال راه حلی جهانی بودیم که پاکسازی تصویر را برای تیم های مختلف با استفاده از رجیستری های مختلف به طور خودکار انجام دهد.
مسیر ما برای تمیز کردن تصویر جهانی
این نیاز از کجا می آید؟ واقعیت این است که ما یک گروه جداگانه از توسعه دهندگان نیستیم، بلکه تیمی هستیم که به بسیاری از آنها به طور همزمان خدمت می کند و به حل همه جانبه مسائل CI/CD کمک می کند. و ابزار فنی اصلی برای این ابزار منبع باز است ورف. ویژگی آن این است که یک عملکرد واحد را انجام نمی دهد، بلکه فرآیندهای تحویل مداوم را در تمام مراحل همراهی می کند: از مونتاژ تا استقرار.
انتشار تصاویر در رجیستری* (بلافاصله پس از ساخت آنها) یکی از عملکردهای آشکار چنین ابزاری است. و از آنجایی که تصاویر برای ذخیره سازی در آنجا قرار می گیرند، پس - اگر فضای ذخیره سازی شما نامحدود نیست - باید مسئول تمیز کردن بعدی آنها باشید. اینکه چگونه ما در این مورد به موفقیت دست یافتیم، با رعایت تمام معیارهای مشخص شده، بیشتر مورد بحث قرار خواهد گرفت.
* اگرچه ممکن است خود رجیستری ها متفاوت باشند (Docker Registry، GitLab Container Registry، Harbor و غیره)، اما کاربران آنها با مشکلات مشابهی روبرو هستند. راه حل جهانی در مورد ما به اجرای رجیستری بستگی ندارد، زیرا خارج از خود رجیستری ها اجرا می شود و رفتار یکسانی را برای همه ارائه می دهد.
اگرچه ما از werf به عنوان نمونه پیادهسازی استفاده میکنیم، امیدواریم که رویکردهای مورد استفاده برای سایر تیمهایی که با مشکلات مشابه مواجه هستند مفید باشد.
پس مشغول شدیم خارجی اجرای مکانیزمی برای تمیز کردن تصاویر - به جای آن قابلیت هایی که قبلاً در رجیستری ها برای ظروف ساخته شده است. اولین قدم استفاده از Docker Registry API برای ایجاد همان سیاست های اولیه برای تعداد تگ ها و زمان ایجاد آنها بود (که در بالا ذکر شد). به آنها اضافه شد لیست مجاز بر اساس تصاویر مورد استفاده در زیرساخت مستقر شده است، یعنی کوبرنتیس برای دومی، استفاده از Kubernetes API برای تکرار در تمام منابع مستقر و دریافت لیستی از مقادیر کافی بود. image.
این راه حل بی اهمیت بحرانی ترین مشکل (معیار شماره 1) را حل کرد، اما تنها آغاز سفر ما برای بهبود مکانیسم تمیز کردن بود. مرحله بعدی - و بسیار جالب تر - تصمیم گیری بود تصاویر منتشر شده را با تاریخچه Git مرتبط کنید.
طرح های برچسب گذاری
برای شروع، ما رویکردی را انتخاب کردیم که در آن تصویر نهایی باید اطلاعات لازم برای تمیز کردن را ذخیره کند و فرآیند را بر اساس طرحهای برچسبگذاری بنا کرد. هنگام انتشار یک تصویر، کاربر یک گزینه برچسب گذاری خاص را انتخاب کرد (git-branch, git-commit یا git-tag) و از مقدار مربوطه استفاده کرد. در سیستم های CI، این مقادیر به طور خودکار بر اساس متغیرهای محیطی تنظیم می شوند. در حقیقت تصویر نهایی با یک Git اولیه خاص مرتبط بود، ذخیره داده های لازم برای تمیز کردن در برچسب ها.
این رویکرد منجر به مجموعهای از خطمشیها شد که به Git اجازه میداد به عنوان منبع منفرد حقیقت استفاده شود:
هنگام حذف یک شاخه/تگ در Git، تصاویر مرتبط در رجیستری به طور خودکار حذف میشوند.
تعداد تصاویر مرتبط با تگها و commitهای Git را میتوان با تعداد تگهای استفاده شده در طرح انتخابی و زمانی که commit مرتبط ایجاد شد، کنترل کرد.
به طور کلی، اجرای حاصل نیازهای ما را برآورده کرد، اما به زودی چالش جدیدی در انتظار ما بود. واقعیت این است که هنگام استفاده از طرحهای برچسبگذاری مبتنی بر Git اولیه، با تعدادی کاستی مواجه شدیم. (از آنجایی که شرح آنها خارج از حوصله این مقاله است، همه می توانند با جزئیات آشنا شوند اینجا.) بنابراین، با تصمیم به تغییر به یک رویکرد کارآمدتر برای برچسب گذاری (برچسب گذاری مبتنی بر محتوا)، مجبور شدیم در اجرای تمیز کردن تصویر تجدید نظر کنیم.
الگوریتم جدید
چرا؟ با تگ گذاری مبتنی بر محتوا، هر تگ می تواند چندین commit را در Git برآورده کند. هنگام تمیز کردن تصاویر، دیگر نمی توانید فرض کنید تنها از commit که در آن تگ جدید به رجیستری اضافه شده است.
برای الگوریتم تمیز کردن جدید، تصمیم گرفته شد که از طرحهای برچسبگذاری فاصله بگیریم و بسازیم فرآیند فرا تصویر، که هر کدام دسته ای از موارد زیر را ذخیره می کنند:
تعهدی که در آن انتشار انجام شده است (مهم نیست که تصویر اضافه شده، تغییر کرده یا در رجیستری کانتینر یکسان باقی مانده است).
و شناسه داخلی ما مربوط به تصویر مونتاژ شده است.
به عبارت دیگر ارائه شد پیوند برچسب های منتشر شده با commit ها در Git.
پیکربندی نهایی و الگوریتم کلی
هنگام پیکربندی تمیز کردن، کاربران اکنون به خط مشی هایی دسترسی دارند که تصاویر فعلی را انتخاب می کنند. هر یک از این سیاست ها تعریف می شود:
بسیاری از مراجع، یعنی تگ های Git یا شاخه های Git که در حین اسکن استفاده می شوند.
و محدودیت تصاویر جستجو شده برای هر مرجع از مجموعه.
برای نشان دادن، این چیزی است که پیکربندی خط مشی پیش فرض شروع به شکل گیری کرد:
این پیکربندی شامل سه خط مشی است که با قوانین زیر مطابقت دارد:
تصویر را برای آخرین 10 تگ Git (بر اساس تاریخ ایجاد برچسب) ذخیره کنید.
بیش از 2 تصویر منتشر شده در هفته گذشته را برای حداکثر 10 موضوع با فعالیت در هفته گذشته ذخیره کنید.
10 تصویر را برای شاخه ها ذخیره کنید main, staging и production.
الگوریتم نهایی به مراحل زیر خلاصه می شود:
بازیابی مانیفست ها از رجیستری کانتینر.
به استثنای تصاویر مورد استفاده در Kubernetes، زیرا ما قبلاً آنها را با نظرسنجی K8s API از قبل انتخاب کرده ایم.
اسکن تاریخچه Git و حذف تصاویر بر اساس خط مشی های مشخص شده.
حذف تصاویر باقی مانده
با بازگشت به تصویر خود، این چیزی است که با werf اتفاق می افتد:
با این حال، حتی اگر از werf استفاده نمیکنید، یک رویکرد مشابه برای تمیز کردن تصویر پیشرفته - در یک اجرا یا دیگری (طبق رویکرد ترجیحی برای برچسبگذاری تصویر) - میتواند برای سیستمها/ابزارهای دیگر اعمال شود. برای انجام این کار، کافی است مشکلات پیش آمده را به خاطر بسپارید و فرصت هایی را در پشته خود بیابید که به شما امکان می دهد راه حل آنها را تا حد امکان به آرامی ادغام کنید. امیدواریم مسیری که طی کرده ایم به شما کمک کند تا با جزئیات و افکار جدید به پرونده خاص خود نگاه کنید.
نتیجه
دیر یا زود، اکثر تیم ها با مشکل سرریز رجیستری مواجه می شوند.
هنگام جستجوی راه حل، ابتدا لازم است معیارهای مربوط به تصویر را تعیین کنید.
ابزارهای ارائه شده توسط خدمات ثبت کانتینر محبوب به شما امکان می دهد یک پاکسازی بسیار ساده را سازماندهی کنید که "دنیای بیرون" را در نظر نمی گیرد: تصاویر استفاده شده در Kubernetes و ویژگی های گردش کار تیم.
یک الگوریتم منعطف و کارآمد باید درک درستی از فرآیندهای CI/CD داشته باشد و نه تنها با داده های تصویر داکر کار کند.