<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های Mehdi Zarepour</title>
        <link>https://virgool.io/feed/@mehdi.zarepour</link>
        <description>Software Engineer</description>
        <language>fa</language>
        <pubDate>2026-06-16 06:44:14</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/2603721/avatar/97ixBM.jpg?height=120&amp;width=120</url>
            <title>Mehdi Zarepour</title>
            <link>https://virgool.io/@mehdi.zarepour</link>
        </image>

                    <item>
                <title>شبکه در Docker و انواع آن</title>
                <link>https://virgool.io/@mehdi.zarepour/%D8%B4%D8%A8%DA%A9%D9%87-%D8%AF%D8%B1-%D8%AF%D8%A7%DA%A9%D8%B1-%D9%88-%D8%A7%D9%86%D9%88%D8%A7%D8%B9-%D8%A2%D9%86-jikbyu5nnmau</link>
                <description>یکی از قسمت‌های مهم داکر Networking هست، قسمتی که تعیین میکنه که Container ها چطوری باهم و با دنیای بیرون ارتباط برقرار می‌کنن. فهمیدن Docker Networking (نمی دونم چه معادل فارسی براش می تونم به کار ببرم!) برای Deploy کردن امن و scalable خیلی مهمه، برای همین تصمیم گرفتم توی این نوشته تا حدی که سرنخ های خوبی بهتون بده برای درک بهتر و عمیق شدن صحبت می‌کنیم.داکر Networking چیست؟خیلی ساده بخواییم بگیم، Docker Networking متدی رو تعریف می‌کنه که با استفاده از اون کانتینرها می‌تونن باهم دیگه و همینطور با دنیای بیرون ارتباط برقرار کنند.وقتی داکر رو نصب می‌کنیم، به طور اتوماتیک یه شبکه مجازی default روی سخت افزار شبکه ماشینی که داکر روش نصب شده ایجاد می‌کنه و یه سطحی از ایزولیشن برای ارتباط اپلیکیشن‌هایی که containerized شدن ایجاد میکنه. یعنی به صورت پیشفرض همه کانتینرهایی که ایجاد میکنیم توی شبکه default رجیستر میشن و میتونن با هم ارتباط برقرار کنن. نمودار بالا نشون میده که چطور کانتینرهایی که ساخته شدن به شبکه default به اسم bridge وصل شدن تا بتونن با هم ارتباط برقرار کنن. خب بیاییم یکم دست به آچار شیم ببینیم این اتفاق چطوری می‌افته و چطوری کار می کنه:۱. برای شروع بیاییم ببینیم این شبکه دیفالت رو داکر ایجاد کرده یا نه؟docker network lsدستور بالا لیست شبکه های مجازی که داکر ایجاد کرده رو بهمون نشون میده، که شبکه با اسم bridge همون شبکه‌ی پیشفرضی هست که اگه موقع ساختن کانتینر شبکه‌ش رو مشخص نکنیم، روی کانتینر ست میشه.۲. یه container جدید run کنیمبرای اینکه ببنیم کانتینر جدید به شبکه پیشفرض وصل میشه یا نه، یه کانتینر جدید ایجاد می‌کنیم ولی شبکه‌ای بهش اختصاص نمیدیم:docker run -dit --name container1 alpine ash۳. بررسی کانتینر ایجاد شدهحالا بیاییم Container ایجاد شده رو بررسی کنیم تا ببینیم به چه شبکه‌ای وصل شده، برای این کار از دستور زیر استفاده می کنیم:docker inspect container1برای دیدن اطلاعات شبکه دنبال پروپرتی Networks بگردین، باید یه چیزی مثل عکس زیر رو ببنید:این تصویر نشون میده که Container جدید به شبکه پیشفرض که اسمش bridge هست کانکت شده و IP و اطلاعات دیگه رو هم می تونین ببینین. حالا هر کانتینر دیگه‌ای که توی این شبکه باشه میتونن با هم ارتبط برقرار کنن. بیاییم اینم تست کنیم.۴. ارتباط کانتینرها در یک شبکهبرای تست این ارتباط یه کانتینر جدید با اسم container2 می‌سازیم و سعی میکنیم ببنیم به میتونیم container1 که تو همین شبکه هست رو ببینیم؟docker run -dit --name container2 alpine ashخب این کانتینر جدید هم چون باید به شبکه پیشفرض (bridge) وصل شده باشه چون موقع ایجاد شبکه‌ای بهش اختصاص ندادیم. پس باید بتونیم به container1 پینگ داشته باشیم، بیاییم اینم با دستور زیر تستش کنیم:docker exec -it container2 ashحالا ببینیم به اون container پینگ داریم؟ اگه یادتون باشه توی تصور مشخصات container1 مقدار آی پی 172.17.0.2 بودping 172.17.0.2توی عکس زیر می‌تونیم ببینیم که به container1  پینگ داریمایجاد و استفاده از شبکه Customخب تا اینجا دیدیم که همه کانتینرهایی که به صورت پیشفرض ایجاد میشن، به شبکه دیفالت که اسمش bridge بود اضافه می‌شن. ولی خب بهتره که کانتینرهایی که ایجاد میکنیم رو به شبکه دیفالت اضافه کنیم و از شبکه‌ی کاستوم که خومون ایجاد می کنیم استفاده کنیم، چرا؟ اولا اینکه از لحاظ امنیتی کار درستی نیس چون همه کانتینرهای توی شبکه‌ی دیفالت می تونن هم دیگه رو ببینن که میتونه مشکل امنیتی ایجاد کنه و دوم اینکه اگه یه وقت نیاز شد که بخواییم شبکه رو کاستوم کنیم و یا محدودیت هایی به شبکه ایجاد کنیم، این کار با استفاده از شبکه پیشفرض امکان پذیر نیست.پس بهتره هر وقت که یه سیستمی رو داریم طراحی میکنیم همه‌ی کانتینرهایی که نیاز دارن باهم در ارتباط باشن رو به یه شبکه کاستوم اضافه کنیم و در صورت نیاز محدودیت هایی بهش اضافه کنیم. خب حالا بریم سراغ اینکه چطوری یه شبکه کاستوم ایجاد کنیم و ازش استفاده کنیم.ایجاد شبکه custom:docker network create my_network وقتی دستور بالا رو اجرا کنیم، مشخصا یه شبکه کاستوم ایجاد میشه (که از نوع bridge هست، جلوتر راجع بهش میگم). پس خروجی دستور زیر باید شبکه جدید رو نشون بده:docker network lsایجاد کانتینر در شبکه کاستوم:خب حالا بیاییم یه container جدید بسازیم و به این شبکه جدید وصلش کنیم، برای این کار از دستور زیر استفاده می‌کنیم:docker run -dit --network=my_network --name container3 alpine ashخب حالا باید container3 به شبکه my_network وصل شده باشه، با دستور زیر میتونیم بررسیش کنیم:docker inspect container3عکس بالا نشون میده که کانتینر جدید به شبکه my_network وصل شده و دیگه به شبکه دیفالت وصل نیست.داکر DNSویژگی کاربردی دیگه‌ای که وقتی از custom network استفاده می کنیم و داکر در اختیارمون می‌زاره یه Embed DNS هست که با کمکش دیگه نیاز نیس برای دسترسی به کانتینرهای تو یه شبکه از IP شون استفاده کنیم و میتونیم صرفا از نام container بجای IP استفاده کنیم و اصلا استفاده از IP خودش مشکل جدیدی رو برایمون ایجاد میکنه، تو حالت‌هایی که زیر بهشون اشاره می‌کنم ممکنه IP تغییر کنه و اگه از اون IP توی کد یا config ها استفاده کرده باشین به مشکل می خورین:وقتی که به هر دلیلی تصمیم بگیریم که کانتینر رو حذف کنیم و یه کانتینر جدید از روی image مون ایجاد کنیم.تغییرات تو شبکه: اگه container رو از شبکه حذف کنیم و دوباره وصلش کنیم IP جدید بهش داده میشه.اگه Docker daemon یا سیستمی که داکر روش نصبه ری‌استارت بشننکته: البته جدا از تغییر IP استفاده کردن از اسم container تا حد خیلی زیادی خوانایی رو بالا میبره.خب حالا بیاییم با یه مثال این DNS رو امتحان کنیم، تو مثال قبلی container3 رو روی شبکه my_network ران کردیم، برای تست این ویژگی میخوام container2 رو هم که قبلا رو شبکه default بود رو هم به این شبکه اضافه کنیم. برای این کار از دستور زیر استفاده میکنیم.اول بیاییم این container رو از شبکه دیفالت disconnect کنیم:docker network disconnect bridge container2۲. حالا وصلش میکنیم به شبکه my_network:docker network connect my_network container2۳. خب حالا اگه inspect بگیریم می‌بینیم که به شبکه جدید وصل شده:docker inspect container2۴. حالا وقت اینه که از اسم container به عنوان DNS name برای ارتباط استفاده کنیم:از اونجایی که الان container2 و container3 هر دو تو یه شبکه هستن می‌تونن با هم ارتباط داشته باشنdocker exec -it container2 ashping container3با استفاده از دستور بالا می‌تونیم ببنیم که تونستیم بجای استفاده از IP با اسم container با container3 ارتباط بگیریم.انواع شبکه در داکرداکر انواع مختلفی از شبکه رو در اختیار ما قرار میده که یکی از مهمترین قابلیت‌های داکر محسوب میشه، هر کدوم از این نوع‌های مختلف مشخص میکنن که یه کانتینر چه دسترسی‌هایی در شبکه داره و چطوری میتونه با کانتینرهای دیگه و یا دنیای بیرون ارتباط برقرار کنه، اینجا قراره با هرکدوم از شبکه‌ها آشنا بشیم و راجع به این صحبت کنیم که هر کدوم از این شبکه‌ها چه کاربردی دارند. انواع شبکه‌هایی که داکر در اختیارمون میزاره به شرح زیر است:BridgeHostOverlayMacvlanNone Networkشبکه Bridgeاین شبکه که پیشتر باهاش آشنا شدیم یکی از سادترین و در عین‌حال پرکاربردترین شبکه در داکر محسوب میشه که میتونیم با کمترین می‌زان تنظیمات و یا آشنایی با جزئیات شبکه، اینجاد و ازش استفاده کنیم. با استفاده از شبکه Bridge می‌تونیم یه شبکه مجازی خصوصی روی ماشین host (ماشینی که داکر روش نصبه) ایجاد کنیم که هر کانتینری که بهش وصل میشه به شکل اتوماتیک یه IP بهش اختصاص داده میشه و کانتینرهایی که تو این شبکه هستن میتونن با هم‌دیگه ارتباط برقرار کنند. موارد استفاده‌ش رو میشه اینطوری گفت:وقتی scale اپلیکیشن که پیاده میکنیم کوچیکه و داشته یه شبکه ساده نیازمون رو برطرف میکنهوقتی که میخواییم شبکه خصوصی داشته باشیموقتی که نیاز داشته باشیم کانتینر ها بتونن باهم ارتباط برقرار کننزمانی که کانتینر نیاز داشته باشه با استفاده از port mapping با دنیای بیرون (شبکه خارج از ماشین هاست مثل اینترنت) ارتبط داشته باشهشبکه Hostاگه یادتون باشه گفتیم تو شبکه از نوع Bridge، داکر روی سخت افزار شبکه ماشین Host (ماشینی که داکر روش نصب شده) یه شبکه‌ی مجازی ایجاد می‌کنه و کانتینرها از این شبکه مجازی استفاده می‌کننن، ولی تو شبکه از نوع هاست اینطوری نیس، برای شبکه Host داکر مسقیما از سخت افزار شبکه ماشین هاست استفاده میکنه، یعنی منابع نرم‌افزاری و سخت‌ افزاری شبکه ماشین هاست با کانتینر ها به اشتراک گذاشته میشه.حالا چه سودی داره این نوع از شبکه؟سرعت بالاتر: از اونجایی که دیگه خبری از یه شبکه مجازی نیس پس سرعت انتقال داده تو این شبکه بیشترهنیازی به Port Mapping نیست: تو این نوع شبکه دیگه نیاز نیست کانتینرها رو به یه Port از ماشین هاست Map کنیم. عملا میشه گفت دیگه از این لحاظ این نوع از شبکه ساده تره.دسترسی راحت تر: تو این نوع از شبکه، هر کدوم از کانتینرها مثل یه سرویس هستن که روی هاست ران شدن، پس ماشین های دیگه برای دسترسی به کانتینرها می تونن به راحتی از IP ماشین هاست و Portی که سرویس (کانتینر روش ران شده) استفاده کنناز اونطرف مشکلاتی که ممکنه بوجود بیاد:مشکل امنیتی: اگه یکی از کانتینرها مشکل امنیتی داشته باشه، از اونجایی که مستقیم روی شبکه ماشین هاست هست، میتونه ریسکی برای کانتینرهای دیگه یا ماشین هاست باشه.تداخل Portها: از اونجایی که دیگه Port Mapping نداریم، اگه دو یا چندتا از کانتینرها روی Port های مشابه اجرا بشن مشکل ایجاد می‌شه.شبکه Overlayخببب شبکه  Overlay، تا الان صحبت از این بود که کانتینرها دارن روی یک ماشین اجرا میشن و از منابع همون ماشین به صورت اشتراکی استفاده می‌کنن ولی اگه قرار باشه هر کدوم از این کانتینرها روی ماشین خودشون اجرا بشن چی؟ توی این حالت دیگه نمیشه از دو شبکه قبلی استفاده کرد، پس اگه قرار باشه کانتینرها که روی ماشین های مختلف اجرا میشن با هم ارتباط برقرار کنن باید از شبکه Overlay استفاده کنیم. این نوع از شبکه مخصوصا برای سیستم‌های توضیع شده خیلی مهم هست.موارد استفاده ش چیه؟در Docker Swarm: شبکه Overlay جزو جدانشدنی و بنیادین سولوشن Docker Swarm هست.معماری Microservice:  اگه قرار باشه چند میکروسرویس داشته باشیم که هر کدوم روی ماشین‌های مختلف اجرا میشن میتونیم از این نوع از شبکه برای ارتباط استفاده کنیم.و کلا همه مواردی که کانتینرها بصورت فیزیکی از هم جدا هستن و روی ماشین های مختلف اجرا میشنفک کنم تا همینجاش هم خیلی طولانی شد :) هدفم ایجاد کنجکاوی بود که برید و بیشتر راجع شبکه در داکر بخونین. یادتون باشه برای متخصص شدن جزییات مهم هستن، این جزییات هستن که شما رو از بقیه متمایز میکنه پس چیزی رو که ازش استفاده میکنین خوب راجع بهش یاد بگیرین تا بتونین به بهترین شکل ازش استفاده کنین و راه حل‌های درست رو پیدا کنین. نه اینکه صرفا چیزی درست کنیم که فقط کار میکنه :))در پایان مثل همیشه اینکه اگه نوشته رو دوست داشتید با دوستان به اشتراک بزارید که هم بهشون کمک کنه و هم انرژی بشه برای من که ادامه بدم :)اگه پیشنهادی هم برای موضوع نوشته بعدی دارین بگین.و اینکه میتونید منو با آی‌دی mehdi_zarepour تو توییتر پیدا کنید، نوشته‌های جدید رو اونجا توییت میکنم. اگه اینجا اکانت ندارین اونجا بهم پیام بدین یا منشن بزارین.</description>
                <category>Mehdi Zarepour</category>
                <author>Mehdi Zarepour</author>
                <pubDate>Sat, 30 Dec 2023 18:54:11 +0330</pubDate>
            </item>
                    <item>
                <title>Load Balancer</title>
                <link>https://virgool.io/codenevis/load-balancer-kkoxxuapklj6</link>
                <description>به این فکر کردین وبسایت ها یا اپلیکیشن‌هایی که ترافیک بالایی دارن چطوری زیر بار اینهمه درخواست همچنان stable می‌مونن؟ این اپلیکیشن‌ها از تکنیک‌های مختلفی تو قسمت‌های مختلف یه سیستم استفاده می‌کنن تا بتونن به حجم بالای درخواست ها جواب بدن و یکی از مهترین این تکنیک‌ها استفاده از Load Balancerهاست که قراره تو این نوشته کوتاه باهاش آشنا بشیم.اول بگیم Load Balancer چیه؟لود بالانسر یه دستگاه سخت‌افزاری یا یه نرافزار هست که ترافیک‌های ورودی یه شبکه یا یه اپلیکیشن رو بین چند سرور پخش می‌کنه و هدف اصلیش بالا بردن سطح performance، reliability و availability یه اپلیکیشن  یا یه وبسایت هست و این کار رو با پخش کردن لود درخواست های به اپلیکیشن بین چند سرور یه صورت مساوی و یا با یه الگوریتم مشخص انجام میده که بار همه درخواست ها روی دوش یه سرور نباشه که نتونه جوابگوی درخواست ها باشه.به تصویر بالا نگاه کنید، فرض کنید ما سه تا کپی از سرورمون داریم که قراره به ریکوئست های کاربرا جواب بدن، همونطور که می بینین یه Load Balancer این وسط قرار داده شده که ریکوئست‌ها اول به اون لودبالانسر ارسال میشن و این لود بالانسر درخواست ها رو به صورت مساوی بین سرورها تقسیم می کنه تا لود بین همه تقسیم شه تا همه کاربرا یا یه پرفورمنس خوب جواب درخواست‌هاشون رو بگیرن.لودبالانسر چطوری کار می‌کنه؟خب پس کار یه لود بالانسر اینه که ترافیک ورودی رو بین سرورها تقسیم کنه، ولی چطوری این کارو میکنه؟ لودبالانسرها از الگوریتم‌های مختلفی برای این کار استفاده می‌کنن که انتخاب این الگریتم‌ها بسته به نیاز اپلیکیشن می‌تونه متفاوت باشه، اگه بخواییم بعضی از این الگوریتم‌ها رو نام ببریم میتونیم به round-robin، least connections و IP hash اشاره کنیم.الگوریتم round-robin: این روشن ریکوئست های دریافتی با همون الگوریتم معروف راندرابین که تو درس سیستم‌های عامل و یا طراحی الگوریتم آشنا شدیم بین سرورها پخش می‌کنه.الگوریتم Least Connection: این روش ریکوئست‌های دریافتی رو با توجه به اینکه کدوم سرور کمترین تعداد کانکشن فعال داره، بین سرورها پخش می‌کنه.الگوریتم IP Hash: تو این روش ریکوئست‌ها با توجه به IP کلاینت بین سرورها پخش می‌شن.نکته: لود بالانسرها از یه مکانیزمی به اسم health check استفاده می‌کنن تا سرورهایی رو که با مشکل روبه‌رو شدن شناسایی کنن و تا موقعی که به حالت عادی برنگشتن از دور خارج میکنن و ریکوئستی رو به سمتشون ارسال نمی‌کنن.انواع لودبالانسرهالودبالانسرها رو میتونی به سه دسته کلی سخت‌افزاری، نرم‌افزاری و ابری تقسیم کنیم.لودبالانسرهای سخت‌افزاریاین لودبالانسرها، همونطور که از اسمشون پیداست دستگاه‌های سخت‌افزاری هستن که برای این کار طراحی شدن و جاهایی استفاده میشن که دردسترس بودن پرفرمنس بالا داشتن سیستم خیلی حیاتیه و معمولا تو سیستم‌هایی که با دیتاهای حیاتی سروکار دارن استفاده می‌شن. خیلی هم گرونن البته!لودبالانسرهای نرم‌افزاریلودبالانسرهای نرم‌افزاری که احتمالا ما بیشتر تاحالا باهاشون سروکار داشتیم روی سخت افزارهای استاندارد یا ماشین‌های مجازی نصب میشن که خیلی سولوشن‌های انعطاف پذیر و ارزونتری نسبت به سخت‌افزاری‌ها هستن. برای مثال می تونیم به موارد زیر اشاره کنیم:NginxHA ProxyApache HTTP Serverلودبالانسرهای ابریاین نوع از لودبالانسرها که توسط شرکت‌هایی که سروریس‌های ابری ارائه میدن ارائه میشه که خیلی انعطاف پذیر و scalable هستن و به راحتی با سرویس‌های دیگه اون شرکت مچ می‌شن و میشه با کمترین کانفیک ممکن ازشون استفاده کرد. برای مثال میشه سرویس‌های زیر رو نام برد:AWS Elastic Load Balancing (ELB)Microsoft Azure Load BalancerGoogle Cloud Load Balancingچرا باید از لودبالانسرها استفاده کنیم؟به مواردی زیادی میشه برای چرایی استفاده از لود بالانسرها اشاره کرد ولی به طوری کلی میشه به موارد زیر به عنوان مهم‌ترین ها اشاره کرد:برای Distribute Load: برای تقسیم ترافیک بین سرورها و جلوگیری از overload شدن سرور و جلوگیری یا پایین آوردن downtime.برای Scalability: با استفاده از لود بالانسرها scale کرد سرور خیلی راحت میشه، چون فقط کافیه یه سرور جدید رو به load balancer معرفی کنیم تا در چرخه قرار بگیره.برای High Availability: از اونجایی که لودبالانسرها از مکانیزم health check برای شناسایی سرورهای معیوب استفاده می‌کنن، سیستم رو به صورت کامل available نگه میدارن و درخواست ها رو به سمت سرور معیوب نمی‌فرستن.برای Security: لودبالانسرها همچنین ویژگی‌های امنیتی مثل DDoS Protection و SSL رو در اختیارمون قرار میدن تا امنیت سیستم رو بالا ببریم.در پایان مثل همیشه اینکه اگه نوشته رو دوست داشتید با دوستان به اشتراک بزارید که هم بهشون کمک کنه و هم انرژی بشه برای من که ادامه بدم :)و اینکه میتونید منو با آی‌دی mehdi_zarepour تو توییتر پیدا کنید، نوشته‌های جدید رو اونجا توییت میکنم.</description>
                <category>Mehdi Zarepour</category>
                <author>Mehdi Zarepour</author>
                <pubDate>Thu, 14 Dec 2023 00:10:33 +0330</pubDate>
            </item>
                    <item>
                <title>چطوری داکرفایل بهینه نویسیم (Dockerfile Best Practices)</title>
                <link>https://virgool.io/@mehdi.zarepour/%DA%86%D8%B7%D9%88%D8%B1%DB%8C-%D8%AF%D8%A7%DA%A9%D8%B1%D9%81%D8%A7%DB%8C%D9%84-%D8%A8%D9%87%DB%8C%D9%86%D9%87-%D9%86%D9%88%DB%8C%D8%B3%DB%8C%D9%85-dockerfile-best-practices-e5aiykdpluhw</link>
                <description>تو نوشته قبلی با هم یه پروژه NodeJS رو Dockerize کردیم که درنهایت Dockerfile زیر شد خروجی نهایی که ایمیج رو از روش ساختیم:FROM node:18.17-alpine

WORKDIR /home/app

COPY . . 

RUN npm i

CMD npm run startخب همونطور که گفتم تو این نوشته قراره این Dockerfile رو بررسی کنیم و به صورت بهینه بازنویسی کنیم و best practice ها رو توش رعایت کنیم. قبل از این کار بیاییم یه سری از این best practice های اساسی رو با هم مرور کنیم.دستور FROMهمونطور که میدونید از دستور FROM برای مشخص کردن base ایمیجمون استفاده می‌کنیم و با دستورات دیگه با توجه به اینکه base رو چی انتخاب کردیم نیازمندی‌های دیگه نرم‌افزار رو به ایمیج اضافه می‌کنیم. تو هر Dockerfile حداقل یک بار از دستور FROM استفاده میشه (برای مشخص کردن base) ولی ممکنه بیشتر از یک بار هم برای مواردی که بیلد multi stage داریم هم استفاده کنیم.مواردی که باید زمان استفاده از FROM در نظر داشته باشیم۱. همیشه از tag استفاده کنیمFROM ubuntu:23.10اسم تگ بعد از اسم image (که اینجا ubuntu) و بعد از &#x60;:&#x60; میاد که اینجا 23.10 هست، چرا؟ بخاطر اینکه تگ نشون دهنده یه ورژن مشخص از اون image هست و اینطوری مشخص می‌کنیم که دقیقا از چه ورژنی از این ایمیج میخواییم استفاده کنیم. اگه تگ رو مشخص نکنیم به صورت پیشفرض از تگ latest استفاده میشه، یعنی:FROM ubuntuبرابر است با:FROM ubuntu:latestاینطوری یعنی هر دفه که ما ایمیجمون رو بیلد می‌کنیم از روی آخرین ورژن Ubuntu ساخته میشه و مشکل موقعی ایجاد میشه که تو آخرین آپدیت Ubuntu یه چیز جدیدی اضافه یا کن شده باشه که دیگه با ایمیجی که میخواییم بسازیم سازگار نیست! پس بهتره مشخص کنیم دقیقا کدوم ورژن Ubuntu رو میخواییم تا مطمعن باشیم هر دفه که ایمیج رو بیلد میکنیم هیچ چیز ناخواسته ای کم و زیاد نشده.۲. به سایز ایمیج توجه کنیمایمیجی که برای base انتخاب می‌کنیم تاثیر خیلی زیادی روی سایز نهایی ایمیجمون داره، پس همیشه ایمیجی رو انتخاب کنیم که فقط چیزهایی که نیاز داریم رو داشته باشه، نه بیشتر نه کمتر. مثلا ما اینجا Ubuntu رو برای بیس انتخاب کردیم که تقریبا 25MB حجمشه، سوالی که اینجا باید از خودمون بپرسیم اینه که آیا ما واقعا به همه‌ی امکاناتی که Ubuntu بهمون میده نیاز داریم؟ یا میتونیم یه ایمیج دیگه با حجم پایینتر انتخاب کنیم؟مثلا اگه alpine برامون کافیه پس بهتره از alpine بجای Ubuntu استفاده کنیم چون جحمش فقط 3MB هست! البته اینم بگم که صرفا فقط فضایی که اشغال میکنه نیست، بلکه alpine منابع کمتری مثل رم و CPU در مقایسه با Ubuntu استفاده میکنه. پس تو انتخاب base ایمیج دقت کنید.۳. ایمیج قابل اعتماد انتخاب کنیمسعی کنید همیشه از ایمیج های رسمی استفاده کنید تا خیالتون راحت باشه که مشکل امنیتی نداره و اگه مشکلی وجود داره حلش میکنن. برای اینکار به دوتا نکته توجه کنید:توی داکرهاب جلوی اسم ایمیج نوشته شده باشه (Docker Official Image)تعداد دانلود بالایی داشته باشهدستور WORKDIRمشخص کردن work directory یکی از مهم‌ترین best practiceهاست که باید رعایت کنیم تا مطمعن باشیم داریم دستورات رو تو چه دایرکتوری اجرا می‌کنیم. بریم سراغ best practiceهایی که باید برای WORKDIR رعایت کنیم:۱. همیشه از WORKDIR استفاده کنیمبجای اینکه از دستور cd برای اجرای دستورات در یک دایرکتوری مشخص، همیشه از WORKDIR استفاده کنیم.WORKDIR /app۲. همیشه از Absolute Path استفاده کنیماینطوری هم خواناتر هست هم از مشکلات احتمالی جلوگیری می‌کنیم# Good
WORKDIR /app

# Bad
WORKDIR app۳. همیشه از دایرکتوری‌های خاص (Dedicated) استفاده کنیمیعنی بجای استفاده از دایرکتوری &#x60;/&#x60; root، یا دایرکتوری های جنرال مثل usr/src/ از دایرکتوری‌‌های خاص مثل app/my-app-name/  استفاده کنیم، اینطوری از تداخلی که با چیزهای دیگه ممکنه بوجود بیاد جلوگیری می کنیم و هم اینکه کاملا مشخص هست که اطلاعات مربوط به پروژه کجا هست.WORKDIR /app/my-app-name۴. از Environment Variables برای WORKDIR استفاده نکنیمهرچند میشه از Environment Variables زمان تعریف working directory استفاده کرد ولی بهتره این کار رو نکنیم چون خوانایی داکرفایل میاد پایین و یا حتی ممکنه با تغییر ناخواسته اون Environment Variable مشکلی ناخواسته بوجود بیاد.FROM ubuntu:20.04
# Bad
WORKDIR $APP_PATH

# Good
WORKDIR /myapp۵. دسترسی به working directoryهمیشه مطمعن باشین user کانتینرتون همه دسترسی‌های لازم به این working directory رو داره.دستور RUNدستور RUN یکی از دستورهای اساسی تو داکرفایل به حساب میاد که باهاش دپندنسی‌های مورد نیاز رو اضافه می کنیم. و اما best practiceهای زمان استفاده از RUN:۱. استفاده از Chain Commandsهر دستور RUN که تو داکرفایل استفاده می‌کنیم یه لایه جدید برای ایمیج ایجاد میکنه که هر لایه نقش خیلی زیادی در حجم نهایی ایمیج، کش کردن، سرعت بیلد و... داره پس اگه میشه چند دستور رو با استفاده از یک RUN اجرا کنیم بهتره تنها یک بار از RUN استفاده کنیم و دستورات رو به صورت chain بنویسیم، برای درک بهتر مثال زیر رو ببینید:RUN apt-get update 
RUN apt-get install -y some-packageدر مثال بالا از ۲ دستور RUN برای نصب یه پکیجی استفاده شده که باعث میشه دوتا لایه جداگونه برای ایمیج ایجاد کنه درصورتی که اگه به شکل زیر دستورات رو Chain کنیم فقط یک لایه ایجاد میشه و دقیقا همون نتیجه رو هم داره:RUN apt-get update &amp;&amp; \
    apt-get install -y some-package۲. لایه ها رو جارو کنیم :)خیلی وقتا بعد از اجرای یه دستوری ممکنه فایل‌هایی وجود داشته باشه که ما دیگه بهشون نیاز نداریم، پس بهتره این فایل‌ها رو تو همون لایه حذف کنیم تا حجم اون لایه بیاد پایین، مثلا اینجا ما اومدیم یه پکیجی رو نصب کردیم:RUN apt-get update &amp;&amp; \
     apt-get install -y some-packageاین دستور یه لایه جدید ایجاد می‌کنه که پکیج جدید رو بهش اضافه می‌کنه ولی می تونه حجمش کمتر و تمیز تر باشه. برای این مثال، تو سیسم‌عامل های دبیان بیس، بهتره دستورات زیر رو هم اضافه کنیم تا فایل‌های اضافه زمان اجرای دستور رو حذف کنیم:RUN apt-get update &amp;&amp; \
    apt-get install -y some-package &amp;&amp; \
    apt-get clean &amp;&amp; \
    rm -rf /var/lib/apt/lists/*اینطوری بعد از نصب پکیج فایل‌های اضافه رو حذف می‌کنیم و حجم نهایی لایه میاد پایین. این نکته کاملا بستگی به دستوری داره که اجرا می‌کنین، ممکنه دستوری چیزی برای تمیز کاری نداشته باشه یا داشته باشه ولی در کل این نکته تو ذهنتون باشه که اگه میشه باید تمیز کرد.۳. فقط پکیج‌های لازم رو نصب کنیمگفتن نداره ولی :)، پکیجی که نیاز نداریم رو صرفا نصب نکنین چون شاید ممکنه نیاز بشه، چون دار فضا اشغال می‌کنه و همینطور حجم لایه و درنهایت ایمیج رو بالا می‌بره.۴. استفاده از Non-Interactive Modeبعضی دستورات ممکنه interactive باشن، یعنی برای انجام کاری نیاز به تایید داشته باشن، ولی از اونجایی که تو فرایند بیلد ایمیج ما دیگه دسترسی برای تایید کردن نداریم (اصلا تایید کردن معنایی نداره) باید مطمعن باشیم که دستورات تو حالت Non-Interactive اجرا میشن. مثلا برای سیستم‌عامل های دبیان بیس میتونیم دستور اینطوری بنویسیم:RUN apt-get update &amp;&amp; \
    DEBIAN_FRONTEND=noninteractive apt-get install -y some-package &amp;&amp; \
    apt-get clean &amp;&amp; \
    rm -rf /var/lib/apt/lists/*با استفاده از DEBIAN_FRONTEND و y- آپشن میتونیم مطمعن باشیم  که مراحل اجرای دستور بدون نیاز به وقفه ای اجرا میشه.استفاده درست از Secretهاهیچ وقت secretهایی مثل password یا API Key رو مستقیم توی اسکریپت داکرفایل نزاریم، بجاش در زمان بیلد از طریق ARG این secret ها رو داکرفایل اضافه کنیم:Bad practice:FROM node:14
ENV API_KEY=your_actual_api_key_hereGood practice:FROM node:14  
ARG API_KEY
ENV API_KEY=$API_KEYاستفاده از dockerignore.همونطور که از gitignore. استفاده می‌کنیم باید از dockerignore. استفاده کنیم تا فایل‌هایی که نیاز نیستن ناخواسته کپی نشن تا بی‌مورد حجم ایمیجمون بالا نره.استفاده از root user و non-root userخیلی خلاصه، یوزر root بهتره فقط برای جاهایی استفاده بشه که حتما نیاز به دسترسی root داریم، مثل نصب کردن پکیج‌های سیستم، بقیه دستورات که نیاز به دسترسی root ندارن بهتره با non-root user اجرا بشن. خیلی نکته‌های مهمی راجع به استفاده از root user و non-root user هست که تو این نوشته نمیگنجه ولی این نکته ها رو یادتون باشه:حواستون باشه که non-root user دسترسی لازم به دایرکتوری که قراره روش کار کنه داشته باشهتا جای ممکن بین یوزرها سوییج نکنید، همه‌ی کارهای لازم رو root user انجام بدین و بعد سوییچ کنین روی non-rootهمیشه با non-root user دستورات CMD و ENTRYPOINT رو اجرا کنینFROM node:14

# As root: Create app directory and install dependencies
WORKDIR /app
COPY . .
RUN npm install

# As root: Create a non-root user named &#039;user1&#039;
RUN useradd user1 &amp;&amp; chown -R user1 /app

# Switch to &#039;user1&#039; for runtime
USER user1

# Run the application as &#039;user1&#039;
CMD [ &amp;quotnode&amp;quot, &amp;quotindex.js&amp;quot ]ترتیب اجرای دستورات  برای بهینه کردن کشهرچی فک کردم عنوان فارسی خوب نتونستم پیدا کنم، واقعا سخته فارسی رو پاس داشت :)) به این best practice اصطلاحا Optimizing Docker Layer Caching یا Leveraging Build Cache گفته میشه. بیایین اینو با یه مثال توضیح بدیم که قابل درک‌تر بشه.فرض کنیم این Dockerfileی هست که برای پروژه‌مون پیاده کردیم:FROM node:18.17-alpine
COPY . /app
WORKDIR /app
RUN npm installحالا بیاییم مرحله به مرحله چک کنیم که چه اتفاقی میافته:تو مرحله اول &#x60;node:18.17-alpine&#x60; به عنوان بیس ایمیج درنظر گرفته میشهکد اپلیکیشنمون با استفاده از دستور COPY کپی میشنبا استفاده از WORKDIR، دایرکتوری رو به app/ تغییر میدهو درنهایت پکیج‌های برنامه رو نصب می‌کنهاین داکرفایل از لحاظ تکنیکی هیچ مشکلی نداره، ولی... بهینه نیس، اصلا هم بهینه نیست. چرا؟ بزارین اینطوری بهش نگاه کنیم، در زمان دولوپ یه برنامه یا تو release های مختلف بیشترین چیزی که تغییر میکنه کد برنامه ست که تو app/ قرار داره و اصولا خیلی کم پیش میاد که بخواییم پکیجی رو به برنامه اضافه کنیم یا ازش کم کنیم درسته؟ این تو ذهنتون باشه، ببینیم داکر چطوری لایه‌ها رو کش میکنه.داکر وقتی تغییر جدیدی توی هر کدوم از لایه ها نبینه از کش استفاده میکنه و دوباره اون لایه رو ایجاد نمیکنه، ولی وقتی تغییری تو یه لایه ایجاد میشه دیگه داکر از کش اون لایه و همه‌ی لایه‌های زیریش استفاده نمی‌کنه و دوباره اون لایه ها رو ایجاد میکنه. یعنی اگه تغییری توی کد ایجاد بشه یعنی یه تغییری تو لایه‌ای که با COPY ایجاد کردیم اتفاق افتاده، یعنی اینجا:COPY . /appپس این لایه و همه‌ی لایه‌های زیریش حتی اگه تغییری هم توشون اتفاق نیافته باشه دوباره ایجاد میشن، یعنی این لایه‌ها:WORKDIR /app
RUN npm installدرصورتی که هیچ تغییری توی پکیج‌ها مون وجود نداره و همچنان میتونن کش بشن! پس این ترتیب درست نیست و باید تا جایی که میشه، لایه‌هایی که احتمال تغییر توشون بالا هست رو باید به لایه های پایین تر انتقال بدیم. با این تعریف حالت بهینه داکرفایل بالا میشه این:FROM node:18.17-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .توی این حالت دیگه اگه تغییری تو کد برنامه ایجاد بشه لایه های بالایی همچنان کش میشن.استفاده از Labelهابا استفاده از LABELها می‌تونیم متادیتا به ایمیج اضافه کنیم که کمک میکنه اطلاعات بیشتری نسبت به ایمیج داشته باشیم، مثلا اینکه maintainer کی هست و یا versionش چیه و... و همیچنین لیبل‌ها کمک میکنن که بفهمیم هدف نهایی یه ایمیج مشخص چی هست.FROM node:14

# Add metadata using the LABEL instruction
LABEL maintainer=&amp;quotMehdi Zarepour &lt;mehdi.zarepoor@gmail.com&gt;&amp;quot
LABEL version=&amp;quot1.0&amp;quot
LABEL description=&amp;quotThis is a sample Node.js app&amp;quot
LABEL git.url=&amp;quothttps://github.com/mehdizarepour/backend.git&amp;quot
LABEL build.date=&amp;quot2023-09-14&amp;quot

WORKDIR /app

COPY package*.json ./

RUN npm install

COPY . .

CMD [&amp;quotnpm&amp;quot, &amp;quotstart&amp;quot]به یکی از موارد استفاده از لیبل‌ها میشه به پیدا کردن یه ایمیج با یه لیبل مشخص اشاره کرد:docker images --filter &amp;quotlabel=version=1.0&amp;quotخب بنظر بهتره بیشتر از این طولانی نشه که از حوصله خارج نشه :) پیشنهاد میکنم حتما موارد دیگه که من نگفتم رو از سایت خود داکر بخونید، اگه چیزی رو اشتباه گفتم یا پرکتیس بهتری میشناسید بهم بگید :)https://docs.docker.com/develop/develop-images/dockerfile_best-practicesخب حالا بعد از همه‌ی این توضیحات بیاییم اون داکرفایل اول نوشته رو بهینه کنیم:# Start with a specific version of the base image
FROM node:18.17-alpine

LABEL maintainer=&amp;quotMehdi Zarepour &lt;mehdi.zarepoor@gmail.com&gt;&amp;quot

# Install system-level dependencies (if any) as root, but We don&#039;t have any :)

# Create a non-root user and switch to it
RUN adduser -D node
USER node

# Set up the working directory
WORKDIR /home/node/app

# Copy only the necessary files for npm install to use cache effectively
COPY package*.json ./

# Install project dependencies
RUN npm i

# Copy the rest of the application
COPY --chown=node . .

# Start the application
CMD [&amp;quotnpm&amp;quot, &amp;quotrun&amp;quot, &amp;quotstart&amp;quot]نمی‌دونم کسی منتظر بود بازم بنویسم یا نه :) ولی اگه کسی بود و میخواد بدونه چرا طول کشید تا اینو بنویسم باید بگم که اینسری افسوردگی خیلی سنگین بود، یکم طول کشید ازش بیام بیرون :)) سعی میکنم بازم بنویسم ;)در پایان مثل همیشه اینکه اگه نوشته رو دوست داشتید با دوستان به اشتراک بزارید که هم بهشون کمک کنه و هم انرژی بشه برای من که ادامه بدم :)و اینکه میتونید منو با آی‌دی mehdi_zarepour تو توییتر پیدا کنید، نوشته‌های جدید رو اونجا توییت میکنم. فعلا نوشته‌هام راجع به داکر خواهد بود.نظرتونم بنویسین :)</description>
                <category>Mehdi Zarepour</category>
                <author>Mehdi Zarepour</author>
                <pubDate>Thu, 14 Sep 2023 20:48:59 +0330</pubDate>
            </item>
                    <item>
                <title>چگونه پروژه خود را Dockerize کنیم؟</title>
                <link>https://virgool.io/@mehdi.zarepour/%DA%86%DA%AF%D9%88%D9%86%D9%87-%D9%BE%D8%B1%D9%88%DA%98%D9%87-%D8%AE%D9%88%D8%AF-%D8%B1%D8%A7-dockerize-%DA%A9%D9%86%DB%8C%D9%85-ooqbpxvft62e</link>
                <description>احتمالا واژه Containerization رو خیلی شنیدیم، این واژه یعنی چی؟ Containerization تکنولوژی هست که به ما این اجازه رو میده که بتونیم برنامه‌ها یا اپلیکیشن‌ها مون رو در کنار همه‌ی دپندنسی‌هاش در یک پکیج به نام Container بسته بندی کنیم، کانتینرها فضایی ایزوله‌ شده برای برنامه‌هامون ایجاد میکنن که بتونیم اون‌ها رو تو محیط‌های مختلف (مثلا یه سیستم دیگه یا یک سرور تو فضای ابری) بدون نگرانی از فراهم بودن منابع مورد نیازشون اجرا کنیم.حالا ممکنه این سوال پیش بیاد که پس Dockerize کردن یعنی چی؟مفهوم Dockerize کردن برنامهخب تا اینجا گفتیم که Containerization کردن چیه و به چه دردی می‌خوره، بریم سراغ Dockerize. به نظر وقتی میگیم Container همه ذهن‌شون میره سمت داکر! درصورتی که داکر تنها  پلتفرمی نیست که امکان ایجاد کانتینر رو بهمون میده بلکه پلتفرم‌های دیگه ای مثل Podman، rkt، LXC و.. هم وجود دارن که هر کدوم‌شون تو یه زمینه‌ای بهتر از دیگری هستن.پس با این تعریف Dockerize کردن یعنی ما با استفاده از Docker نرم‌افزارمون رو Containerized می‌کنیم، پس مفهوم جدیدی نیس که داکر ایجاد کرده باشه.داکر مثل اون پلتفرم‌های دیگه ابزار‌ها و تکنولوژی‌های مختلفی رو برای ایجاد کانتینر در اختیارمون قرار میده که Dockerfile و Docker Image از اساسی‌ترین ابزارها برای این کار هستن. تو این نوشته هم قراره بیشتر با Dockerfile آشنا بشیم.داکرایمیج Docker Imageهمونطور که گفتیم داکر یکی از چندین پلتفرم‌هایی هست که امکان Containerized کردن نرم‌افزار رو بهمون میده، پس هدف نهایی داکر ایجاد این کانتینرهاس و هر مفهموم دیگه‌ای (مثل Docker Image) که داکر در اختیارمون قرار میده صرفا ابزاری هستن براین ایجاد کانتینرها.داکرایمیح هم از اساسی‌ترین این مفاهیم هست و نقش مرکزی در ایجاد کانتینرها داره، چون یک container در نهایت از روی Image ساخته میشن و این ایمیج‌ها مثل نقشه‌هایی هستن که مشخص میکنن یک کانتینر باید شامل چه تنظیمات، فایل‌ها و دستوراتی برای اجرا باشند.داکرفایل Dockerfileخب وقتی Container از روی Docker Image ساخته می‌شه پس ما نیاز به ابزاری داریم که بتونیم این ایمیج‌ها رو ایجاد کنیم و Dockerfile همون ابزاری هست که داکر برای ایجاد Image در اختیارمون قرار میده. داکرفایل یه فایل متنی به اسم &#x60;Dockerfile&#x60; هست که توش مشخص می‌کنیم که میخواییم Imageمون شامل چه چیزهایی باشه.برای آشنایی بیشتر با Dockerfile و Dockerize کردن پروژه بیاییم با یه مثال عملی پیش بریم. چند سال پیش یه پروژه NodeJS که برای شالوده پروژه‌هام استفاده می کردم رو توی GitHub گذاشتم که می‌تونه مثال خوبی باشه. البته شما می‌تونید هر پروژه ای با هر زبونی که دوست دارید رو انتخاب کنید.برای شروع پروژه رو از این Repository با دستور زیر Clone کنید.git clone https://github.com/mehdizarepour/backend.gitحالا اگه پروژه رو با ادیتورتون باز کنید باید به شکل زیر باشه:اینکه پروژه چیه و چه قابلیت‌هایی داره و یا قسمت‌های مختلفش چیکار می‌کنن مهم نیس، صرفا خواستم از یه پروژه واقعی استفاده کرده باشم، پس وارد جزییات‌ش نشین (البته پروژه‌ی خوبیه، پیشنهاد می‌کنم بعدا یه نگاه بهش بندازین ?).خب از اونجایی که این یه پروژه NodeJS هست قبل از اجرا باید ماژول‌هاش رو نصب کنیم، برای این کار دستور زیر رو اجرا کنید:npm iو برای اجرا دستور زیر رو اجرا کنید:npm startبعد از اجرای این دستور احتمالا به خطای زیر میخورید:[Exception] ENOENT: no such file or directory, open &#039;./runtime/private.key&#039;
  stack: Error: ENOENT: no such file or directory, open &#039;./runtime/private.key&#039;این خطا برای اینه که چون پروژه از JWT برای احرازهویت استفاده می‌کنه و شما private key و public key رو توی فلدر runtime ندارید، برای حل این مشکل اگه دوست دارید میتونید این فایل‌ها رو اضافه کنید اگه هم نه صرفا برید به فلدر config/app.js/ و این دو خطی که پایین تو عکس نشون دادم رو کامنت کنید:حالا دوباره دستور npm start رو اجرا کنید تا پروژه به درستی اجرا بشه:خب رسیدیم به جای قشنگش ?، تا اینجا دو تا مشکل برای اجرا کردن پروژه ای که من نوشتم و به شما دادم برای اینکه اجرا کنید وجود داشت، چی؟اگه شما NodeJs رو سیستم‌تون نصب نباشه؟ اگه ندونید اصلا پروژه نود رو چطوری اجرا می‌کنن چی؟پروژه برای اجرا شدن به دوتا فایل نیاز داشت (private.key و public.crt) که شما روح‌تونم خبر نداشت :)خب همین دو مسئله باعث شد پروژه‌ای که من نوشتم قابل‌حمل نباشه و شما نتونید روی سیستم خودتون (یا یه سرور) اجراش کنید. این دقیقا یکی از مشکلاتی هست که ما می‌خواییم با Containerized کردن حلش کنیم، یعنی شما بتونید نرم‌افزار یا پروژه‌ای که من نوشتم رو بدون نگرانی از اینکه آیا نیازمندی‌ها یا دپندنسی‌هاش (مثل NodeJs) رو روی سیستم خودتون دارید یا نه اجرا کنید. اگه هنوز این سوال براتون وجود داره که چرا ما نیاز داریم یه نرم‌افزار یا اپلیکیشن رو Containerized یا Dockerize کنیم، پیشنهاد می کنیم یه نگاه به این نوشته که راجع به چرایی استفاده از داکر توضیح دادم بندازین.خب حالا که مشکل و راه حل رو فهمیدیم بیاییم پروژه رو Dockerize کنیم که هرکسی بتونه به راحتی روی هر سیستمی اجراش کنه.داکرایز کردن پروژهبرای شروع یه فایل به اسم Dockerfile به روت پروژه به شکل زیر اضافه می‌کنیم:خب قبل از اینکه شروع کنیم بیاییم یه بار دیگه یادآوری کنیم که ما قراره همه‌ی دپندنسی‌های اجرا شدن این نرم‌افزار رو تو یه Image پکیج کنیم، پس با استفاده از Dockerfile می‌خواییم مشخص کنیم که این دپندنسی‌ها چی هستن تا داکر از روی اون image رو ایجاد کنه. پس بیاییم راجع به دپندنسی‌های این برنامه صحبت کنیم و ببینیم چه چیزهایی نیازه:سیستم‌عامل قاعدتا اولین نیازمندی یه نرم‌افزار یه سیستم‌عامل هست که بتونه روش اجرا بشه و همینطور دپندنسی‌هاش روش نصب یا کانفیگ بشه. برای اینکار ما از دستور FROM استفاده می‌کنیم تا سیستم‌عامل مدنظرمون رو به عنوان base image انتخاب کنم.شاید سوال باشه که منظور از base image چیه؟ اگه بخواییم خیلی ساده به این سوال جواب بدیم، اینطور می‌گم که، یه سری تنظیمات و یا دپندنسی‌ها هست که خیلی کلی هستن و تقریبا تو همه‌ی نرم‌افزارها مشترکن، مثلا تنظیماتی که برای خود سیستم‌عامل هستن، خب وقتی ما می‌خواییم دپندنسی‌های خاص نرم‌افزار خودمون رو اضافه کنیم نباید نگران این باشیم که آیا مثلا سیستم‌عامل درست کانفیگ شده یا نه که، درسته؟با استفاده از base image ما یه imageی رو انتخاب میکنیم تا نیازمندی‌های خودمون رو بهش اضافه کنیم تا یه ایمیج جدید بسازیم، پس دستور FROM برای انتخاب base imageمون اولین دستوری هست که تو Dockerfile می‌نویسیم(اولین دستوری که کامنت نیست).انتخاب من برای base image سیستم‌عامل Alpine Linux هست، چون یه سیستم‌عامل سبکه و چیز اضافه‌ای هم روش نصب نیس که باعث میشه حجم image من زیاد نشه. پس Dockerfile رو به شکل زیر تعیین میکنم:تو این دستور در مقابل کلمه کلیدی FROM اسم ایمیج که alpine هست آورده شده و بعد از &#x60;:&#x60; هم تگ اون ایمیج که latest هست اینجا آورده شده، این یعنی ما آخرین ورژن ایمیج alpine رو به عنوان بیس ایمیجمون انتخاب کردیم و حالا وقته اینه که دپندنسی‌های دیگه رو روش نصب کنیم.نصب NodeJs از اونجایی که برنامه‌مون با NodeJs نوشته شده پس قطعا نیاز داریم که NodeJs رو روی alpine و ایمیجمون داشته باشیم، پس  از دستور  RUN استفاده می‌کنم تا NodeJs رو نصب کنم، که میشه به شکل زیر:دستور RUN این امکان رو بهمون می‌ده که دستوراتی که جلوش می‌نویسیم (که اینجا &#x60;apk add --update nodejs npm&#x60; هست) رو روی shell سیستم‌عامل اجرا کنیم، یا به بیان ساده تر انگار اون دستور رو داریم توی ترمینال اون سیستم‌عامل اجرا می‌کنیم.نکته: بسته به اینکه سیستم‌عاملی که انتخاب می‌کنید چی هست، دستوری که برای نصب nodejs استفاده می‌کنید متفاوت خواهد بود، مثلا اگه بیسمون ubuntu بود از دستور &#x60;apt install&#x60;  استفاده می کردیم.خب تا اینجا NodeJs رو هم نصب کردیم، ولی این کار زیاد درست و استاندارد نبود! چرا؟ چون تقریبا همه‌ی این تکنولوژی‌ها مثل NodeJs خودشون نسخه رسمی ایمیجی رو در اختیارمون قرار می‌دن که NodeJs روش نصب هست و احتمالا به بهترین شکل ممکنه کانفیگ شده.انتخاب image base مناسبمثلا ما اگه میخواییم سیستم‌عامل‌مون alpine باشه باید ایمیجی از nodejs استفاده کنیم که روی alpine نصب شده، اینطوری ما یه alpine داریم که روش nodejs از قبل نصب شده و دیگه نیاز نیس ما نصبش کنیم. برای پیدا کردن این ایمیج‌ها میتونیم به Docker Hub مراجعه کنیم و ایمیجی که می‌خواییم رو سرچ کنیم که معمولا لینکشون تو خود سایت این تکنولوژی‌ها هست.برای NodeJs میتونیم به صفحه رسمیش تو داکرهاب بریم (https://hub.docker.com/_/node)، که اگه یکم بریم پایین‌تر میتونیم این قسمت که راجع به ورژن alpine توضیح میده رو می‌بینیم که توضیح داده شامل چه چیزهایی میشه و حجمش چقدره:از اونجایی که آخرین ورژن stableه NodeJs درحال حاضر &#x60;18.17.0&#x60; هست پس اسم ایمیجی که میخواییم به عنوان base ازش استفاده کنیم میشه &#x60;node:18.17-alpine&#x60; از کجا می‌دونم؟ چون اینجا نوشته :)البته اگه می‌خوایین دقیق‌تر دنبال یه image مشخص بگردین میتونین به قست tags برید و ایمیج مورد نظر خودتون رو پیدا کنید:البته می‌تونید از این افزونه‌ها هم روی ادیتورتون استفاده کنید برای پیدا کردن ایمیجی که می خوایین:نکته: سعی کنید همیشه از ایمیج‌های رسمی استفاده کنید، یا اگه نبود حتما نگاه کنید چقدر دانلود یا ستاره داره، اینطوری می‌تونید مطمعن باشید imageی که انتخاب می‌کنید مشکلی نداره:پس با این تعریف، Dockerfileمون رو به شکل زیر تغییر می‌دیم:و دیگه نیازی به &#x60;RUN apk add --update nodejs npm&#x60; هم نداریم.اضافه کردن پروژه به Imageتا اینجا یه سیستم‌عامل داریم که NodeJs هم روش نصب شده و بنظر میاد همین برای پروژه‌مون کافی باشه تا بتونه با موفقیت اجرا بشه، پس می‌ریم سراغ اینکه خود پروژه‌مون رو تو ایمیج قرار بدیم. ولی قبل از اون بیاییم با دستور WORKDIR آشنا بشیم.کاربرد WORKDIRبا استفاده از این دستور می‌تونیم مشخص کنیم دایرکتوری جاری (current directory) که دستورات بعدی قراره اجرا بشن کجاست، خیلی ساده بخوام بگم وقتی داکر به این خط می‌رسه مثل این می‌مونه که ما از دستور cd استفاده کردیم تا داریکتوری‌مون رو تغییر بدیم به مسیری که مورد نظرمونه، با این تفاوت که حتی اگه اون دایرکتوری وجود نداشت داکر برامون اون دایرکتوری رو می‌سازه. پس دستور زیر مارو منتقل می کنه به &#x60;home/app/&#x60;.WORKDIR /home/appیعنی اگه ما بعد از این دستور از pwd استفاده کنیم تا دایرکتوری جاری رو ببینیم، خروجی &#x60;home/app/&#x60; خواهد بود.کپی کردن پروژهخب حالا برگردیم به جایی که میخواستیم پروژه رو به ایمیج اضافه کنیم، برای این کار از دستور COPY استفاده می‌کنیم تا فایل‌های پروژه رو کپی کنیم تو ایمیج، ولی قبل از اون WORKDIR رو به home/app/ تغییر میدم، چون نمیخواییم فایل‌های پروژه رو تو root سیستم‌عامل بریزیم، میخواییم جایی کپی کنیم که مشخصا می‌دونیم کجاست تا بتونیم کنترول روش داشته باشه باشم و مدیریتش کنیم. پس داکر فایل رو به شکل زیر تغییر می‌دیم:FROM node:18.17-alpine
WORKDIR /home/appحالا وقتشه که از دستور COPY برای کپی کردن فایل‌های پروژه استفاده کنیم، ساختار این دستور به شکل زیره:COPY &lt;source&gt; &lt;destination&gt;مبدا یا source: آدرس دایرکتوری پروژه‌مون رو سیستم‌مون که میخواییم کپی‌ش کنیم هست که باید یک آدرس relative باشه.مقصد یا destination: آدرس جایی هست که میخواییم فایل‌هامون کپی بشه تو ایمیج.پس با این تعریف من دستور کپی رو به شکل زیر به داکرفایلم اضافه می‌کنم:FROM node:18.17-alpine
WORKDIR /home/app
COPY . .که این دستور دارکتوری جاری روی سیستم‌مون (با توجه به build context موقع اجرا docker build - جلوتر راجع بهش حرف می‌زنیم) رو کپی می‌کنه تو home/app/ تو کانتینر یا ایمیج.نصب دپندنسی‌های پروژهتا اینجا خوده پروژه رو هم کپی کردیم، حالا وقت اینه که دپندنسی‌های خود برنامه رو نصب کنیم، از اونجایی که پروژه NodeJs هست باید با استفاده از دستور npm i دپندنسی‌هایی که تو packge.json مشخص شد رو نصب کنیم. پس برای این کار از دستور RUN استفاده به شکل زیر استفاده می‌کنیم:FROM node:18.17-alpine
WORKDIR /home/app
COPY . .
RUN npm iتعیین دستور پیشفرض برای اجرای کانتینرحالا که همه دپندنسی‌ها فراهم شدن وقت این رسیده که با CMD دستور پیشفرضی که قراره بعد از ساختن کانتینر از روی این ایمیج اجرا بشه رو تعیین کنیم. از اونجایی که ما می‌خوایم پروژه رو اجرا کنیم پس دستور اجرایی می‌تونه npm run start باشه تا پروژه اجرا بشه، پس داکرفایل رو به شکل زیر تغییر میدیم:FROM node:18.17-alpine
WORKDIR /home/app
COPY . .
RUN npm i
CMD npm run startخب دیگه پروژه با موفقیت Dockerize شده و الان وقت این رسیده که از روش یه ایمیج ایجاد کنیم و تست‌ش کنیم.ایجاد Image از روی Dockerfileبرای ایجاد ایمیج کافیه که به دایرکتوری که Dockerfile قرار داره بریم و دستور زیر رو اجرا کنیم:docker build . -t backendنکته: دات که بعد از build اومده مشخص کننده build context و محلی هست که داکر باید دنبال Dockerfile برای ساخت ایمیج بگرده. برای اطلاعات بیشتر ای قسمت از داکیومنت داکر رو بخونید.بعد از اجرا دستور خروجی‌مون به شکل زیر باید باشه:برای نمایش ایمیج ایجاد شده هم می‌تونیم از دستور زیر استفاده کنیم:docker imagesاجرای پروژهحالا که ایمیج ایجاد شده، زمان این رسیده که با ایجاد یک container پروژه رو اجرا کنیم، برای این کار از دستور زیر استفاده می کنیم:docker run backendنکته: backend اسم ایمیجی‌ هست که زمان ایجاد انتخاب کردیم با استفاده از t-بعد از اجرا این دستور پروژه باید با موفقت اجرا شده باشه و تمام :)تبریک می‌گم، شما پروژه رو با موفقیت Dockerize و درنهایت اجرا کردید :)ناگفته هااول اینکه، دستوراتی که تو داکرفایل استفاده میشن، خیلی بیشتر از دستوراتی هستن که من استفاده کردم برای این پروژه، برای همین توصیه می‌‌کنم حتما داکیومنت داکر رو مرجع قرار بدید و دستورات دیگه رو یاد بگیرید.نکته بعدی اینکه سناریویی که من برای ایجاد این Dockerfile استفاده کردم بهمینه نیس و خیلی از best practice ها رو توش رعایت نکردم بخاطر پیچیده نشدن فرایند، ولی توی کامنت بگید بنظرتون کجا میتونست بهتر باشه؟ چه best practiceهایی رو رعایت نکردم؟ می‌تونید از ریپوزیتوری پروژه که داکرفایل‌های دیگه هم توش هستن تقلب کنید ?تو نوشته بعدی راجع به این بهینه سازی و best practice ها صحبت خواهیم کرد، پس اگه براتون سواله یا میخوایین ببینین درست حدس زدید یا نه نوشته بعدی رو هم دنبال کنید.در پایان حتما کامنت بزارین و نظرتون رو بگید، خیلی بهم کمک می‌کنه، بگید مثلا این کنجکاوی‌ها رو کجاها بیشتر بریم توش. اگه نوشته رو دوست داشتید با دوستان به اشتراک بزارید که هم بهشون کمک کنه و هم انرژی بشه برای من که ادامه بدم :)و اینکه میتونید منو با آی‌دی mehdi_zarepour تو توییتر پیدا کنید، نوشته‌های جدید رو اونجا توییت میکنم. فعلا نوشته‌هام راجع به داکر خواهد بود.</description>
                <category>Mehdi Zarepour</category>
                <author>Mehdi Zarepour</author>
                <pubDate>Wed, 09 Aug 2023 10:42:21 +0330</pubDate>
            </item>
                    <item>
                <title>ایمیج‌های داکر چطور ایجاد میشن؟ نقش لایه‌های داکر چیه؟</title>
                <link>https://virgool.io/@mehdi.zarepour/%D8%A7%DB%8C%D9%85%DB%8C%D8%AC-%D9%87%D8%A7%DB%8C-%D8%AF%D8%A7%DA%A9%D8%B1-%DA%86%D8%B7%D9%88%D8%B1-%D8%A7%DB%8C%D8%AC%D8%A7%D8%AF-%D9%85%DB%8C%D8%B4%D9%86-%D9%86%D9%82%D8%B4-%D9%84%D8%A7%DB%8C%D9%87-%D9%87%D8%A7%DB%8C-%D8%AF%D8%A7%DA%A9%D8%B1-%DA%86%DB%8C%D9%87-inuhsrfdhtjg</link>
                <description>تو این نوشته قراره به سوال جواب بدیم که داکر چطوری ایمیج‌ها رو میسازه و مدیریت می‌کنه و همینطور با مفاهمین Dockerfile و Docker Layers بیشتر آشنا می‌شیم.قبل از اینکه بریم سراغ نحوه ایجاد ایمیج‌ها توسط داکر، بیاییم یکم راجع به Dockerfile صحبت کنیم.داکرفایل Dockerfileداکرفایل(Dockerfile) در واقع اسکریپتی هست که شامل همه‌ی دستورات و اطلاعات مورد نیاز داکر برای ایجاد image رو تعریف می‌کنه.اسکریپت Dockerfile معمولا با دستورات مهم‌تر مثل FROM (که مشخص می‌کنه ‌base ایمیج ما چی هست، مثلا سیستم‌عاملی که میخواییم برای ایمیج داشته باشیم) شروع میشه و با با دستور RUN (که می‌تونیم باهاش هر دستوری رو اجرا کنیم)، CMD &#40;که می‌تونیم باهاش دستور پیشفرض اجرایی کانتینر رو مشخص کنیم&#41; و دستورات دیگه مثل LABEL، EXPOSE، ENV،ADD تکمیل و ایجاد میشه.‌نکته: تو این نوشته دستورات داکرفایل مورد بحث نیس و تو نوشته‌ای دیگه راجع بهشون صحبت می‌کنیم و اینکه نیاز نیست این دستورات رو بلد باشید تا این نوشته رو متوجه بشید.خب با این تعریف بیاییم یه داکرفایل ساده با محتوای زیر ایجاد کنیم و راجع به این صحبت کنیم که داکر چطوری از روی این داکرفایل ایمیج رو ایجاد میکنه:FROM ubuntu:20.04
LABEL maintainer=&amp;quotMehdi Zarepour&amp;quot
RUN apt-get update &amp;&amp; apt-get install -y curl
WORKDIR /app
COPY . /app
CMD [&amp;quotecho&amp;quot, &amp;quotHello Docker&amp;quot]بیاییم این دستورات رو یکی یکی بررسی کنیم و ببینیم داکر با استفاده از این دستورات چطوری ایمیج رو ایجاد می کنه:۱. دستور FROM ubuntu:20.04: دستور FROM به داکر میگه که قراره Base ایمیجمون چی باشه، که اینجا گفتیم میخواییم ubuntu باشه (معمولا اولین دستور داکرفایل FROM هست). پس تو این مرحله ایمیج‌مون به شکل زیر میشه، یعنی سیستم عامل به ایمیج اضافه میشه:۲.دستور &quot;LABEL maintainer=&quot;Mehdi Zarepour: دستور LABEL یه متادیتا به اسم maintainer و مقدار Mehdi Zarepour به ایمیج اضافه میکنه (LABEL ساختار key-value داره، پس مقدار key و value می تونه هرچیزی که دوست دارید باشه) این دستور کار خاصی نمی کنه، صرفا داره مشخص می کنه ایجاد کننده و نگهدارنده این ایمیج کیه. تو این مرحله ایمیج‌مون به شکل زیر میشه، یعنی نگهدارنده یه جایی تو فایل ایمیج ذخیره میشه:۳. دستور RUN apt-get update &amp;&amp; apt-get install -y curl: دستور RUN، هر دستوری که جلوش بیاد رو اجرا میکنه که تو مثال ما داره curl رو روی Ubuntu نصب میکنه، پس curl به Ubuntuای که توی فایل ایمیج داشتیم اضافه میشه:۴. دستور WORKDIR /app: دستور WORKDIR دایرکتوری جاری رو تغییر میده به آدرسی که جلوش مشخص کردیم یعنی app/ (می تونیم بگیم این دستور با cd /app یکی هستن، با این تفاوت که وقتی از WORKDIR استفاده می کنیم، اگه دایرکتوری وجود نداشته باشه ایجادش میکنه ولی cd خطا میده اگه app/ وجود نداشته باشه). پس تو این مرحله دایرکتوری app/ به ایمیج اضافه میشه:۵. دستور COPY . /app:  دستور COPY فایل های برنامه یا نرم‌افزار ما رو از دایرکتوری جاری سیستم لوکالمون به ایمیج و دایرکتوری app/ اضافه می‌کنه.۶. دستور CMD [&quot;echo&quot;, &quot;Hello Docker&quot;]: دستور CMD مشخص می‌کنه دستور پیشفرض اجرایی برای کانتینری که از روی این ایمیج ساخته میشه چی هست.خب وقتی همه‌ی دستورات توی داکرفایل توسط داکر خونده شد، این میشه نسخه نهایی ایمیجی که از روش می‌سازه. ساده بود نه؟ :)باید بگم که این تعریف اشتباه‌ست یا حداقل کامل نیست! داکر برای ایجاد ایمیج تنها یک فایل مثلا با فرمت ISO نمیسازه که شامل دپندنسی‌هایی که تو Dockerfile مشخص کردیم باشه، بلکه به ازای هر کدام از دستوراتی که ما توی Dockerfile تعریف می‌کنیم اصطلاحا یک «لایه Docker Layer» ایجاد می کنه. خب پس بریم ببینم این لایه ها چی هستن و چطوری داکر باهاشون ایمیج ها رو ایجاد می کنه.لایه‌های داکر  Docker Layerایمیج‌های داکر از چندیدن لایه تشکیل میشن که این لایه ها مجموعه ای از فایل‌ها و یا دایرکتوری‌های read-only هستن که بصورت stack روی هم قرار می گیرن. هر لایه از روی دستورات نوشته شده تو Dockerfile ایجاد میشه، یعنی از روی هر کدوم از این دستورات مثل FROM، RUN، COPY و غیره یک لایه ایجاد میشه که هر کدوم از این لایه ها یه تغییری روی image میزارن و درنهایت image نهایی ساخته میشه، هر کدوم از این لایه ها به صورت کلی دو نوع تغییر روی image میزارن:یه فایل یا دایرکتوری به فایل سیستم اضافه یا حذف می کننمتادیتا یا اطلاعات دیگه به ایمیج اضافه می کنن تا مشخص کنن  image چه خصوصیاتی باید داشته باشهبرای درک بهتر به تصویر زیر نگاه کنید:بیاییم یکم با جزییات بیشتر به هر کدوم لاز این لایه ها نگاه کنیم و ببینیم هر کدوم از این لایه ها چیکار می کنن:لایه اول: داره تمام فایل ها و دایرکتوری های سیستم عامل Ubuntu رو به image اضافه می‌کنه، پس بعد از این لایه ما به Ubuntu و قابلیت‌هاش دسترسی داریم.لایه دوم: این اطلاعات که نگهدارنده این ایمیج کی هست رو به متادیتای image اضافه می‌کنه (تاثیری روی فایل‌سیستم نداره).لایه سوم: فایل ها و دایرکتوری‌های مربوط به cURL رو به مثلا usr/bin/ که در Ubuntu هست اضافه می‌کنه.لایه چهارم: دایرکتوری app/ رو ایجاد میکنه.لایه پنجم: فایل‌های نرم‌افزارمون یا برنامه‌مون رو از سیستم لوکال کپی میکنه و در app/ که قبلا ایجاد شده قرار میدهلایه ششم: مشخص میکنه دستور پیشفرضی که بعد از اجرای container باید اجرا بشه چیه که اینجا echo Hello Docker هست.پس مجموع این لایه ها روی هم در نهایت image رو بوجود میارن، حالا سوال اینجاس، داکر چطوری این لایه ها رو ذخیره می‌کنه؟ و چطوری یکپارچه شون میکنه و از روشون یک image ایجاد میکنه؟ اول بریم سراغ نحوه ذخیره سازی سازی این لایه‌ها.نحوه ذخیره‌سازی لایه ها توسط داکرگفتیم هر کدوم از لایه‌های داکر یه فایل یا دایرکتوری read-only هستن، یعنی بعد از ایجاد شدن دیگه قابل تغییر نیستن. داکر این فایل ها و دایرکتوری ها رو توی دایرکتوری مشخصی ذخیره و مدیریت میکنه، بزاریم الکی پیچیده‌ش نکنیم و فرض کنیم داکر این لایه‌ها رو در دایرکتوری /var/lib/docker/ ذخیره میکنه./var/lib/docker/
│   ├── &lt;layer1&gt;/ (Ubuntu 20.04 files)
│   ├   └── /usr/
│   ├   └── /etc/
│   ├   └── /lib/
│   ├── &lt;layer2&gt;/ (Maintainer label)
│   ├── &lt;layer3&gt;/ (curl installation)
│   ├   └── /usr/bin/curl
│   ├── &lt;layer4&gt;/(/app directory)
│   ├   └── /app
│   ├── &lt;layer5&gt;/ (Copied files)
│   ├   └── /app/index.js
│   └── &lt;layer6&gt;/(CMD instruction)نکته: نموداری که بالا کشیدم صرفا برای شبیه‌سازی هست و در واقع ذخیره‌سازی این فایل‌ها و دایرکتوری‌ها به شکل پیچیده‌تری پیاده و مدیریت میشه و واقعا نیازی به رفتن به جزییات بیشتر نیست.همونطور که شکل بالا نشون میده، داکر میاد تغییرات لایه‌ها رو توی دایرکتوری‌های read-only ذخیره میکنه، مثلا برای لایه اول که شامل Ubuntu میشه، همه فایل ها و دایرکتوری های Ubuntu رو توی یه دایرکتوری مثلا به اسم layer1 ذخیره می‌کنه و همین کار رو برای لایه‌های دیگه هم میکنه، مثلا فایل‌ها و دایرکتوری‌های cURL رو هم توی یه دایرکتوری به اسم layer3 ذخیره میکنه.پس هر لایه یک دایرکتوری read-only هست که توسط داکر ایجاد و نگهداری میشه که شامل تغییراتی هست که هر لایه قراره روی image ایجاد میکنه.خب حالا بریم سراغ سوال دوم که داکر چطوری از روی این لایه‌ها (دایرکتوری‌های read-only) image رو ایجاد میکنه.نحوه ایجاد Image توسط Dockerخب با وجود این لایه‌ها بنظر داکر کار سختی نداره! فقط کافیه‌ که این فایل ها و دایرکتوری‌ها رو بیاره کنار هم و تو یک سیستم فایل مشترک قرار بده‌، یعنی:/my-image
│   └── /usr/
│   ├   └── /usr/bin/curl
│   └── /etc/
│   └── /lib/
│   └── /app
│   ├   └── /app/index.jsاگه توجه کنید، همه‌ی دایرکتوری‌ها با هم merge شدن و یک سیستم‌فایل واحد متشکل از همه‌ی نیازمندی‌هایی که تو Dockerfile ایجاد کردیم هست، یعنی ما Ubuntu رو با همه‌ی فایل‌ها و تنظیماتش داریم، curl هم به دایرکتوری bin اضافه شده و همینطور کد برنامه‌مون تو دایرکتوری app قرار داده شده، و تمام! اینطوری برنامه‌ ما کنار همه‌ی دپندنسی‌هاش در یک پکیج به اسم Docker Image بسته‌بندی شده.از اونجایی که ما خیلی کنجکاویم، این سوال پیش میاد که داکر چطوری این دایرکتوری‌ها رو با هم merge میکنه و یک سیستم‌فایل واحد برای ایمیج ایجاد میکنه؟ ?داکر و Union File System &#40;UnionFS&#41;داکر برای ایجاد این فایل‌سیستم واحد از UnionFS استفاده می‌کنه، UnionFS نوعی از فایل سیستم هست که این اجازه رو به ما میده که چند سیستم فایل رو با هم merge کنیم و یک سیستم‌فایل واحد ایجاد کنیم. به مثال زیر نگاه کنید تا ببینیم UnionFS چطوری این کارو میکنه:فرض کنیم ما سه تا دایرکتوری با نام‌های A, B و C داریم که محتوایت توشون به شکل زیره:A/
└── file1
B/
└── file2
C/
└── file3با استفاده از UnionFS ما میتونیم این دایرکتوری‌ها رو با هم مرج کنیم و یک دایرکتوری واحد به شکل زیر ایجاد کنیم:Union(A, B, C)/
├── file1
├── file2
└── file3تو این حالت file1 از دایرکتوری A اومده، file2 از دایرکتوری B اومده و file3 از دایرکتوری C اومده و در نهایت روی هم یک دایرکتوری واحد ایجاد کردن. تو دنیای داکر هر کدوم از این دایرکتوری ها (A, B, C) همون لایه‌هایی هستن که داکر از روی Dockerfile ایجاد می‌کنه و در نهایت از UnionFS استفاده میکنه و یک فایل سیسم واحد در اختیار Image قرار میده.نکته: اگه فایل مشترکی توی هر کدوم از این دایرکتوری‌ها (یا همون لایه‌ها) وجود داشته باشه توسط UnionFS مرج میشه و محتویات آخرین دایرکتوری نگهداری میشه. مثلا اگه یه دایرکتوری D هم داشته باشیم که file1 توش باشه، UnionFS محتوایات فایلی که در آخرین دایرکتوری یعنی D قرار گرفته شده رو جایگزین فایلی می کنه که در دایرکتوری A بود. پس حواستون باشه که این اتفاق برای محتوایات لایه‌هایی که داکر ایجاد میکنه هم میافته و لایه‌های بالاتر محتویات لایه‌های پایین تر رو override میکنن.کنجکاوی: داکر معمولا از overlay2 به عنوان UnionFS برای مرج کردن لایه‌ها یا دایرکتوری ها استفاده میکنه.پس مراحل ایجاد Docker Image به شکل زیر میشه:لایه کانتینر Container Layerگفتیم این لایه‌ها که Image از روشون ساخته میشه read-only هستن، احتمالا این اتفاق افتاده براتون که از روی یه Image یک Container ایجادکنید و مقدار یه فایلی رو تغییر بدید و وقتی دوباره یه Container جدید از رو Image بسازید میبینید که تغییرات reset شدن و دیگه نیستن! این قضیه ثابت میکنه که ایمیج read-only هست و ما نمی‌تونیم تغییری توش ایجاد کنیم، چرا؟ چون لایه‌های که ایمیج از روشون ساخته میشه read-only هستن.خب این ته ماجرا نیس! چون ما نیاز داریم تو یه Container تغییری توی Image ایجاد کنیم، مثلا یه فایل جدید بسازیم و یا محتویات یه فایلی رو تغییر بدیم، راه حلی که داکر برای این مسئله داره اینه که زمانی که میخواییم یه کانتینر رو run کنیم، یه لایه جدید به اسم لایه container روی همه‌ی لایه‌هایی که برای ایمیج داریم اضافه میکنه که فرقش اینه که توی این لایه ما دسترسی write هم داریم پس میتونیم توی این لایه تغییراتمون رو اعمال کنیم.اگه یادتون باشه گفتیم توی UnionFS لایه‌های بالایی میتونن لایه‌های پایینی رو override کنن، پس عملا ما بدون اینکه واقعا تغییری روی فایل‌سیسم Imageها ایجاد کنیم، با استفاده از لایه کانتینر overrideشون می‌کنیم و تغییراتی که نیاز داریم رو اعمال میکنیم. به شکل زیر نگاه کنید:Container Filesystem
├── Read-write layer (specific to this container)
│   ├── &lt;layerN&gt;
│   ├── ...
│   ├── &lt;layer2&gt;
│   ├── &lt;layer2&gt;
│   └── &lt;layer1&gt;
└── Read-only layers (from the image)دوست دارم خیلی بیشتر راجع به Layering تو Docker و مزایاش بگم، مثلا چطوری باعث میشه تو مصرف هارد صرفه‌جویی بشه یا چطوری داکر از لایه‌ها برای cache کردن استفاده میکنه. ولی بنظر میاد نوشته طولانی بشه پس تا همینجا تمومش می‌کنم و اگه عمری بود تو نوشته‌های بعدی راجع بهشون حرف میزنیم.حتما کامنت بزارین و نظرتون رو بگید، خیلی بهم کمک می‌کنه، بگید مثلا این کنجکاوی‌ها رو کجاها بیشتر بریم توش.در پایان اینکه اگه نوشته رو دوست داشتید با دوستان به اشتراک بزارید که هم بهشون کمک کنه و هم انرژی بشه برای من که ادامه بدم :)و اینکه میتونید منو با آی‌دی mehdi_zarepour  تو توییتر پیدا کنید، نوشته‌های جدید رو اونجا توییت میکنم. فعلا نوشته‌هام راجع به داکر خواهد بود.</description>
                <category>Mehdi Zarepour</category>
                <author>Mehdi Zarepour</author>
                <pubDate>Sun, 30 Jul 2023 20:19:25 +0330</pubDate>
            </item>
                    <item>
                <title>چرا به داکر نیاز داریم؟</title>
                <link>https://virgool.io/@mehdi.zarepour/%DA%86%D8%B1%D8%A7-%D8%A8%D9%87-%D8%AF%D8%A7%DA%A9%D8%B1-%D9%86%DB%8C%D8%A7%D8%B2-%D8%AF%D8%A7%D8%B1%DB%8C%D9%85-lgbpj7vzrxhe</link>
                <description>پیشگفتارقراره تو این نوشته راجع به این صحبت کنیم که مشکل چی بوده که تکنولوژی مثل داکر بوجود اومده و چرا ما نیاز داریم ازش استفاده کنیم. شاید خیلی از ماها از داکر استفاده می کنیم بدون اینکه جواب این «چرا؟» رو کامل بدونیم. برای اینکه بتونیم درک عمیق تری از تکنولوژی ها داشته باشیم بهتره اول بریم سراغ اینکه بفهمیم مشکل چی بوده که یه همچین تکنولوژی بوجود اومده؟ اونوقت می تونیم درک بهتری از مفاهیم و قابلیت های اون تکنولوژی داشته باشیم و بهتر ازشون استفاده کنیم.مقدمهدلیل استفاده از داکر زیاده ولی ما می خواییم راجع به قابل لمس ترینش حرف بزنیم تا برای همه با هر سطحی قابل درک باشه. خب بیایین با این مثال شروع کنیم که شما یک برنامه کامپیوتری رو توسعه دادید و می‌خوایین اون رو تو یک محیط متفاوت، مثل سرور production اجرا کنید. با این حال، همیشه احتمال وجود یه سری مشکلات و عدم سازگاری در محیط‌های مختلف هست. منظورم اینه که نرم افزارمون روی سیستم یا سرور دیگه درست کار نکنه و مجبور باشیم روی این سیستم مقصد تغییراتی ایجاد کنم (مثل نصب کردن یه سری library). به عبارت دیگه، این برنامه یا نرم افزار که نوشتیم قابل حمل یا portable نیست.مشکل چی بود؟احتمالا براتون اتفاق افتاده که موقع نصب یه نرم افزار به ارور های مختلف خوردین و مجبور شدین یه سری چیزای دیگه رو روی سیستم تون نصب کنین تا بتونین در نهایت نرم‌افزار رو اجرا کنین، درسته؟ یه نگاه به تصویر زیر بندازین که چرخه نصب یه نرم‌افزار رو نشون میده:این تصویر نشون میده ما چه فرایندی رو طی می کنیم تا یه نرم‌افزار رو روی سیستم‌مون اجرا یا نصب کنیم. بدین صورت پیش میاد که وقتی یه نرم‌افزاری رو اجرا می کنیم به یک خطایی می خوریم که مثلا پایتون۳ روی سیستم نصب نیست، یه خطایی مثل این:Error: Python 3 required to run this program.برای حلش خب اگه ندونیم پایتون چیه شروع می کنیم تو گوگل سرچ کردن راجع به ارور (Throubleshoot Issue) بعد پایتون رو نصب می کنیم و دوباره سعی می کنیم برنامه رو اجرا کنیم (Rerun Program)، بعد اجرا کردن دوباره بازم این احتمال وجود داره که به یه ارور جدید بخوریم (New Error) و مجبور میشیم دوباره بریم سراغ اینکه این مشکل رو هم حل کنیم (Throubleshoot Issue) و دوباره برنامه رو اجرا کنیم به امید اینکه اینبار درست اجرا بشه! این چرخه ممکنه چندین بار تکرار بشه تا ما نهایتا بتونیم برنامه رو اجرا کنیم که میتونه خیلی زمان بر و سخت هم باشه...بعضی وقتا این مشکلات پیچیده تر از صرفا نصب کردن پایتون می‌تونن باشن، یا حتی قابل حل شدن هم نباشن، مثلا نرم افزار از یه نسخه خاصی از یک کتابخونه استفاده کنه که شما دسترسی بهش ندارین، یا بدتر از اون اصلا نرم‌افزار با نسخه سیستم‌عامل شما مشکل داشته باشه! که به طور خیلی کلی میشه گفت این نرم افزار قابل حمل نیس! خب حالا بیاییم راجع به این صحبت کنیم که به چه نرم‌افزاری قابل حمل می‌گن؟نرم افزار قابل حمل (Portable)به چه نرم افزاری نرم افزار قابل حمل میگن؟ بطور کلی به نرم افزاری قابل حمل میگیم که خودش به همراه همه‌ی dependencyهاش یه جا پکیج شده باشه و بتونه رو هر ماشین مقصدی صرفه نظر از اینکه چه کانفیگی داره (چه کتابخونه ها و نرم افزارهایی روش نصبه و...) اجرا بشه. خب حالا که به یه تعریفی از نرم افزار قابل حمل رسیدیم، بگیم منظور از dependencyهای یک نرم افزار چیه؟دپندنسی‌ نرم افزار (Dependency)بیاییم پیچیده‌ش نکنیم و یه تعریف کلی از dependencyها داشته باشیم. به طور کلی به هر چیزی که یک نرم افزار برای اجرا یا نصب شدن روی یک ماشین نیاز داره اصطلاحا بهش می گیم dependency اون نرم‌افزار. این dependencyها رو هم می تونیم به دو دسته کلی تقسیم کنیم:زمان اجرا Runtime Dependenciesزمان کامپایل Compile-time dependenciesهمونطور که از اسم این dependencyها مشخصه، Runtime Dependencies به دپندنسی هایی گفته میشه که نرم افزار که یک نرم‌افزار زمان اجرا بهشون نیاز داره مثل:LibrariesFrameworksDatabase DriversRuntime Environmentsدپندنسی‌های زمان کامپایل (Compile-time dependencies) هم اشاره به نیازمندی هایی داره که یک نرم افزار برای کامپایل شدن بهشون نیاز داره، مثل:Platform-Specific SDKs (Android SDK, iOS SDK)Library Dependencies (OpenSSL, SQLite)Development Frameworksنکته: اگه با این مواردی که مثال زدم آشنا نیستید مهم نیست، چون موضوع بحث نیستن، تا همینجا کافی که دپندنسی‌ها به این دو دسته کلی می تونن تقسیم بشن و نرم افزار برای اینکه بتونه درست روی ماشین مقصد کار کنه بهشون نیاز داره.پس وقتی میگیم یه نرم‌افزار قابل‌حمل هست یعنی این dependencyها در کنار خود نرم افزار در یک پکیج قرار گرفتن و نیازی نیست که ماشین مقصد از قبل این دپندنسی‌ها رو تو خودش داشته باشه، و ما صرفا کافیه که این پکیج رو کپی کنیم روی ماشین مقصد و برنامه رو اجرا کنیم.اینطوری دیگه نیازی نیس نگران این باشیم که آیا dependencyهای نرم‌افزار روی ماشین مقصد نصب شده یا نه و می تونیم مطعمن باشیم که برنامه بدون مشکل اجرا میشه. نقش داکر در ایجاد نرم‌افزارهای قابل حملتا اینجا راجع به اینکه نرم‌افزار قابل‌حمل چیه صحبت کردیم و متوجه شدیم که نرم‌افزار برای اجرا شدن نیازه داره dependencyهاش روی ماشین مقصد فراهم شده باشه، که گفتیم برای قابل‌حمل کردن نرم‌افزار باید نرم‌افزار رو به همراه دپندنسی‌هاش در یک پکیج قرار بدیم و برای اجرا به ماشین مقصد منتقل کنیم. خب این همون مسئله‌ای هست که ما نیاز به یه ابزار یا راه‌حلی داریم که بتونه این پکیج رو ایجاد کنه.پس برای این منظور یعنی قابل‌حمل کردن نرم‌افزارها تکنولوژی‌هایی مثل داکر ایجاد شدند تا بتونیم به کمک‌شون نرم‌افزارهای قابل‌حمل ایجاد کنیم. داکر از دو مفهوم به نام‌های Docker Image برای ایجاد پکیج نرم‌افزار و Container برای اجرای نرم‌افزار در ماشین مقصد استفاده می کنه که در ادامه راجع بهشون صحبت می کنیم.داکر ایمیج Docker Imageداکر ایمیج (Docker Image)، در واقع یک فایل آرشیو شده و قابل اجراست که شامل همه‌ی دپندنسی‌های لازم برای اجرای یک برنامه یا نرم‌افزار هست. یعنی شامل خود کد برنامه، کتابخانه‌های مورد نیاز و Environment Variablesها هست.نکته مهم اینکه حتی سیستم عامل هم به عنوان یکی از دپندنسی های نرم‌افزار به ایمیج داکر اضافه میشه، چون می دونیم که بهرحال هر نرم‌افزاری باید در بستر یه سیستم‌عامل اجرا بشه تا بتونه از منابع سیستم استفاده کنه. پس وقتی ما برنامه یا نرم‌افزارمون رو توی یک ایمیج داکر بسته‌بندی می‌کنیم حتی مهم نیس که سیستم‌عامل ماشین مقصد چیه چون ما حتی سیستم‌عامل مورد نیاز نرم‌افزارمون رو کنار خود نرم‌افزارمون بسته‌بندی کردیم.تصویر زیر یه نمونه از ایمیج داکر رو نشون میده که دپندنسی‌های برنامه، شامل سیستم‌عامل، NodeJS و خود برنامه س.خب تا اینجا گفتیم Docker Image یک فایله که شامل نرم‌افزار و دپندسی‌هاش میشه، حالا سوال اینجاست که داکر از کجا می دونه دپندنسی‌های این نرم‌افزار چیه که توی Image قرارشون بده؟ اینجاست که پای Dockerfile به وسط میاد.داکرفایل Dockerfileجواب این سوال اینه‌ که ما به عنوان سازنده این نرم‌افزار با استفاده از فایلی به نام Dockerfile مشخص می‌کنیم که دپندنسی‌های این نرم‌افزار چیه و چه چیزهایی باید در Docker Image بسته بندی بشه. مثلاً، ممکن است تعیین کنیم که چه کتابخانه‌هایی نیازه، یا کدام فایل باید به عنوان فایل اجرایی نرم‌افزار استفاده بشه، و غیره.حلا به عنوان مثال بیاییم برای مثالی که تو تصویر بالا آورده شده یک ایمیج داکر ایجاد کنیم. گفتیم برای ایجاد Docker Image باید تو Dockerfile مشخص کنیم که این Image شامل چه چیزهایی میشه، از اونجایی که تو مثال بالا ما یه برنامه NodeJS داریم Image باید شامل:سیستم عامل (که اینجا Alpine linux هست)نیاز به NodeJS دارمو خود برنامه که تو فایل index.js نوشته شدهبنابراین Dockerfile به صورت زیر باید تعریف بشه (برای ایجاد داکرفایل یه فایل با کمک text editorتون مثل vscode با نام Dockerfile بدون پسوند ایجاد کنید و کدهای زیر رو توش بنویسید و زخیره کنید):در این فایل تو خط اول مشخص کردیم میخواییم برنامه‌مون رو بستر سیستم‌عامل alpine اجرا بشه و با استفاده از دستور RUN دپندنسی برنامه که nodejs هست رو نصب کردیم، با استفاده از دستور COPY فایل‌های خود برنامه‌مون رو توی ایمیج کپی کردیم و در نهایت با استفاده از دستور CMD مشخص کردیم برنامه‌مون از کجا و چطوری باید اجرا بشه.نکته: توضیحاتی که راجع به دستورات داکرفایل دادم خیلی کلی هستن چون موضوع بحث این نوشته نیستن، ولی تو نوشته بعدی به طور مفصل راجع بهشون حرف میزنیم و به جزيیات می پردازیم.خود برنامه هم تو فایل index.js نوشته شده که صرفا فقط یه چیزی روی کنسل چاپ می کنه:خب، اینطوری مشخص کردیم که Docker Image یا پکیج نرم‌افزارمون میخواییم شامل چه چیزهایی باشه. حالا وقت اینه که ایمیج داکرمون رو ایجاد کنیم، برای این دستور کافیه توی ترمینال بنویسیم:docker build . -t my-programهمونطور که حدس زدید، این دستور یه ایمیج داکر با نام my-program ایجاد کرده که شامل چیزهایی هست که تو Dockerfile مشخص کردیم. برای اینکار از دستور docker build استفاده کردیم که خیلی کوتاه شامل آپشن های زیر بود:دستور build:docker build .که در اینجا .  (dot) مشخص می‌کنه که Dockerfile کجاست و dot به معنی current directory هست (یعنی همونایی که داریم دستور رو اجرا میکنیم).آپشن t--t my-programکه باهاش مشخص می کنیم اسم image که میخواییم بسازیم چیه.برای اینکه مطعمن بشیم که imageمون ساخته شده یا نه، می‌تونیم از دستور زیر استفاده کنیم تا لیست همه‌ی ایمیج های ایجاد شده رو ببینیم:docker imagesهمونطور که تو عکس مشخصه یه ایمیج جدید با نام my-program ایجاد شده.نکته: بیشتر از این نمیخواییم راجع به دستورات docker اینجا صحبت کنیم چون از موضوع صحبت خارج میشه، و بعدا تو یه نوشته دیگه با جزییات بیشتر راجع به این دستورات صحبت میکنیم.خب تا اینجا ما برنامه‌مون رو توی docker image بسته‌بندی کردیم و حالا وقت اینه که برنامه مون رو اجرا کنیم، برای اینکار داکر از مفهومی به نام container استفاده می‌کنه که در ادامه راجع بهش حرف می زنیم.داکر کانتینر Docker Containerبطور خیلی کلی کانتینر یه نمونه اجرا شده از امیج داکر (Docker Image) یا حتی می تونیم بگیم یه process در حال اجراس که ویژگی منحصربه‌فردش اینه که کاملا ایزوله شدس. بیاییم نریم تو جزییات و پیچیدش نکنیم و اینطوری درنظر بگیریم که وقتی میگیم کانتینر یعنی داریم راجع به یه پروسس در حال اجرا که ایزوله شدس صحبت می کنیم.خب تا اینجا ایمیج داکر رو ساختیم و الان وقت اینه که با ایجاد یه container اجراش کنیم، برای این کار از دستور زیر استفاده می‌کنیم:docker run my-programهمینطور که می‌بینید برنامه با موفقیت اجرا شده و Hello رو در کنسول چاپ کرد.اگه میخوایین بیشتر راجع به کانتینرها بدونین، پیشنهاد میکنم این نوشته (پشت پرده کانتینرهای داکر) رو بخونید، تو این نوشته توضیح دادم که داکر چطوری با استفاده از کانتینرها، برنامه(ایمیج) رو بصورت ایزوله شده اجرا میکنه.خب اگه توجه کرده باشید، ما ایمیج داکر رو روی یک سیستم ایجاد و روی همون سیستم اجراش کردیم ولی گفتیم هدف اینه که با ایجاد ایمیج داکر برنامه های قابل حمل ایجاد کنیم، حالا سوال اینجاس که چطوری میتونیم فایل ایمیج رو به ماشین مقصد منتقل و اجرا کنیم؟برای اینکه این نوشته طولانی نشه، این موضوع رو توی نوشته بعدی بررسی می‌کنیم که بتونیم هم با جزيیات بیشتری صحبت و هم این نوشته طولانی نشه.توی این نوشته راجع به چرایی نیاز و استفاده از داکر صحبت کردیم، تو نوشته های بعدی راجع به اینکه اصلا Docker چی هست صحبت می کنیم و وارد جزییات بیشتری از نحوه کار و استفاده از دستورات داکر می‌شیم.سخن آخر اینکه، میخوام سعی کنم منابع مفیدی به زبان فارسی تولید کنم تا هم خودم بیشتر یاد بگیرم و هم کسانی که دسترسی به منابع اینگلیسی ندارن و یا با زبان فارسی بهتر یاد میگیرن کمک کنم، پس اگه نوشته‌های منو دوست داشتین برای دوستاتون هم بفرستین که هم اونا استفاده کنن و هم انرژی میشه برای من که ادامه بدم :)اگه توییتر دارید می تونید منو با آی‌دی mehdi_zarepour پیدا کنید، نوشته‌های جدید رو اونجا توییت میکنم. فعلا نوشته‌هام راجع به داکر خواهد بود.</description>
                <category>Mehdi Zarepour</category>
                <author>Mehdi Zarepour</author>
                <pubDate>Thu, 27 Jul 2023 23:37:25 +0330</pubDate>
            </item>
                    <item>
                <title>پشت پرده کانتینرهای داکر</title>
                <link>https://virgool.io/@mehdi.zarepour/%D9%BE%D8%B4%D8%AA-%D9%BE%D8%B1%D8%AF%D9%87-%DA%A9%D8%A7%D9%86%D8%AA%DB%8C%D9%86%D8%B1%D9%87%D8%A7%DB%8C-%D8%AF%D8%A7%DA%A9%D8%B1-bwbmfpjegubt</link>
                <description>همیشه وقتی یه چیز جدید می خونم تا نفهمم اون پشت مشتا چه اتفاقی داره میافته احساس می کنم چیزی یادم نگرفتم، یا یه چیزی هست هنوز نمیدونم! خلاصه اینقدر قلقلکم می ده که برم ببینم واقعا چه اتفاقی داره پشت پرده میافته.مدتی بود که از داکر برای کانتینرایز (containerize) کردن اپلیکشن ها استفاده می کردم و درک کلی و کافی ازش داشتم ولی خب این حس که یه چیزی هست که نمی دونم وجود داشت! برای همین رفتم سراغ اینکه یکم عمیق تر شم تا ببینم پشت پرده چه اتفاقی داره میافته!تو این مقاله هم می خوام یه خلاصه ای از اتفاقاتی که داره میافته رو براتون بگم، بدون استفاده از مفاهیم قلمبه سلمبه، چون هم میخوام برای همه قابل درک باشه با هر سطحی از دانش و هم اینکه واقعا ته نداره اگه بخوای تو دیتیل هر چیزی بری!کانیتر چیست؟خب بیایین با این سوال که کانتینر چیه (که هر کسی که با داکر کار کرده یه جوابی براش داره) شروع کنیم. بطور خیلی کلی کانتینر یه نمونه اجرا شده از امیج داکر (Docker Image) یا حتی می تونیم بگیم یه process در حال اجراس که ویژگی منحصربه‌فردش اینه که کاملا ایزوله شدس و این یکی از دلایل ایجاد و استفاده از Docker هست که بتونیم اپلیکشن هامون رو بصورت ایزوله به همراه دپندنسی هاش (Dependency) روی ماشین مقصد بدون مشکل اجرا کنیم.بیاییم نریم تو جزییات و پیچیدش نکنیم و اینطوری درنظر بگیریم که وقتی میگیم کانتینر یعنی داریم راجع به یه پروسس در حال اجرا که ایزوله شدس صحبت می کنیم (جلو تر وقتی با یه سری از مفاهیم آشنا شدیم بهتر می تونیم کانتینر رو تعریف کنیم)، خب چیزی که من میخواستم برم دنبال جوابش هم همین نکته‌س! یعنی چی ایزوله؟ چطوری ایزوله میشه؟ کی این کارو می کنه؟ داکر؟اینا سوالایی هستن که میخوام راجع بهشون حرف بزنم.پروسس ایزوله شدهخب بیاییم اول تکلیف اینو مشخص کنیم که پروسس ایزوله شده ینی چی؟ برای اینکه درک بهتری داشته باشیم بیاییم به این نمودار نگاه کنیم:توی این نمودار ۳تا process رو داریم که از طریق کرنل(Kernel) سیستم عامل به منابع سخت افزاری سیستم دسترسی پیدا می کنن، فرض کنیم قراره اینا توی یه فایلی توی هارددیسک چیزی بنویسن یا بخونن و این فایل هم تو مسیر tmp/file/ ذخیره شده.توی این حالت هر ۳ پروسس دارن یک فایل رو تغییر میدن که اگه هرکدوم از این پروسس ها بخوان مقدار این فایل رو بخونن نمی تونن انتظار داشته باشن که مقدارش همون چیزی هست که خودشون توش نوشتن، که یه چیز خارج از انتظاره براشون و ممکنه تو روند کارشون مشکلی ایجاد کنه، معنیش اینه که پروسس ها ایزوله نیستن.خب حالا بیاییم به این سوال که پروسس ایزوله شده یعنی چی جواب بدیم، پروسس ایزوله شده (Isolated process) به یک پروسس یا برنامه اشاره داره که در یک محیط عملیاتی جداگونه اجرا می‌شه و از سایر پروسس‌ها یا برنامه‌ها در سیستم عامل جداست. این مفهوم ایزوله سازی برای تفکیک و محافظت از منابع و فعالیت‌های یک پروسس مشخص استفاده می‌شه.وقتی یک پروسس در یک محیط ایزوله اجرا می‌شه، این یعنی که این پروسس مستقل از سایر پروسس‌ها عمل می‌کنه و تأثیر کوچکی روشون داره. تو محیط ایزوله شده، پروسس ممکنه دسترسی محدودتری به منابع سیستمی مثل حافظه، فایل‌ها، شبکه و دستگاه‌های ورودی/خروجی داشته باشه.خب حالا که فهمیدیم پروسس ایزوله شده یعنی چی بریم ببینیم این اتفاق چطوری داره تو لینوکس میافته.ایزوله سازی در لینوکس (Process Isolation In Linux)یه بار دیگه به این نمودار دقت کنین، یه مفهومی توش بود که راجع بهش حرف نزدیم default namespace.تو لینوکس هر پروسس بدون استثنا داره توی یه namespace مشخص اجرا میشه، که این namespace مشخص میکنه پروسس ما به چه منابعی از سیستم دسترسی داره، که همین موضوع نشون میده چرا پروسس های ما نسبت به هم ایزوله نیستن و از منابع مشترک استفاده می کنن (چون تو یک namespace مشترک به اسم default namespace دارن اجرا میشن).خب حالا با این مقدمه بریم سراغ اینکه لینوس چطوری پروسس ها رو ایزوله میکنه؟ برای این منظور دو feature تو لینوکس پیاده شده که مسئول این ایزوله سازی هستن:NamespaceControl Groups (cgroups)آشنایی با Namespaceبا این ویژگی تا یه حدی آشنا شدیم، namespaceها خیلی خلاصه مسئول این هستن که مشخص کنن هر پروسس یا یه گروه از پروسس‌ها به چه منابعی می تونن دسترسی داشته باشن! البته مهم تر از اون، پروسسی که در یک namespace قرار می گیره اینطور براش شبیه سازی می شه که فک می کنه که به تمام منابع سیستم دسترسی داره و خودش تنها پروسسی هست که داره اجرا میشه (مثل دید ما انسان ها به دنیا ?). به نمودار زیر نگاه کنیم تا بهتر این مفهوم رو درک کنیم:تو این نمودار می تونیم ببینیم که پروسسی که تو یک namespace قرار گرفته به یک نسخه انتزایی از منابع سیستم مثل RAM, CPU, Network و Hard Drive دسترسی داره و به همین ترتیب پروسس های دیگه در namespace های دیگه هم فقط به نسخه‌ای از منابع که بهشون تخصیص داده شده دسترسی دارن و نمی تونن دخل و تصرفی به منابع پروسس های دیگه داشته باشن. به همین دلیل میگیم پروسس ها دارن تو یک محیط ایزوله شده اجرا میشن. نمودار پایین نشون میده که چطور دو تا پروسس نسبت به هم ایزوله هستن:انواع Namespace در لینوکسنکته مهم اینکه تنها فقط یک نوع namespace برای این منظور وجود نداره، namespace‌های مختلفی تو لینوکس وجود داره که هر کدوم‌شون مسئول مدیریت منابعی از سیستم هستن و اینجا می خوایم با چندتا از پر استفاده ترینشون آشنا بشیم که مخصوصا تو تکنولوژی های مثل داکر برای ایجاد یک کانتینر استفاده میشن: PID namespaceNetwork namespaceMount namespaceUser namespaceنوع PID namespaceاین namespace برای ایزوله کردن ID پروسس‌ها ایجاد شده، به این معنی که پروسس‌هایی که در PID namespace قرار می‌گیرن ID‌هاشون طوری تعریف میشه که تداخلی با ID پروسس‌های دیگه در namespaceهای دیگه نداشته باشن.نوع Network namespaceاین نوع از namespace  همونطور که از اسمش مشخصه، مسئول ایزوله سازی منابع مرتبط با شبکه هست مثل network interfaces, IP addresses, routing tables و firewall rules. هر network namespace می تونه کانفیگ مربوط به شبکه خودش رو داشته باشه که اینطور براش بنظر میاد که یه سخت افزار شبکه جداگونه بهش اختصاص دادن که هر طور نیاز داره می تونه کانفیکش کنه بدون اینکه نگران این باشه که مشکلی برای پروسس های دیگه بوجود بیاره. این یعنی میتونیم مثلا تو namespaceهای مختلف رنج IP های یکسان داشته باشیم بدون اینکه مشکلی ایجاد بشه.نوع Mount namespaceبرای ایزوله کردن mount pointهای فایل سیستم استفاده میشه. پروسس هایی که تو mount namespace‌های مختلف اجرا میشن، دیدی که نسبت درخت فایل سیستم‌شون دارن متفاوت از هم دیگه‌ست، که باعث میشه پروسس‌ها فایل سیستم ایزوله شده خودشون رو داشته باشن و نتونن دخل و تصرفی روی فایل های پروسس دیگه داشته باشن.نوع User namespaceبرای ایزوله کردن تو سطح user و group استفاده میشه که این اجازه رو به پروسس‌ها میده که با دسترسی های مختلف (privileges) در namespace اجرا بشن.آشنایی با Control Groupsخب تا اینجا متوجه شدیم که namespace برای تخصیص منابع به پروسس‌ها به کار میرن که انواع مختلفی هم داشت که با بعضی‌هاشون آشنا شدیم و گفتیم با namespaceها یه کپی از منابع سیستم رو اختصاص میدیم به یه پروسس ولی سوال اینجاست که خب چقدر از منابع؟ یا هر پروسس چقدر از این منابع رو در اختیار داره؟جواب این سوال cgroups هست، cgroups یه فیچر تو کرنل لینوکس هست که مسئول تخصیص و مدیریت میزان مصرف منابع  برای هر پروسس هست. پس ما می تونیم با استفاده از namespaceها منابعی رو که پروسس ها نیاز دارن بهشون تخصیص بدیم و به وسیله‌ی cgroups مشخص کنیم که به چه میزان از این منابع می تونن استفاده کنن.کانتینر چیست؟خب حالا بیاییم یک بار دیگه کانتینر رو معرفی کنیم، کانتینر یک محیط ایزوله شده‌ست (Isolated environment)  که با تکنولوژی هایی مثل داکر با استفاده از ابزارهایی هایی مانند namespace و cgroups ایجاد می‌شود و به برنامه‌ها منابع مورد نیازشان (نرم افزاری و سخت‌افزاری) را برای اجرا در اختیارشون می‌گذارن.با استفاده از کانتینرها، برنامه‌ها به‌راحتی قابل بسته‌بندی، انتقال و اجرا در محیط‌های مختلف دیگه هستن. همچنین کانتینرها می‌تونن برنامه‌ها را در محیط‌های متفاوت به صورت یکسان و پیش‌بینی‌پذیر اجرا کنند.نکته: کانتینرها ویژگی های مهم دیگه علاوه بر Isolation، مانند Encapsulation، Portability و Consistency در اختیار ما قرار میده که مورد بحث ما نیستن.در پایان خواستم به این نکته هم اشاره کنم که سعی کردم مفاهیم رو تا جای ممکنه ساده سازی کنم که با هر سطح از دانشی قابل درک باشه، و معمولا ساده سازی مفاهیم یه سری چیزا ممکنه جا بمونه یا اونطوری که هست کامل بیان نشه. هدفم از نوشتن این نوشته ایجاد یه کنجکاوی بود که برید ببینین اون پشت مشتآ چه اتفاقی داره میافته که عمیق تر مسائل رو یاد بگیرید :)</description>
                <category>Mehdi Zarepour</category>
                <author>Mehdi Zarepour</author>
                <pubDate>Mon, 19 Jun 2023 10:40:10 +0330</pubDate>
            </item>
            </channel>
</rss>