این روزها استفاده از Docker در شرکتها به طور مداوم افزایش مییابد و بسیاری از افراد هم با آن آشنا هستند؛ اما هنوز هم خیلیها به بهترین شکل از روشهای داکر استفاده نمیکنند. اما چرا باید از روشهای ایده آل Docker استفاده کنیم؟
در این مقاله قصد داریم ۸ روش را به شما نشان دهیم که با کمک آنها میتوانید از Docker به شیوهای درست و بهینه در پروژههای خود استفاده کنید. با کمک این روش ها شما میتوانید از برخی از ویژگیهای مفید Docker استفاده کرده و همچنین Dockerfiles تمیزتری با قابلیت نگهداشت سادهتر بنویسید.
روش اول – استفاده از تصویر رسمی و تایید شده Docker به عنوان تصویر پایه
تا جایی که میتوانید، از یک تصویر (Image) رسمی و تایید شده Docker به عنوان ایمیج پایه استفاده کنید.
فرض کنید در حال توسعه یک برنامه Node.js هستید و میخواهید آن را به عنوان یک تصویر Docker بسازید و اجرا کنید. به جای گرفتن تصویر از سیستم عامل پایه و نصب npm، node.js و هر ابزار دیگری که برای برنامه خود نیاز دارید، از تصویر رسمی خود برنامه استفاده کنید.
مزایا و بهبودها:
- داکرفایل (DockerFile) تمیزتر
- استفاده از ایمیج رسمی و تایید شده که به بهترین روش ساخته شده است
روش دوم – استفاده از داکر ایمیجهای مشخص و دقیق
فرض کنید که یمیج پایه خود را طبق استاندارد بالا ساختیم. اما حالا هر زمان که بخواهیم ایمیج برنامه خود را از این Dockerfile بسازیم، از آخرین تک ایمیج نود (گره) استفاده میکند.
چرا این کار مشکلساز است؟
- ممکن است نسخه قدیمیتری از ایمیج را دریافت کنید
- نسخه جدید تصویر ممکن است سیستم را دچار مشکل کند
- آخرین برچسب (
latest
tag) غیر قابل پیشبینی است و باعث رفتارهای غیرمنتظره میشود
بنابراین به جای استفاده از آخرین تگ تصویر به صورت تصادفی، شما میتوانید یک نسخه را فیکس کنید و همان طور که دوست دارید یک نسخه خاص از برنامه خود را منتشر کنید، تصویر رسمی را هم با استفاده از یک نسخه خاص ایجاد کنید. قانون مهم این است: هر چه خاصتر، بهتر.
مزایا و بهبودها:
- شفافیت بیشتر در رابطه با نسخه ایمیج پایه مورد استفاده
روش سوم – استفاده از تصاویر رسمی با اندازه کوچک در Docker
هنگامی که یک تصویر Node.js را انتخاب میکنید، میبینید که در واقع چندین تصویر رسمی وجود دارد که نه تنها نسخه آنها مختلف است، بلکه توزیع سیستم عامل متفاوتی هم دارند.
حالا سوال مهم این است، شما کدام را انتخاب میکنید و چرا این موضوع اهمیت دارد؟
۱. اندازه تصویر
انتخاب اشتباه: اگر تصویر بر اساس یک توزیع سیستم عامل کامل مانند Ubuntu یا Centos باشد، شما از قبل مجموعهای از ابزارها برای تصاویر را خواهید داشت. بنابراین اندازه تصویر بزرگتر خواهد بود، اما شما به اکثر این ابزارها در تصاویر برنامه خود نیاز ندارید.
انتخاب درست: داشتن تصاویر کوچکتر به این معنی است که شما به فضای ذخیره سازی کمتری در repository تصویر و استقرار سرور نیاز دارید و همچنین میتوانید هنگام pull یا push آنها از repository، تصاویر را سریعتر انتقال دهید.
۲. مشکل امنیتی
انتخاب اشتباه: با نصب تعدادی زیادی از ابزارها در داخل سیستم، شما باید حتما جنبه امنیت را نیز در نظر داشته باشید. زیرا تصاویر پایه معمولا حاوی صدها نقطه آسیبپذیر شناخته شده هستند و به این ترتیب شما در عمل احتمال بیشتری برای اتک به تصویر را در برنامه ایجاد میکنند. به این ترتیب شما از ابتدا مشکلات امنیتی غیرضروری را برای تصویر مشخص میکنید.
انتخاب درست: در مقایسه با حالت قبلی، از تصاویر کوچکتر با توزیعهای سیستمعامل کمتر که فقط سیستم لازم را بستهبندی میکند، استفاده کنید. با کمک ابزارها و کتابخانهها، سطح حمله را به حداقل برسانید و مطمئن شوید که تصاویر امنتری میسازید.
بنابراین بهترین روش در اینجا انتخاب یک تصویر، با یک نسخه خاص بر اساس توزیع سیستم عامل ضعیفتر مانند alpine است.
Alpine شامل همه چیزهایی میشود که برای شروع برنامه خود در یک container نیاز دارید. اما این نسخه بسیار سبکتر است و برای اکثر تصاویری که در داکرهاب میبینید، یک تگ نسخه با توزیع Alpine در آن خواهید دید که یکی از رایجترین و محبوبترین تصاویر پایه برای کانتینرهای Docker است.
روش چهارم – بهینهسازی کش (Cache) لایههای تصویر هنگام ساخت یک تصویر در Docker
لایههای تصویر چیست و کش لایه تصویر به چه معناست؟
لایههای تصویر چیست؟
یک تصویر Docker بر اساس یک Dockerfile ساخته میشود و در Dockerfile، هر دستور یا دستورالعمل یک لایه تصویر ایجاد میکند:
وقتی از یک تصویر پایه نود alpine مانند مثال بالا استفاده میکنیم، این تصویر به دلیل اینکه با استفاده از Dockerfile ساخته شده است، از قبل تعدادی لایه دارد و در Dockerfile ما چند دستور دیگر داریم که هر کدام یک لایه جدید به این تصویر اضافه میکنند.
در زمان کش چه اتفاقی میافتد؟
هر لایه توسط Docker ذخیره میشود. بنابراین وقتی تصویر خود را بازسازی میکنید، اگر Dockerfile شما تغییر نکرده باشد، Docker فقط از لایههای کش برای ساخت تصویر استفاده میکند.
مزایای لایههای تصویر کش شده:
- ساخت سریعتر تصویر
- pull و push سریعتر نسخههای جدید تصویر
اگر یک نسخه تصویری جدید از همان برنامه را pull کنیم و فرض کنیم ۲ لایه جدید، در نسخه جدید اضافه شده است. در این موقع فقط لایههای جدید دانلود میشوند و بقیه از قبل به صورت local توسط Docker ذخیره شدهاند.
بهینهسازی cache
برای بهینهسازی کش، باید در نظر گرفت هنگامی که یک لایه تغییر میکند، تمام لایههای بعدی یا پایین دستی نیز باید دوباره ایجاد شوند. به عبارت دیگر، هنگامی که محتویات یک خط را در Dockerfile تغییر میدهید، کش تمام خطوط یا لایههای زیرین شکسته و باطل میشوند.
بنابراین در این جا قانون و بهترین اقدام این است:
دستورات خود را در Dockerfile از کمترین تا بیشترین تغییر مرتب کنید تا از مزایای کش استفاده کرده و از این طریق، سرعت ساخت تصویر را بهینه کنید.
روش پنجم – استفاده از فایل .dockerignore
به طور معمول وقتی یک تصویر را میسازیم، برای اجرای داخلی اپلیکیشن به همه چیزهایی که در پروژه است، مانند فولدرهای خود ساخته، اهداف یا فولدر ساخت یا فایلهای readme و … نیاز نداریم.
شاید این سوال برای شما پیش بیاید که چگونه میتوان از قرار گرفتن چنین محتوایی در تصویر نهایی اپلیکیشن جلوگیری کرد؟
پاسخ ساده به این سوال استفاده از فایل dockerignore. است.
در حقیقت ما فقط فایل .dockerignore را ایجاد میکنیم و تمام فایلها و پوشههایی را که میخواهیم نادیده گرفته شوند را لیست میکنیم و در هنگام ساخت تصویر داکر به محتویات فایل نگاه کرده و هر چیزی را که در داخل آن مشخص شده است، نادیده میگیرد.
مزایا و بهبودها:
- کاهش حجم تصویر
روش ششم – استفاده از ساختهای چند مرحلهای
فرض کنید در پروژه شما محتویاتی (مانند توسعه، ابزارهای تست و کتابخانهها) وجود دارند که در طول فرایند برای ساختن تصویر به آنها نیاز دارید؛ اما در خود تصویر نهایی برای اجرای برنامه به آنها نیازی ندارید.
اگر این artifactها (فایلهای اضافه) را در تصویر نهایی خود نگه دارید، حتی اگر برای اجرای برنامه کاملا غیر ضروری باشند، باز هم منجر به افزایش اندازه تصویر و افزایش سطح اتک میشود.
پس چگونه مرحله ساخت را از مرحله اجرا جدا کنیم؟
به عبارت دیگر چگونه میتوانیم وابستگیهای ساخت را از تصویر حذف کنیم، در حالی که هنوز آنها را در حین ساخت تصویر در دسترس داریم؟
برای انجام این کار میتوانید از روشی که به آن ساختهای چند مرحلهای (multi-stage builds) میگویند، استفاده کنید.
ویژگی ساخت چند مرحلهای به شما این امکان را میدهد که از چندین تصویر موقت در طول فرایند ساخت استفاده کنید، اما تنها آخرین تصویر به عنوان artifact نهایی نگه دارید.
مزایا و بهبودها:
- جدایی ابزارهای توسعه از نیازمندیهای اجرا
- وابستگی و حجم تصویر کمتر
روش هفتم – استفاده حداقلی از کاربر خاص
وقتی این تصویر را ایجاد کرده و در نهایت آن را به عنوان یک کانتینر اجرا میکنیم، از کدام کاربر سیستم عامل برای راهاندازی اپلیکیشن در داخل استفاده میشود؟
به طور پیش فرض، زمانی که یک Dockerfile یک کاربر را مشخص نمیکند، از یک کاربر root استفاده میکند. اما در واقعیت و در بیشتر مواقع، دلیلی برای اجرای کانتینرهایی با امتیازات روت وجود ندارد.
این موضوع در حقیقت یک مشکل امنیتی را معرفی میکند، زیرا هنگامیکه کانتینر روی هاست راهاندازی میشود، به طور بالقوه دسترسی روت را در هاست Docker خواهد داشت.
بنابراین اجرای یک برنامه در داخل کانتینر با کاربر روت یک امتیاز مضاعف بر روی هاست است که کار را برای اتکر آسانتر میکند.
برای جلوگیری از این موضوع، بهترین کار این است که به سادگی یک کاربر و یک گروه اختصاصی در تصویر Docker ایجاد کنید تا برنامه را اجرا کرده و همچنین برنامه را در داخل کانتینر با همان کاربر اجرا کنید.
شما میتوانید از دستورالعملی به نام USER با نام کاربری استفاده کرده و بعد از آن برنامه را به راحتی راهاندازی کنید.
نکته: برخی از تصاویر از قبل دارای یک دسته کاربر عمومی هستند که میتوانید از آن استفاده کنید و نیازی به ایجاد یک مورد جدید ندارید. برای مثال تصویر node.js یک کاربر عمومی به نام node دارد که میتوانید از آن برای اجرای برنامه در داخل کانتینر استفاده کنید.
روش هشتم – اسکن تصاویر برای آسیبپذیریهای امنیتی در Docker
در نهایت چگونه میتوانید مطمئن شوید که تصویری که میسازید، حفره امنیتی ندارد؟
بهترین پیشنهاد به عنوان یک راه حل نهایی و ایدهآل، این است که پس از ساختن تصویر آن را از نظر آسیبپذیریهای امنیتی با استفاده از دستور dockerscan اسکن کنید.
Docker به طور پیشفرض از سرویسی به نام snyk برای اسکن آسیبپذیری تصاویر بهره میبرد و برای اسکن از پایگاه داده آسیبپذیریها استفاده میکند که به صورت مداوم بهروزرسانی میشود.
نمونه خروجی دستور اسکن docker به شکل زیر است:
خودکار کردن اسکن در Docker
علاوه بر اسکن دستی تصاویر با دستور docker scan در یک CLI، شما میتوانید Docker Hub را برای اسکن خودکار تصاویر زمانی که به repository پوش (Push) میشوند، پیکربندی کنید. همچنین شما میتوانید در هنگام ساخت تصاویر Docker، آنها را در پایپلاینهای CI/CD خود ادغام کنید.
جمعبندی
در این مقاله به ۸ تا از بهترین روشهایی که امروزه میتوانید برای ساخت تصاویر Docker سبکتر و ایمنتر استفاده کنید، اشاره کردیم. البته روشهای بسیار بیشتری در رابطه با Docker وجود دارد اما به نظر میرسد که استفاده از روشهای اشاره شده در این مقاله، بتوانند نتایج بسیار مثبتی هنگام استفاده از Docker در تولید محصول برای شما داشته باشد.
اگر این مقاله برای شما جالب بوده است یا روشهایی دیگری را میشناسید، که میتوانند نتایج بهتری در پی داشته باشند، خوشحال خواهیم شد تا آنها را در کامنت را به ما به اشتراک بگذارید.
منبع: https://dev.to
دیدگاهتان را بنویسید