اولین مرحله از استقرار در Kubernetes قرار دادن برنامه شما در یک کانتینر است. در این مجموعه، نحوه ایجاد یک تصویر کانتینر کوچک و ایمن را بررسی خواهیم کرد.
به لطف Docker، ایجاد تصاویر کانتینر هرگز آسان تر نبوده است. یک تصویر پایه را مشخص کنید، تغییرات خود را اضافه کنید و یک ظرف ایجاد کنید.
در حالی که این تکنیک برای شروع عالی است، استفاده از تصاویر پایه پیشفرض میتواند منجر به کار ناامن با تصاویر بزرگ پر از آسیبپذیری شود.
علاوه بر این، اکثر تصاویر در داکر از دبیان یا اوبونتو برای تصویر پایه استفاده میکنند، و در حالی که این سازگاری عالی و سفارشیسازی آسان را فراهم میکند (یک فایل داکر فقط دو خط کد نیاز دارد)، تصاویر پایه میتوانند صدها مگابایت بار اضافی به ظرف شما اضافه کنند. به عنوان مثال، یک فایل node.js ساده برای برنامه Go "hello-world" حدود 700 مگابایت است، در حالی که حجم برنامه واقعی شما تنها چند مگابایت است.
بنابراین تمام این حجم کاری اضافی هدر دادن فضای دیجیتال و مخفیگاهی عالی برای آسیب پذیری های امنیتی و اشکالات است. بنابراین بیایید به دو روش برای کاهش اندازه تصویر ظرف نگاه کنیم.
اولی استفاده از تصاویر پایه کوچک، دومی استفاده از Builder Pattern. استفاده از تصاویر پایه کوچکتر احتمالاً ساده ترین راه برای کاهش اندازه ظرف شما است. به احتمال زیاد، زبان یا پشته ای که استفاده می کنید یک تصویر برنامه اصلی را ارائه می دهد که بسیار کوچکتر از تصویر پیش فرض است. بیایید نگاهی به کانتینر node.js خود بیاندازیم.
به طور پیش فرض در Docker، اندازه تصویر پایه node:8 670 مگابایت است و اندازه تصویر node: 8-alpine تنها 65 مگابایت است، یعنی 10 برابر کوچکتر. با استفاده از تصویر کوچکتر پایه آلپاین، اندازه ظرف خود را به میزان قابل توجهی کاهش خواهید داد. Alpine یک توزیع کوچک و سبک لینوکس است که در بین کاربران داکر بسیار محبوب است، زیرا با بسیاری از برنامه ها سازگار است و کانتینرها را کوچک نگه می دارد. برخلاف تصویر استاندارد Docker "node"، "node:alpine" بسیاری از فایلها و برنامههای سرویس را حذف میکند و تنها آنهایی را که برای اجرای برنامه شما کافی هستند باقی میماند.
برای انتقال به یک تصویر پایه کوچکتر، به سادگی Dockerfile را به روز کنید تا با تصویر پایه جدید شروع به کار کنید:
اکنون، برخلاف تصویر قدیمی onbuild، باید کد خود را در کانتینر کپی کرده و وابستگی ها را نصب کنید. در یک Dockerfile جدید، کانتینر با یک تصویر node:alpine شروع می شود، سپس یک دایرکتوری برای کد ایجاد می کند، وابستگی ها را با استفاده از مدیر بسته NPM نصب می کند و در نهایت server.js را اجرا می کند.
این ارتقا منجر به تولید ظرفی با اندازه 10 برابر کوچکتر می شود. اگر زبان برنامه نویسی یا پشته شما قابلیت کاهش تصویر پایه را ندارد، از Alpine Linux استفاده کنید. همچنین امکان مدیریت کامل محتویات ظرف را فراهم می کند. استفاده از تصاویر پایه کوچک یک راه عالی برای ایجاد سریع ظروف کوچک است. اما کاهش حتی بیشتر را می توان با استفاده از Builder Pattern به دست آورد.
در زبان های تفسیر شده، کد منبع ابتدا به مفسر داده می شود و سپس مستقیماً اجرا می شود. در زبان های کامپایل شده ابتدا کد منبع به کد کامپایل شده تبدیل می شود. با این حال، کامپایل اغلب از ابزارهایی استفاده می کند که واقعاً برای اجرای کد مورد نیاز نیستند. یعنی می توانید این ابزارها را به طور کامل از ظرف نهایی خارج کنید. برای این کار می توانید از Builder Pattern استفاده کنید.
کد در اولین کانتینر ایجاد شده و کامپایل می شود. سپس کد کامپایل شده در یک ظرف نهایی بدون کامپایلرها و ابزارهای مورد نیاز برای کامپایل آن کد بسته بندی می شود. بیایید یک برنامه Go را از طریق این فرآیند اجرا کنیم. ابتدا از تصویر روی ساخت به Alpine Linux حرکت می کنیم.
در Dockerfile جدید، ظرف با یک تصویر golang:alpine شروع می شود. سپس یک دایرکتوری برای کد ایجاد می کند، آن را در کد منبع کپی می کند، آن کد منبع را می سازد و برنامه را اجرا می کند. این کانتینر بسیار کوچکتر از کانتینر onbuild است، اما همچنان حاوی کامپایلر و سایر ابزارهای Go است که واقعاً به آنها نیاز نداریم. پس بیایید برنامه کامپایل شده را استخراج کرده و در ظرف خودش قرار دهیم.
ممکن است متوجه چیز عجیبی در این فایل Docker شوید: شامل دو خط FROM است. بخش 4 خطی اول دقیقاً مشابه Dockerfile قبلی است با این تفاوت که از کلمه کلیدی AS برای نامگذاری این مرحله استفاده می کند. بخش بعدی دارای یک خط FROM جدید برای شروع یک تصویر جدید است که به جای تصویر golang:alpine از Raw alpine به عنوان تصویر پایه استفاده می کنیم.
Raw Alpine Linux هیچ گواهینامه SSL نصب نکرده است، که باعث می شود اکثر تماس های API از طریق HTTPS با شکست مواجه شوند، بنابراین اجازه دهید برخی از گواهی های CA ریشه را نصب کنیم.
اکنون قسمت سرگرم کننده فرا می رسد: برای کپی کردن کد کامپایل شده از اولین ظرف به دوم، می توانید به سادگی از دستور COPY واقع در خط 5 قسمت دوم استفاده کنید. این فقط یک فایل برنامه را کپی می کند و بر ابزارهای Go utility تأثیری نمی گذارد. فایل چند مرحله ای داکر حاوی یک تصویر ظرف است که تنها 12 مگابایت حجم دارد، در مقایسه با تصویر کانتینر اصلی که 700 مگابایت بود، که یک تفاوت بزرگ است!
بنابراین استفاده از تصاویر پایه کوچک و Builder Pattern راههای عالی برای ایجاد ظروف بسیار کوچکتر بدون کار زیاد است.
ممکن است بسته به پشته برنامه، راه های دیگری برای کاهش اندازه تصویر و ظرف وجود داشته باشد، اما آیا ظروف کوچک واقعاً مزایای قابل اندازه گیری دارند؟ بیایید به دو زمینه که در آن ظروف کوچک بسیار موثر هستند - عملکرد و امنیت نگاه کنیم.
برای ارزیابی افزایش عملکرد، مدت زمان فرآیند ایجاد یک ظرف، درج آن در رجیستری (فشار)، و سپس بازیابی آن از آنجا (کشش) را در نظر بگیرید. می بینید که یک ظرف کوچکتر مزیت مشخصی نسبت به ظرف بزرگتر دارد.
Docker لایهها را کش میکند، بنابراین ساختهای بعدی بسیار سریع خواهند بود. با این حال، بسیاری از سیستمهای CI که برای ساخت و آزمایش کانتینرها استفاده میشوند، لایهها را کش نمیکنند، بنابراین صرفهجویی قابل توجهی در زمان وجود دارد. همانطور که می بینید، زمان ساخت یک ظرف بزرگ، بسته به قدرت دستگاه شما، از 34 تا 54 ثانیه است و در هنگام استفاده از ظرف با استفاده از الگوی سازنده، از 23 به 28 ثانیه کاهش می یابد. برای عملیات از این نوع، افزایش بهره وری 40-50٪ خواهد بود. بنابراین فقط به این فکر کنید که چند بار کد خود را می سازید و آزمایش می کنید.
پس از ساخت کانتینر، باید تصویر آن (تصویر کانتینر فشار) را به رجیستری کانتینر فشار دهید تا بتوانید از آن در خوشه Kubernetes خود استفاده کنید. توصیه می کنم از Google Container Registry استفاده کنید.
با Google Container Registry (GCR)، شما فقط هزینه ذخیره سازی خام و شبکه را پرداخت می کنید، و هیچ هزینه اضافی برای مدیریت کانتینر وجود ندارد. خصوصی، امن و بسیار سریع است. GCR از ترفندهای زیادی برای سرعت بخشیدن به عملیات کشش استفاده می کند. همانطور که می بینید، قرار دادن کانتینر تصویر Docker Container با استفاده از go:onbuild از 15 تا 48 ثانیه بسته به عملکرد رایانه، و همین عملیات با یک ظرف کوچکتر از 14 تا 16 ثانیه طول می کشد و برای ماشین های کم تولید مزیت در سرعت عملیات 3 برابر افزایش می یابد. برای ماشینهای بزرگتر، زمان تقریباً یکسان است، زیرا GCR از یک کش جهانی برای پایگاه داده مشترک تصاویر استفاده میکند، به این معنی که شما اصلاً نیازی به بارگیری آنها ندارید. در یک کامپیوتر کم مصرف، CPU گلوگاه است، بنابراین مزیت استفاده از ظروف کوچک در اینجا بسیار بیشتر است.
اگر از GCR استفاده می کنید، من به شدت توصیه می کنم از Google Container Builder (GCB) به عنوان بخشی از سیستم ساخت خود استفاده کنید.
همانطور که می بینید، استفاده از آن به شما اجازه می دهد تا به نتایج بسیار بهتری در کاهش مدت زمان عملیات Build+Push حتی نسبت به یک ماشین تولیدی دست یابید - در این حالت، فرآیند ساخت و ارسال کانتینرها به میزبان تقریباً 2 برابر سریعتر است. به علاوه، هر روز 120 دقیقه ساخت رایگان دریافت می کنید که در اکثر موارد نیازهای ساختمان کانتینر شما را پوشش می دهد.
در مرحله بعدی مهمترین معیار عملکرد می آید - سرعت بازیابی یا دانلود، کشش ظروف. و اگر به زمان صرف شده برای عملیات فشار اهمیتی نمی دهید، پس طول فرآیند کشش تأثیر جدی بر عملکرد کلی سیستم دارد. فرض کنید یک خوشه از سه گره دارید و یکی از آنها خراب می شود. اگر از یک سیستم مدیریتی مانند Google Kubernetes Engine استفاده می کنید، به طور خودکار گره مرده را با یک گره جدید جایگزین می کند. با این حال، این گره جدید کاملا خالی خواهد بود و شما باید تمام کانتینرهای خود را به داخل آن بکشید تا شروع به کار کند. اگر عملیات کشش به اندازه کافی طول بکشد، خوشه شما در تمام مدت با عملکرد پایین تری اجرا می شود.
موارد زیادی وجود دارد که ممکن است این اتفاق بیفتد: اضافه کردن یک گره جدید به یک خوشه، ارتقاء گره ها، یا حتی تغییر به یک کانتینر جدید برای استقرار. بنابراین، به حداقل رساندن زمان استخراج کشش به یک عامل کلیدی تبدیل می شود. این غیر قابل انکار است که یک ظرف کوچک بسیار سریعتر از یک ظرف بزرگ دانلود می شود. اگر چندین کانتینر را در یک خوشه Kubernetes اجرا می کنید، صرفه جویی در زمان می تواند قابل توجه باشد.
به این مقایسه نگاهی بیندازید: عملیات کشش در ظروف کوچک بسته به قدرت دستگاه، 4 تا 9 برابر کمتر از عملیات مشابه با استفاده از go:onbuild زمان می برد. استفاده از تصاویر پایه کانتینرهای کوچک به اشتراک گذاشته شده، زمان و سرعتی را که میتوانند با آن گرههای Kubernetes جدید مستقر شوند و آنلاین شوند، به میزان قابل توجهی افزایش میدهد.
بیایید به بحث امنیت نگاه کنیم. کانتینرهای کوچکتر بسیار ایمن تر از کانتینرهای بزرگتر در نظر گرفته می شوند زیرا سطح حمله کوچکتری دارند. آیا واقعا؟ یکی از مفیدترین ویژگی های Google Container Registry این است که به طور خودکار کانتینرهای شما را از نظر آسیب پذیری اسکن می کند. چند ماه پیش من هم کانتینرهای روی ساخت و هم کانتینرهای چند مرحله ای ایجاد کردم، پس بیایید ببینیم آیا آسیب پذیری در آنجا وجود دارد یا خیر.
نتیجه شگفتانگیز است: تنها 3 آسیبپذیری متوسط در یک ظرف کوچک شناسایی شد و 16 آسیبپذیری حیاتی و 376 آسیبپذیری دیگر در یک ظرف بزرگ یافت شد. اگر به محتویات یک کانتینر بزرگ نگاه کنیم، می بینیم که اکثر مشکلات امنیتی ربطی به برنامه ما ندارند، بلکه مربوط به برنامه هایی هستند که حتی از آنها استفاده نمی کنیم. بنابراین وقتی مردم در مورد یک سطح حمله بزرگ صحبت می کنند، منظورشان این است.
نکته واضح است: ظروف کوچک بسازید زیرا عملکرد واقعی و مزایای امنیتی را برای سیستم شما فراهم می کنند.
چند تبلیغ 🙂
از اینکه با ما ماندید متشکرم آیا مقالات ما را دوست دارید؟ آیا می خواهید مطالب جالب تری ببینید؟ با ثبت سفارش یا معرفی به دوستان از ما حمایت کنید
Dell R730xd 2 برابر ارزان تر در مرکز داده Equinix Tier IV در آمستردام؟ فقط اینجا
منبع: www.habr.com