Docker Image Best Practices

پذیرش Docker به طور مداوم افزایش می‌یابد و بسیاری با آن آشنا هستند، اما هنوز هم خیلی‌ها به بهترین شکل از روش‌های داکر استفاده نمی‌کنند.چرا باید از روش‌های ایده آل Docker استفاده کنیم؟در این مقاله قصد داریم 8 روش را به شما نشان دهیم که با کمک آن‌ها می‌توانید از Docker به شیوه‌ای درست در پروژه‌های خود استفاده کنید:● بهبود امنیت● بهینه سازی اندازه تصویراز برخی از ویژگی‌های مفید Docker بهره ببرید و همچنین Dockerfiles تمیز‌‌تر و قابل نگهداری تری بنویسید.روش اول - استفاده از تصویر رسمی‌ و تایید شده Dockerبه عنوان تصویر پایههر زمانی که امکان داشت، از یک تصویر رسمی‌ و تایید شده Docker به عنوان تصویر پایه استفاده کنید.فرض کنید در حال توسعه یک برنامه Node.jsهستید و می‌خواهید آن را به عنوان یک تصویر Docker بسازید و اجرا کنید.به جای گرفتن تصویر از سیستم عامل پایه و نصب node.js، npm و هر ابزار دیگری که برای برنامه خود نیاز دارید، از تصویر رسمی‌ نود برنامه خود استفاده کنید.بهبودها:پاک کننده Dockerfileتصویر رسمی‌ و تایید شده، که در حال حاضر با بهترین شیوه‌ها ساخته شده است.روش دوم - استفاده نسخه‌های خاص تصویر داکرتا الان ما تصویر پایه را انتخاب کرده‌ایم، اما اکنون وقتی تصویر برنامه‌های خود را از این Dockerfile می‌سازیم، همیشه از آخرین تگ تصویر نود استفاده می‌کند.چرا این مشکل ایجاد می‌شود؟● ممکن است نسخه تصویر متفاوتی را که قبلا ساخته شده است، دریافت کنید.● نسخه جدید تصویر ممکن است چیزهایی را خراب کند.● آخرین برچسب غیر قابل پیش بینی است و باعث رفتار غیرمنتظره ای شده است.بنابراین به جای استفاده از آخرین تگ تصویر به صورت تصادفی، شما می‌توانید یک نسخه را فیکس کرده و همان طور که دوست دارید، برنامه خود را با کمک نسخه خاصی که می‌خواهید از تصویر رسمی‌ آن استفاده کنید، گس‌‌ترش دهید. قانون مهم این است: هر چه خاص ‌‌تر، بهترروش بهبود :ایجاد شفافیت برای این که بدانید دقیقا از چه نسخه‌ای از تصویر پایه استفاده می‌کنید.روش سوم - استفاده از تصاویر رسمی‌ با اندازه کوچکهنگامی‌ که یک تصویر Node.js را انتخاب می‌کنید، می‌بینید که در واقع چندین تصویر رسمی‌وجود دارد. نه تنها با شماره نسخه‌های مختلف، بلکه توزیع‌های سیستم عامل مختلفحالا سوال مهم این است، شما کدام را انتخاب می‌کنید و چرا این موضوع اهمیت دارد؟● اندازه تصویراقدام نادرست : اگر تصویر بر اساس یک توزیع سیستم‌عامل کامل مانند Ubuntu یا Centos باشد، شما از قبل مجموعه‌ای از ابزارها برای تصاویر را خواهید داشت. بنابراین اندازه تصویر بزرگ‌‌تر خواهد بود، اما شما به اکثر این ابزارها در تصاویر برنامه خود نیاز ندارید.اقدام درست : داشتن تصاویر کوچک‌‌تر به این معنی است که شما به فضای ذخیره سازی کم‌‌تری در repository تصویر و استقرار سرور نیاز دارید و همچنین می‌توانید هنگام pull یا push آن‌ها از repository، تصاویر را سریع‌‌تر انتقال دهید.● مشکل امنیتیاقدام نادرست : با نصب تعدادی زیادی از ابزارها در داخل سیستم، شما باید حتما جنبه امنیت را نیز در نظر داشته باشید. زیرا تصاویر پایه معمولاً حاوی صدها نقطه آسیب پذیری شناخته شده هستند و به این ‌‌ترتیب شما در عمل، سطح بزرگ‌‌تری برای اتک تصویر را در برنامه ایجاد می‌کنند.به این ‌‌ترتیب شما از ابتدا مشکلات امنیتی غیر ضروری را برای تصویر مشخص می‌کنید.اقدام درست : در مقایسه با حالت قبلی، از تصاویر کوچک‌‌تر با توزیع‌های سیستم‌عامل کم‌‌تر، که فقط سیستم لازم را بسته‌بندی می‌کند؛ استفاده کنید. با کمک ابزارها و کتابخانه‌ها، سطح حمله را به حداقل رسانده و مطمئن می‌شوید که تصاویر امن‌‌‌تری می‌سازید.بنابراین بهترین روش در اینجا انتخاب یک تصویر، با یک نسخه خاص بر اساس توزیع سیستم عامل ضعیف‌‌‌تر مانند alpine است.Alpine همه چیزهایی را که برای شروع برنامه خود در یک container مورد نیاز است، دارد، اما بسیار سبک‌‌‌تر است و برای اکثر تصاویری که در داکر‌هاب نگاه می‌کنید، یک تگ نسخه با توزیع Alpine در آن خواهید دید.که یکی از رایج ‌‌ترین و محبوب ‌‌ترین تصاویر پایه برای کانتینرهای Docker است.روش چهارم - بهینه سازی کش (cache) برای لایه‌های تصویر هنگام ساخت یک تصویرلایه‌های تصویر چیست و کش لایه تصویر به چه معناست؟1) لایه‌های تصویر چیست؟یک تصویر Docker بر اساس یک Dockerfile ساخته شده است و در Dockerfile هر دستور یا دستورالعمل یک لایه تصویر ایجاد می‌کند:وقتی از یک تصویر پایه node alpine مانند مثال بالا استفاده می‌کنیم، این تصویر از قبل یکسری لایه دارد، چون قبلاً با استفاده از Dockerfile ساخته شده است. به علاوه، در Dockerfile ما چند دستور دیگر داریم که هر کدام یک لایه جدید به این تصویر اضافه می‌کنند.2) در مورد کش کردن چطور؟هر لایه توسط Docker ذخیره می‌شود. بنابراین وقتی تصویر خود را بازسازی می‌کنید، اگر Dockerfile شما تغییر نکرده باشد، Docker فقط از لایه‌های کش برای ساخت تصویر استفاده می‌کند.مزایای لایه‌های تصویر کش شده:● ساخت سریع‌‌تر تصویر● pull و push سریع‌‌تر نسخه‌های جدید تصویراگر یک نسخه تصویری جدید از همان برنامه را pull کنیم و فرض کنیم 2 لایه جدید، در نسخه جدید اضافه شده است. در این موقع فقط لایه‌های جدید اضافه شده، دانلود می‌شوند، بقیه قبلاً به صورت local توسط Docker ذخیره شده‌اند.3) بهینه‌‌سازی cacheبرای بهینه‌سازی کش، باید در نظر گرفت، هنگامی‌ که یک لایه تغییر می‌کند، تمام لایه‌های بعدی یا پایین دستی نیز باید دوباره ایجاد شوند. به عبارت دیگر، هنگامی‌ که محتویات یک خط را در Dockerfile تغییر می‌دهید، کش تمام خطوط یا لایه‌های زیرین شکسته و باطل می‌شوند.بنابراین در این جا قانون و بهترین اقدام این است:دستورات خود را در Dockerfile از کم‌‌ترین تا متداول‌‌‌ترین دستورات در حال تغییر مرتب کنید تا از مزایای کش استفاده کرده و از این طریق سرعت ساخت تصویر را بهینه کنید.روش پنجم - استفاده از فایل .dockerignoreبه طور معمول وقتی یک تصویر را می‌سازیم، برای اجرای داخلی اپلیکیشن به همه چیزهایی که در پروژه است، مانند فولدرهای خود ساخته، اهداف یا فولدر ساخت یا فایل‌های readme و … نیاز نداریم.شاید این سوال برای شما پیش بیاید که چگونه می‌توان از قرار گرفتن چنین محتوایی در تصویر نهایی اپلیکیشن جلوگیری کرد؟پاسخ ساده به این سوال، استفاده از فایل dockerignore. است.در حقیقت ما فقط فایل .dockerignore را ایجاد می‌کنیم و تمام فایل‌ها و پوشه‌هایی را که می‌خواهیم نادیده گرفته شوند، را لیست می‌کنیم و در هنگام ساخت تصویر، داکر به محتویات فایل نگاه کرده و هر چیزی را که در داخل آن مشخص شده است نادیده می‌گیرد.روش بهبود:● کاهش حجم تصویرروش ششم - استفاده از ساخت‌های چند مرحله‌ایفرض کنید در پروژه شما محتویاتی (مانند توسعه، ابزارهای آزمایش و کتابخانه‌ها) وجود دارد که در طول فرایند، برای ساختن تصویر به آن‌ها نیاز دارید اما در خود تصویر نهایی برای اجرای برنامه به آن‌ها نیاز ندارید.اگر این artifact‌ها را در تصویر نهایی خود نگه دارید، حتی اگر برای اجرای برنامه کاملاً غیر ضروری باشند، باز هم منجر به افزایش اندازه تصویر و افزایش سطح اتک می‌شود.پس چگونه مرحله ساخت را از مرحله اجرا جدا کنیم؟به عبارت دیگر، چگونه می‌توانیم وابستگی‌های ساخت را از تصویر حذف کنیم، در حالی که هنوز آن‌ها را در حین ساخت تصویر در دسترس داریم؟خوب، برای انجام این کار می‌توانید از روشی که به آن ساخت‌های چند مرحله‌ای می‌گویند، استفاده کنیدویژگی ساخت چند مرحله‌ای به شما این امکان را می‌دهد که از چندین تصویر موقت در طول فرایند ساخت استفاده کنید، اما تنها آخرین تصویر به عنوان artifact نهایی نگه دارید.روش هفتم - استفاده حداقلی از کاربر خاصوقتی این تصویر را ایجاد کرده و در نهایت آن را به عنوان یک کانتینر اجرا می‌کنیم، از کدام کاربر سیستم عامل برای راه اندازی اپلیکیشن در داخل استفاده می‌شود؟به طور پیش فرض، زمانی که یک Dockerfile، یک کاربر را مشخص نمی‌کند، از یک کاربر root استفاده می‌کند. اما در واقعیت و در بیش‌‌تر مواقع دلیلی برای اجرای کانتینرهایی با امتیازات روت وجود ندارد.این موضوع در حقیقت یک مشکل امنیتی را معرفی می‌کند، زیرا هنگامی‌که کانتینر روی‌ هاست راه‌اندازی می‌شود، به طور بالقوه دسترسی روت در‌ هاست Docker خواهد داشت.بنابراین اجرای یک برنامه در داخل کانتینر با کاربر روت یک امتیاز مضاعف بر روی‌ هاست است که کار را برای اتکر آسان‌‌‌تر می‌کند.and basically get hold of the underlying host and its processes, not only the container itself Especially if the application inside the container is vulnerable to exploitation.برای جلوگیری از این موضوع، بهترین کار این است که به سادگی یک کاربر و یک گروه اختصاصی در تصویر Docker ایجاد کنید تا برنامه را اجرا کرده و همچنین برنامه را در داخل کانتینر با همان کاربر اجرا کنید.شما می‌توانید از دستورالعملی به نام USERبا نام کاربری استفاده کرده و بعد از آن برنامه را به راحتی راه‌اندازی کنید.نکته: برخی از تصاویر از قبل دارای یک دسته کاربر عمومی‌هستند که می‌توانید از آن استفاده کنید. بنابراین نیازی به ایجاد یک مورد جدید ندارید. برای مثال تصویر node.js قبلاً یک کاربر عمومی‌به نام node رادسته‌بندی می‌کنید و بعد به سادگی می‌توانید، از آن برای اجرای برنامه در داخل کانتینر استفاده کنید.روش هشتم - اسکن تصاویر برای آسیب‌پذیری‌های امنیتیدر نهایت، شما چگونه می‌توانید، مطمئن شوید که تصویری که می‌سازید، چند آسیب‌پذیری امنیتی دارد؟بهترین پیشنهاد به عنوان یک راه حل نهایی و ایده آل، این است که پس از ساختن تصویر، آن را از نظر آسیب پذیری‌های امنیتی با استفاده از دستور dockerscanاسکن کنید.در پس‌زمینه، Docker در واقع از سرویسی به نام snyk برای اسکن آسیب‌پذیری تصاویر بهره می‌برد و برای اسکن از پایگاه داده‌ای آسیب پذیری‌ها استفاده می‌کند، که به صورت مدام بروزرسانی می‌شود.نمونه خروجی دستور اسکن docker به شکل زیر است:همان طور که در تصویر بالا مشاهده می‌کنید، مواردی مانند فهرست زیر مشخص شده است:1) نوع آسیب پذیری2) یک URL برای اطلاعات بیش‌‌تر3) نکته‌ قابل توجه این است، که مشخص شده است، کدام نسخه از کتابخانه مربوطه می‌تواند، آسیب پذیری را برطرف کند. بنابراین شما می‌توانید با بروزرسانی کتابخانه‌های خود، از شر این مشکلات خلاص شوید.خودکار کردن اسکنعلاوه بر اسکن دستی تصاویر با دستور docker scanدر یک CLI، شما می‌توانید Docker Hub را برای اسکن خودکار تصاویر، زمانی که به repository،push می‌شوند، پیکربندی کنید. همچنین شما می‌توانید در هنگام ساخت تصاویر Docker، آن‌ها را در پایپ‌لاین‌های CI/CD خود ادغام کنید.جمع بندیدر این مقاله به 8 تا از بهترین روش‌هایی که امروزه می‌توانید برای ساخت تصاویر Docker کم‌‌‌تر و ایمن‌‌‌تر استفاده کنید، اشاره کردیم. امیدواریم این روش‌ها برای بعضی از شما کاربردی باشند. البته روش‌های بسیار بیش‌‌تری در رابطه با Docker وجود دارد، اما به نظر می‌رسد که استفاده از روش‌های اشاره شده در این مقاله بتواند نتایج بسیار مثبتی، هنگام استفاده از Docker در تولید (محصول) برای شما داشته باشد. اگر در مورد این مقاله نظری داشتین یا موارد دیگه ای داشتین خوشحال میشم تا آن‌ها را در کامنت به اشتراک بگذارید.