داکر کامپوز ابزاریه که با استفاده از اون میتونیم چندین کار رو با یک دستور انجام بدیم. مثلا میتونیم چندین کانتینر رو به همراه نتورکها و والیومهایی که لازم داره بسازیم و به هم ارتباط بدیم. قبلتر باید داکر کامپوز رو جداگانه نصب میکردیم اما اخیرا امکان اینکه بتونیم کامپوز رو به صورت یه پلاگین همراه داکر کلاینت داشته باشیم هم اضافه شده و دیگه نیاز نیست که براش ابزار جداگانهای نصب کنیم. یه نکتهی مهم اینکه اگر شما یک سرور داشته باشید بهترین گزینه برای مدیریت سرویسها استفاده از docker compose هست.
خب یه مروری کنیم پستهای قبلی رو:
توصیه میکنم که حتما این پستها رو هم مطالعه کنید. بریم که ادامه بدیم.
تاریخچه داکر کامپوز:
ورژن اول کامندلاین داکر کامپوز تو سال ۲۰۱۴ اومد که با زبان پایتون نوشته شده بود و با دستور docker-compose اجرا میشد و بالای فایل های کامپوزش هم یک قسمت version میذاشتن که از عدد ۲.۰ تا ۳.۸ مقادیر مختلف داشت که فایل فورمت های مختلفن و اینجا میتونید بیشتر بخونید در موردش. اما از سال ۲۰۲۰ ورژن دوم داکر کامپوز معرفی شد که به زبان گولنگ هست و با دستور docker compose ازش استفاده میکنیم و دیگه بخش version رو بالای فایل هاش نداره و میتونیم نذاریمش.
کامپوز قابلیت اینو داره که توی محیط های مختلف عملیاتی مثل پروداکشن، استیج، دولوپمنت و تست اجرا بشه و سرویسهای ما رو راهاندازی کنه. یعنی اینکه ما یه کامپوزفایل داریم که باهاش میتونیم تو محیطهای مختلف سرویس خودمون رو راهاندازی کنیم و بالا بیاریم.
یک نکتهی مهم اینکه ما یک کامندلاین به عنوان docker compose و یک compose file داریم که فرمت yaml داره. همواره ما کامپوز فایل سرویسهای خودمون رو آماده میکنیم که داخل آن سرویسها به همراه نتورک و والیومهای آنها و هر چیزی که لازم دارند رو قرار دادیم. به عبارتی ما تو کامپوزفایل داریم میگیم که سرویسهامون چطوری بالا میان و راهاندازی میشن.
داکر کامپوز برای ما کنترل کردن کل استک اپلیکیشن هامون رو راحت کرده و همینطور مدیریت سرویس ها و شبکه اونها و والیومهای دیسکی که نیاز دارند رو جمع کرده توی یه دونه yaml فایل. بعد از اینکه کامپوز فایلتون رو آماده کنید، یه دستور docker compose up -d میزنید و تمام سرویسها و کانفیگ هایی که زدید، ایجاد میشن 🙂
نکتهی دیگه اینکه ما با استفاده از compose file داریم میریم سمت اینکه همه چیز رو به صورت کد کنیم. با داکرفایل داریم نحوهی آماده سازی ایمیج رو به صورت کد میکنیم و با استفاده از کامپوز فایل نحوهی راهاندازی و اجرای کانتینرها رو داریم کد میکنیم. قبلا هم زیاد روی این موضوع تاکید کردم و کلا توی دواپس ما دنبال این هستیم که بریم سمت کد! دلیلش هم اینه که کد رو میشه نگهداری کرد و بهبودش داد و هی بهترش کرد.
توی مسیر پروژه کامپوز فایل باید با یکی از اسمهای compose.yml یا compose.yaml یا docker-compose.yml یا docker-compose.yaml قرار بگیره که دو مورد آخر برای ورژن های قبلتر هست و اولویت اجرا با اسم compose هست.
برای اینکه کامپوز فایلتون رو کارآمدتر کنید و نگهداریش رو بهتر کنید میتونید در مورد fragments و extensions هم بخونید.
اگر تعداد سرویسهای کامپوزتون زیاد هست برای اینکه فایل کامپوز مرتب تری داشته باشید میتونید سرویسهاتون رو توی چنتا فایل جدا کنید. سه روش برای این مورد هست که ساده ترش اینه که از فلگ f- و merge استفاده کنید و روش های Extend و Include هم هستند که میتونید بیشتر درموردشون بخونید.
در ادامه لیستی از مواردی که میتونیم توی کامپوز فایل مون اونها رو کانفیگ کنیم همراه یه توضیح کوتاه ازشون رو براتون میذارم:
معمولا این سناریو در راهاندازی سرویسها انجام میشود. ابتدا داکرفایل برای ایجاد ایمیجها آماده میشود. سپس با توجه به نیاز موجود برای راهاندازی سرویس و ارتباطات و عملکرد آنها با هم یک کامپوز فایل آماده میگردد. سپس با استفاده از دستورات داکرکامپوز و با توجه به کامپوز فایل سرویس با تمام شرایط مد نظر راهاندازی و در اختیار قرار میگیرد. میتوان برای کل سرویس و یا هر جزئی از آن نیز تست نوشت و تمام موارد را تست کرد.
حالا ما در ادامه این مستند گریزی هر چند کوتاه اما مفید بر نگارش کامپوز فایل خواهیم داشت.
تنها دستورالعملهای services, networks و volumes به صورت مسیر پیشفرض در کامپوزفایل میباشند. البته دستورالعملهای configs و secrets هم هستند اما آنها تنها در قسمت swarm کاربرد دارند. همانطور که میدونید yaml به indent دستورالعملها حساس میباشد از این رو در زمان ایجاد yaml file میبایست به موقعیت مکانی تمام دستورالعملها دقت کرد زیرا اگر در جای درستی قرار نگرفته باشن خطا میده و فایل شما اجرا نخواهد شد. در ضمن پسوند فایل میتواند yml. یا yaml. باشد و هر دو تای آنها درسته.
زمانی که یک کامپوزفایل اجرا میشود همانند این است که با دستورات مختلف ایمیج دریافت و یا ساخته شود و یا اینکه کانتینر با استفاده از تنظیماتی که قرار داده شده است ایجاد شود و یا اینکه شبکه با کانفیگ مشخص ایجاد شود. در واقع تمام آپشنها و دستورالعملهایی که در کامپوزفایل مورد استفاده قرار میگیرد همان دستورات داکر است که اومدن توی یه فایل yaml قرار گرفتن.
با استفاده از این دستورالعمل میتوان تنظیمات مربوط به ساخت ایمیج در زمان اجرای سرویس را داد. میتوان مسیر و اسم داکرفایل را مشخص کرد و آپشنهای زمان build همانند arg را در آن قرار داد و یا اینکه ایمیج با چه نامی ساخته شود. دستورالعملهای مهم زیر مجموعهی build عبارتند از:
دستورالعمل context: مسیری که داکرفایل در آنجا قرار دارد و یا آدرس ریپوی git آن را مشخص میکند.
دستورالعمل dockerfile: داکرفایل اگر با نام Dockerfile داخل مسیری که اشاره شد وجود ندارد و نام دیگری دارد با این آپشن مشخص میکند.
دستورالعمل args: دقیقا همان arg داخل داکرفایل است که میتوان در زمان ساخت ایمیج آن را قرار داد.
دستورالعمل labels: در زمان ساخت ایمیج به آن لیبل داده میشود. (از نسخهی ۳.۳ به بعد)
دستورالعمل command: دستورالعمل پیشفرض کانتینر را جایگذاری میکند.
اسم کانتینر را مشخص میکند. اگر اسم برای کانتینر انتخاب نشود ترکیبی از اسم سرویس به همراه دایرکتوری آن قرار میدهد.
این دستورالعمل بسیار کاربردی میباشد و اگر بین سرویسهای داخل کامپوز فایل اولویت زمانی در راهاندازی اهمیت داشته باشد با استفاده از این دستورالعمل میتوان سرویسی را به سرویس دیگری وابسته کرد. در تصویر زیر برای اینکه سرویس web راهاندازی شود نیاز است تا ابتدا سرویس db و سرویس redis راهاندازی شود. تازمانی که هر دو سرویس راهاندازی نشوند سرویس web راهاندازی نخواهد شد.
فقط در نسخهی ۳ کار میکند. میتوان با استفاده از آن موارد مربوط به پیادهسازی سرویس را مشخص کرد. این دستورالعمل تنها در زمان استفاده از swarm و با دستورالعمل docker stack deploy قابل استفاده میباشد. اگر با دستور docker compose استفاده شود این قسمت به صورت کلی نادیده گرفته میشود. حالا بعدا در مستندی به صورت کامل swarm و نحوهی کار با آن و آپشنهای کنار آن رو توضیح میدهیم.
برخی از آپشنهای زیرمجموعهی این دستورالعمل توضیح داده میشود.
دستورالعمل endpoint_mode: تنها در نسخهی ۳.۳ قابل استفاده است. برای زمانی که کاربر از بیرون کلاستر بخواهد به آن متصل شود کاربرد دارد. دو حالت دارد که در ادامه توضیح داده میشود:
دستورالعمل mode: اگر به صورت global تنظیم شود به ازای هر نود در کلاستر swarm یک کانتینر ایجاد خواهد شد. به صورت پیشفرض replicated تنظیم شده است که به تعداد مشخصی از کانتینر دیپلوی میشود.
دستورالعمل replicas: با استفاده از آن تعداد مشخص کانتینر رو برای ایجاد کردن مشخص میکند.
دستورالعمل resources: با استفاده از این دستورالعمل میتوان منابعی که این کانتینر استفاده میکند را مشخص و محدودیتهای مربوط به آن را تنظیم نمود. به مثال زیر توجه کنید.
دستورالعمل restart_policy: تنظیمات مربوط به restart کانتینر میباشد. این کانفیگ تنظیمات مربوط به restart را جایگزین میکند. در مثال زیر زمانی که موضوعی باعث fail کانتینر شود با ۵ ثانیه تاخیر ۳ بار تلاش میکند تا کانتینر را ران کند.
با استفاده از این دستور العملها میتوان برای کانتینر DNS تنظیم کرد. به مثالهای زیر توجه کنید.
dns: 8.8.8.8 dns: - 8.8.8.8 - 9.9.9.9 dns_search: example.com dns_search: - dc1.example.com - dc2.example.com
با استفاده از این دستورالعمل، میتوان entrypoint داخل ایمیج را در این سرویس جایگذاری میکند و این به جای آن اجرا میشود. به صورت زیر میتوان از آن استفاده کرد.
entrypoint: /code/entrypoint.sh
entrypoint: - php - -d - zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20100525/xdebug.so - -d - memory_limit=-1 - vendor/bin/phpunit
اضافه کردن متغیرهای محلی با استفاده از فایل که میتواند شامل یک متغیر و یا لیستی از آنها باشد. به مثالهای زیر توجه کنید.
env_file: .env
env_file: - ./common.env - ./apps/web.env - /opt/secrets.env
در فایلهای متغیرها، اونها رو به صورت VAR=VAL میبایست قرار داد. اگر از # استفاده شود به صورت comment خواهد بود و خط خالی نیز نادیده گرفته میشود.
# Set Rails/Rack environment RACK_ENV=development
اگر نیاز باشد متغیری تنها در زمان build مورد استفاده قرار گیرد میبایست از arg استفاده کرد. اگر چند تا فایل متغیر باهم لود بشن و داخل آنها متغیر یکسان وجود داشته باشد همواره متغیرهای فایل آخر مرجع میباشد. یعنی آخرین مقداری که متغیر گرفته باشد معتبر است. نکتهی مهمی است که بهش دقت کنید.
از این دستورالعمل برای زمانی که بخواهیم یک یا چند متغیر را در کانتینر مقداردهی کنیم استفاده میکنیم. تفاوت در این است که تمام متغیرها داخل خود کامپوزفایل تعریف خواهد شد و فایل دیگهای لود نخواهد شد. به هر دو صورت زیر از آن استفاده میشود.
environment: RACK_ENV: development SHOW: 'true' SESSION_SECRET:
environment: - RACK_ENV=development - SHOW=true - SESSION_SECRET
برای expose کردن پورت داخل کانتیر استفاده میشه. این به معنای در دسترس قرار دادن آن پورت در داکرهاست نیست. به اون عمل، publish میگن که دستورالعمل مخصوص خودش رو داره. معمولا از expose برای ارتباط داخلی بین کانتینرها و زمانی که آنها بین هم link میشوند استفاده میشود.
expose: - "3000" - "8000"
حواستون به تفاوت بین expose و publish باشه که این دو تا باهم متفاوت هستند. اینجا در موردشون صحبت کردیم.
برای زمانی که نیاز است تا با کانتینری خارج از این docker-compose.yml ارتباط برقرار کرد استفاده میشود. به صورت CONTAINER:ALIAS نیز استفاده میشود. به مثال زیر توجه کنید.
external_links: - redis_1 - project_db_1:mysql - project_db_1:postgresql
با استفاده از آن میتوان داخل etc/hosts/ کانتینر اطلاعاتی که لازم داریم را وارد کنیم و اصطلاحا به آن host اضافه کنیم.
extra_hosts: - "somehost:162.242.195.82" - "otherhost:50.31.209.229"
میتوان وضعیت سلامت سرویس داخل کانتینر رو بررسی کرد که دارای ۳ تا وضعیت میباشد که قبلا در داکرفایل آنها را توضیح دادیم. تمام مواردی که در این دستورالعمل مورد استفاده قرار میگیرد دقیقا همانند داکرفایل میباشد با این تفاوت که در داکرفایل داخل ایمیج این موارد تنظیم میشد و اینجا برای خود کانتینر تنظیم میشه.
healthcheck: test: ["CMD", "curl", "-f", "http://localhost"] interval: 1m30s timeout: 10s retries: 3 start_period: 40s
در صورتی که نیاز داشته باشید که healthcheck مربوط به ایمیج را نیز غیر فعال کنید میتواند از دستور زیر استفاده کنید.
healthcheck: disable: true
ایمیج مورد استفاده را مشخص میکند و کانتینر از روی این ایمیج آماده میشود. البته میتوان با استفاده از دستورالعمل build ایمیج مورد استفاده را از روی داکرفایل نیز ایجاد کرد.
با استفاده از آن میتوان metadata کانتیرها را تغییر داد. گاهی با استفاده از این اطلاعات که به کانتینرها اضافه میشود میتوان سرویسهای مختلفی را دریافت کرد. برای همین این موضوع اهمیت زیادی دارد.
با استفاده از آن میتوان سرویس logging مربوط به کانتینر را پیکربندی کرد. همانطور که میدانید و قبلا نیز توضیح داده شد سرویس logging داخل داکر و برای کانتیرها دارای درایورهای مختلفی میباشد از این رو میتوان نوع درایور و تنظیمات آن را در این دستورالعمل مشخص کرد. به مثال زیر توجه کنید.
logging: driver: syslog options: syslog-address: "tcp://192.168.0.42:123"
به صورت پیشفرض ۳ تا درایور برای لاگ کانتیرهای داکر وجود دارد که عبارت است از:
driver: "json-file" driver: "syslog" driver: "none"
که درایور json-file به صورت پیشفرض میباشد و تمام آن را میتوان در دستور docker-compose logs مشاهده کرد. یه نکتهی مهم اینکه این آپشن و دستورالعمل وابسته به کانفیگ مربوط به logging driver سرویس داکر شما میباشد و درایورهایی رو میتوانید استفاده کنید که در آنها تعریف کرده باشید.
برای مشخص کردن شبکه کانتینر مورد استفاده قرار میگیرد. برای زمانی کاربرد دارد که شما بخواهید از modeهای مختلفی به عنوان مثال host و یا none استفاده نمایید.
با استفاده از آن میتوان تنظیمات مربوط به شبکهی کامپوزفایل و کانتینرهای آن را تعیین کرد. این دستورالعمل چند تا زیرمجموعهی مهم دارد که در ادامه توضیح داده میشود.
دستورالعمل aliases: با استفاده از آن برای کانتیرها aliase تعریف میشود و میتوان داخل آن network کانتینر را علاوه بر اسم و id آن با این aliase نیز صدا کرد.
دستورالعمل ipv4_address, ipv6_address: با استفاده از آن میتوان ip به هر کانتیر اختصاص داد.
version: '3' services: some-service: networks: some-network: aliases: - alias1 - alias3 ipv4_address: 172.16.238.10 ipv6_address: 2001:3984:3989::
میتوان pid داخل کانیتر را با host یکی کرد که برای این کار از این دستورالعمل استفاده میشود.
که با استفاده از آن میتوان پورتها رو از داخل کانتیر به هاست publish کرد. به صورت اختصار به صورت HOST:CONTAINER استفاده میشود. برای مثال پورت ۸۰ کانتیر به پورت ۸۰۸۰ هاست مپ میشود.
ports: - "8080:80"
میتوان تنها پورت کانتیر را قرار داد که آنگاه سرویس داکر آن را بر روی یکی از رندم پورتهای هاست مپ میکند. و میتوان به صورت اختصاصی مشخص کرد که این پورت بر روی کدام پورت و ip سروس هاست bind شود و یا اینکه در چه پروتکلی قرار داشته باشد. در مثالهای زیر تمام موارد آورده شده است.
ports: - "3000" - "3000-3005" - "8000:8000" - "9090-9091:8080-8081" - "49100:22" - "127.0.0.1:8001:8001" - "127.0.0.1:5000-5010:5000-5010" - "6060:6060/udp"
اما به گونهای دیگر نیز پورت را تعریف کرد که دارای توضیحات زیاد و روش طولانی آن میباشد. در مثال زیر پورت ۸۰ داخل کانتینر را به پورت ۸۰۸۰ داخل هاست مپ میکند. این نوع فرمت در نسخه ۳.۲ به بعد میباشد.
ports: - target: 80 published: 8080 protocol: tcp mode: host
این دستورالعمل برای سیاست restart کانتینر مورد استفاده قرار میگیرد و به صورت پیشفرض برای همهی کانتینرها no میباشد. این دستورالعمل تنها در زمان استفاده غیر swarm کاربرد دارد. اگر از آپشن always استفاده شود همواره بعد از هر اتفاقی حتی اگر کانفیگ کانتینر مشکل داشته باشد مدام تلاش میکند که آن را استارت کند. آپشن on-failure برای زمانی است که به دلیل خطایی کانتینر استاپ شده باشد که آن را مجدد استارت میکند. آپشن unless-stopped که بسیار شبیه always میباشد اما اگر کانتیر به صورت دستی stop شود بعد از restart سرویس داکر کانتیر را استارت نمیکند اما در always این کار را انجام میدهد.
با استفاده از آن میتوانید آپشنهای مربوط به sysctl داخل کانتیر ایجاد و اجرا کنید. به دو صورت زیر مورد استفاده قرار میگیرد.
sysctls: net.core.somaxconn: 1024 net.ipv4.tcp_syncookies: 0 sysctls: - net.core.somaxconn=1024 - net.ipv4.tcp_syncookies=0
با استفاده از آن آپشنهای مربوط به limit.conf را میتوان در کانتیر تغییر داد و اجازه استفاده بیشتر و بهینهتر از منابع سیستمعامل را به آن داد.
ulimits: nproc: 65535 nofile: soft: 20000 hard: 40000
به دو روش یکی قرار دادن بر روی مسیری از دایرکتوری هاست و دیگری ایجاد والیوم با استفاده از درایورهای مختلف میتوان دادههای کانتینر را بر روی هاست ذخیره کرد. در استفاده از والیوم نیز میتوان به صورت مختصر یعنی HOST:CONTAINER استفاده کرد یا به صورت طولانیتر تمام هر قسمت را توضیح داد. در مثال زیر چند نمونه از استفادهی مختصر آن آورده شده است.
volumes: # Just specify a path and let the Engine create a volume - /var/lib/mysql # Specify an absolute path mapping - /opt/data:/var/lib/mysql # Path on the host, relative to the Compose file - ./cache:/tmp/cache # User-relative path - ~/configs:/etc/configs/:ro # Named volume - datavolume:/var/lib/mysql
معمولا این روش بسیار مرسومتر است و روش توضیح بیشتر آن کمتر استفاده میشود.
میتوان با استفاده از آن domainname را برای کانتینر تعریف کرد.
با استفاده از آن hostname برای کانتینر تعریف میکنیم.
اگر در کانتینر نیاز به سطح دسترسی بیشتری هستیم آن را با privileged اجرا خواهیم کرد. این موضوع نکتهی امنیتی دارد و بهتر است که استفاده نشود.
کاربر کانتینر در زمان اجرا را مشخص میکند.
دایرکتوری کاری کانتینر را مشخص میکند.
والیومی که در قسمت بالاتر توضیح داده شد مربوط به قسمت سرویس میباشد اما این قسمت برای تعریف والیوم میباشد. این قسمت هم ردیف قسمت سرویس در کامپوز فایل قرار داده میشود. این دستورالعمل شامل چند زیرمجموعه میباشد که عبارتند از:
دستورالعمل driver: با استفاده از آن میتوانیم درایور مربوط به والیوم را مشخص کنیم. به صورت پیشفرض درایور local استفاده میشود.
دستورالعمل driver_opts: با استفاده از این دستورالعمل میتوان لیست آپشنهای مربوط به درایور والیوم را مشخص و تنظیم کرد. به عنوان مثال میتوان برای والیوم خود محدودیت حجم در نظر گرفت.
دستورالعمل external: اگر این آپشن true باشد یعنی والیوم بیرون از کامپوز فایل تعریف میشود و وجود خواهد داشت و باید از آن استفاده کند. معمولا این آپشن مواقعی که از stack استفاده میشود کاربرد دارد.
دستورالعمل labels: با استفاده از آن میتوان metadata والیومها را تغییر داد.
دستورالعمل name: برای کانتینر اسم انتخاب کرد. (از نسخهی ۳.۴ به بعد)
قبلا درباره network که زیرمجموعه سرویس بود صحبت کردیم. این قسمت هم ردیف سرویس در کامپوز فایل بوده و برای معرفی شبکهی مورد استفاده کاربرد دارد. این دستورالعمل چندین زیرمجموعه دارد که در ادامه به آنها اشاره میشود:
دستورالعمل driver: با استفاده از آن درایور شبکه مورد نظر را مشخص میکند که به صورت پیشفرض bridge میباشد.
دستورالعمل driver_opts: با استفاده از آن میتوانیم آپشنهای مربوط به درایور را مشخص کنیم که این موارد به صورت key-value تنظیم میگردد.
دستورالعمل attachable: میتوان یک کانتینر را به شبکهی overlay متصل کرد.
دستورالعمل enable_ipv6: نسخهی ipv6 را برای این شبکه فعال میکند.
دستورالعمل ipam: برای اینکه بتوان درایور ipam را تغییر داد از آن استفاده میشود. به عنوان مثال میتوان subnet و .. را تغییر داد و آنها را کانفیگ کرد.
دستورالعمل internal: به صورت پیشفرض تنظیم شده است. به معنای اینکه شبکه داخل کامپوزفایل ایجاد می شود و داخل آن استفاده میشود.
دستورالعمل external: به معنای آن میباشد که این شبکه بیرون از کامپوز فایل تعریف شده است و میبایست قبل از اجرای کامپوز فایل آن را ایجاد نمایید.
دستورالعمل labels: با استفاده از آن میتوان metadata مربوط به شبکه را کاملتر کرد.
دستورالعمل name: برای شبکهای که ساخته میشود اسم انتخاب میکند.
در زمان آماده سازی کامپوز فایل میتوان برخی از مقادیر را به صورت متغیر تعریف کرد. نحوهی استفاده از متغییرها به صورت زیر میباشد.
$VARIABLE ${VARIABLE}
تمام این متغیرها و مقادیر آنها در یک env. فایل باید باشد تا در کامپوز فایل مورد استفاده قرار گیرد.
برخی از موارد دیگه همانند configs و secrets باقیمانده است که آنها را در زمانی که میخواهیم از swarm استفاده کنیم توضیح خواهیم داد.
مراقب خودتون باشید. 🌹🐳🌹
خوبه که داکرمی رو تو جاهای مختلف فالو کنید. پذیرای نظرات شما هستیم.
🫀 Follow DockerMe 🫀
🔔 Follow YouTube 🔔
📣 Follow Instagram 📣
🖇 Follow LinkedIn DockerMe🖇
🔎 Follow Linkedin Ahmad Rafiee 🔎
🕊 Follow Twitter 🕊