اگه نمیدونید داکر چیه و جرا باید ازش استفاده کنیم، این پست رو بخونید.
در این مقاله موارد زیر را با استفاده از جنگو و PostgreSQL توضیح میدهم:
حتما توصیه میکنم بخش آخر، جمع بندی، را بخونید. از گیج شدن بعد خوندن این پست کاملا جلوگیری میکنه.
داکر Compose یک ابزار برای تعریف و اجرای اپهایی هستش که از چند کانتینر مختلف استفاده میکنند.
فرض کنید شما روی توسعه یک وب اپلیکشن توسط فریمورک Django با استفاده دیتابیس PostgreSQL کار میکنید. اگر بخواهید از داکر استفاده کنید، باید کانتینر مربوط به Django و PostgreSQL رو جداگانه کانفیگ و اجرا کنید. (اینجا فرض من اینه میدونید داکر چیه و چرا باید کانتیترهای جنگو و دیتابیس رو جدا اجرا کرد) اما با استفاده از داکر compose میتونید هر دو کانتینر رو به عنوان یک سرویس و با یک دستور اجرا کنید.
یکی از ویژگیهای جالب docker compose پشتیبانی از اجرای تستهای واحد و E2E، به صورت سریع و قابل تکراره و این تستها در محیطهای مخصوص به خودش انجام میشه.
داکر Compose از تداخل سرویس های مختلف جلوگیری میکنه. میتویند از یک سرویس کپی یا کانفینگهای مختلفی روی لوکال یا سرور داشته باشید.
داکر Compose یک راه سریع و ساده برای شروع پروژه ها است چون به سرعت محیطهای توسعه ایزوله جدید را ایجاد میکنه. نرم افزار تمام وابستگیهای سرویس برنامه (دیتابیسها، API های وب سرویس و غیره) را کانفیگ میکنه. این به شما امکان میده با استفاده از یک فرمان، یک یا چند کانتینر برای هر وابستگی ایجاد و شروع کنید.
راه اندازی سریع و ساده (Fast and simple configuration)
به لطف اسکریپت های YAML و متغیرهای محلی، میتوانید به راحتی سرویسهای برنامه را کانفیگ یا تغییر دهید. ( اینکه YAML چیه رو در ادامه میخونید)
ارتباطات امن (Secure internal communication)
از آنجایی که همه سرویسها در داخل فایل docker-compose تعریف شدهاند، توسعهدهندگان میتوانند به راحتی به کل کانفیگ دسترسی داشته باشند. با استفاده از فایل docker-compose ، در عرض چند دقیقه محیط توسعه آماده میشه که این به راه اندازی و فعال کردن CI/CD Pipeline کارآمد کمک میکنه.
داکر Compose به شما امکان میده چندین محیط ایزوله را روی یک هاست اجرا کنید. اجرای همه چیز روی یک سخت افزار به شما اجازه میده منابع آزاد بیشتری داشته باشید.
۱. ایجاد یک Dockerfile . این فایل Image های داکر را میسازد که به عنوان پایه کانتینرها استفاده می شه.
یک Dockerfile، اسکریپت با دستورالعملهایی در مورد نحوه ساخت Docker Image است. این دستورالعملها در واقع گروهی از دستورات هستند که به طور خودکار در محیط داکر برای ساخت Docker Image خاص اجرا میشوند.
۲. سرویسها را در یک فایل Compose تعریف کنید. یک فایل جدید در دایرکتوری پروژه با نام docker-compose.yml ایجاد کنید و سرویسها رو با استفاده از سینتکس YAML تعریف کنید.
۳. با استفاده از دستور docker compose up کل برنامه اجرا میشه. ( images & containersl سرویسها اجرا میشوند.)
در ادامه متوجه میشید در اکثر مواقع نیازی به انجام مرحله اول نداریم.
برای اینکه یک مثال ببینیم ۳ مرحله docker compose چجوری اجرا میشه، جنگو و postgreSQL رو با استفاده docker compose کانفیگ میکنم.
یک دایرکتوری با هر اسمی دلخواهی ایجاد کنید. از این دایرکتوری برای ایجاد سورس اولیه مورد نیاز برای ساختن image استفاده میکنیم.
۱. فایلی با نام Dockerfile در داخل پوشه پروژه تون (دایرکتوری که مرحله قبل ساختید) ایجاد کنید. در لینوکس و مک با دستور touch Dockerfile اینکار انجام میشه.
نکته مهم اینه که اسم فایل حتما و حتما باید Dockerfile باشه. بدون هیچ فرمتی مثل txt
اسکریپت زیر رو داخل Dockerfile بنویسید.
# syntax=docker/dockerfile:1 FROM python:3.10.2 ENV PYTHONDONTWRITEBYTECODE=1 ENV PYTHONUNBUFFERED=1 WORKDIR /majid COPY . . RUN pip install -r requirements.txt
اگر این پست رو بخونید متوجه میشید که Docker image را میشه براساس Docker image های دیگه ساخت. در واقع تعداد زیادی Base Image داریم که براساس اونها Image خودمون رو میسازیم. Base Image در واقع یک لینوکس کوچک هستش که روی هر کدامشان یک یا چند ابزار پایه با کمترین Dependencyها نصب شده اند.
در حال حاضر ما یک image جدید بر اساس Python 3.10.2 داریم (البته هنوز ساخته نشده) و dependencies های مورد نیاز رو هم داخلش تعریف کردیم.
ما دستورالعملهای کامل برای ایجاد یک تصویر سفارشی داریم اما هنوز آن را نساختهایم. دستور انجام این کار بصورت زیر هستش. قبل اینکه دستور را بزنید باید داخل ترمینال با دستور cd وارد دایرکتوری که Dockerfile قرار داره، بشید.
docker build -t django-image .
در این دستور t - یک تگ به نام django-image به docker image انتساب میده. اینکار برای خوانایی راحتتر انجام میشه. در آخر دستور بالا < . > بیانگر این است که Dockerfile در دایرکتوری فعلی هستش.
در اینجا خروجی زیادی وجود خواهد داشت که من فقط دو خط اول و آخری را آورده ام.
تا اینجا ما با استفاده از Base image: Python3.9 یک Image ساختیم. در این پست توضیح دادم که چجوری میشه یک کانتینر ساخت و اجراش کرد. در اینجا هم ما باید کانتینر بسازیم. میتونیم مشابه پست قبلی و کانتینرمون رو بسازیم. اما یادتون باشه که در اینصورت ما فقط یک کانتینر براساس Python3.9 و برای جنگو ایجاد کرده ایم. اگر بخواهیم کانتینر برای PostgreSQL رو هم ایجاد کنیم باید مشابه پست قبلی، اول Image مناسب رو از سایت داکرهاب pull کنیم و .....
اما Docker Compose اومده که ما بتونیم بصورت ساده تر و دقیقتر (و همینطور خواناتر) همه کانتینرهامون رو بسازیم.
۲.فایل docker-compose.yam برای پروژه جنگو با دیتابیس PostgreSQL
برای ساخت و اجرای کانتیر یکسری دستورعمل نیاز هستش که بوسیله فایل docker-compose.yml این دستورالعمل هارو مشخص میکنیم. ابتدا یک فایل ایجاد کنید و نام آن را دقیقا برابر docker-compose قرار دهید. فرمت فایل هم میتواند yaml یا yml باشد. ( docker-compose.yml ) این فایل دقیقا کنار Dockerfile باشد.
اینکه فایل YAML چیه و چه دستوراتی میتونیم داخلش بنویسیم و همینطور سینتکس اون چجوری هستش رو حتما سرچ کنید. اینجا صرفا دستورات پایهای و اصلی مورد نیاز برای وب اپلیکشین جنگو و postgrsql رو مینویسم.
سپس داخل این فایل کدهای زیر را بنویسید:
services: web: build: . command: python manage.py runserver 0.0.0.0:8000 volumes: - .:/code ports: - "8000:8000" environment: - POSTGRES_NAME=postgres - POSTGRES_USER=postgres - POSTGRES_PASSWORD=postgres depends_on: - db
در خط اول کلمه servces برای این است که مشخص کنیم میخواهیم که کدام سرویسها (یا کانتینرها) را میخواهیم اجرا کنیم.
در اینجا ما سرویس وب را میخواهیم اجرا کنیم و در خط دوم web را نوشتم.
در خط بعدی build به Dockerfile اشاره میکنه. و چون docker-compose.yml کنار داکرفایل هستش، میتونیم فقط از . استفاده کنیم ( آدرس دهی در لینوکس به این صورت هستش)
در خط بعدی پورتی که میخواهیم جنگو ازشون استفاده کنه رو مشخص کردم. و با استفاده از command دستور اجرای جنگو رو نوشتم.
در خط بعدی هم آدرس Docker Volume رو مشخص کردم.
در ادامه متغیرهای محلی جنگو را مشخص کردم. اگر با جنگو آشنا باشید به خوبی میدانید معنی هرکدام چی هستش.
سرویس web برای اجرا وابسته به سرویس db هستش و در خط آخر این رو مشخص کردم.
db: image: postgres volumes: - ./data/db:/var/lib/postgresql/data environment: - POSTGRES_DB=postgres - POSTGRES_USER=postgres - POSTGRES_PASSWORD=postgres
در خط اول سرویسی که میخواهیم اجرا بشه رو مشخص کردم.
در خط بعدی مشخص کردم که سرویس db (کانتینر) بر اساس کدوم Docker Image باشه. در خط بعدی آدرس Docker Volume رو مشخص کردم ( این آدرسی است که درصورتی که دیتابیس رو روی لوکال نصب کنید، اطلاعات داخلش ذخیره خواهد شد. بطور سنتی ماهم از همون آدرس استفاده کردیم. شما میتونید هرآدرس دلخواهی استفاده کنید) . سپس متغیرهای محلی دیتابیس رو تعریف کردم. که اگر با جنگو و postgrsql آشنا باشید کاملا میدونید چه متغیرهایی هستند. ( هرچند از روی اسم شون هم مشخص هستش)
در نهایت فایل docker-compose.yml شما باید بصورت زیر باشه:
services: db: image: postgres volumes: - ./data/db:/var/lib/postgresql/data environment: - POSTGRES_DB=postgres - POSTGRES_USER=postgres - POSTGRES_PASSWORD=postgres web: build: . ports: - "8000:8000" command: python manage.py runserver 0.0.0.0:8000 volumes: - .:/majid environment: - POSTGRES_NAME=postgres - POSTGRES_USER=postgres - POSTGRES_PASSWORD=postgres depends_on: - db
با استفاده از دستور زیر میتوانید هر دو کانتینتری که در داخل فایل بالا مشخص کردیم رو همزمان بسازیم و اجرا کنیم ( میتونید داخل فایل بالا چندین سرویس (کانتینر) تعریف کنید):
docker copmpose up
اگر خروجی مشابه خروجی زیر داشتید یعنی همه چی درست نصب و اجرا شده:
با استفاده از دستور docker container ls -a میتونید نام کانتینر مروبط به دیتابیس که ایجاد و اجرا شده رو پیدا کنید. سپس توسط دستور زیر به دیتابیس postgresql متصل بشید:
docker exec -it container-name psql -U postgres
حتما الان سوال میپرسید که پس جنگو چیشد؟ چرا نمیتونیم آدرس ۰.۰.۰.۰:۸۰۰۰ رو روی مرورگر بدرستی ببینیم؟ دلیلش اینه که هنوز فریمورک جنگو رو اجرا نکردید!!!
برای اینکار ۳ راه وجود داره:
docker compose run web django-admin startproject composeexample .
دقت کنید که تنها برای بار اول این دستور رو انجام بدید، در دفعات بعدی باید از دستور docker compose up استفاده کنید.
این دستور به Compose میگه تا با استفاده از imageهای وب سرویس،
دستور django-admin startproject Name را در یک کانتینر اجرا کند. و خب همانطور که داخل فایل docker-compose.yml توضیح دادم، image با استفاده از دستور build ساخته میشه ( که در فایل ما به Dockerfile اشاره میکنه)
توصیه میکنم حتما از روی سایت داکر، دستور docker compose run رو مطالعه کنید تا فرقش رو با دستور docker compose up متوجه بشید. ( همانند دستورات docker create & docker run برای ایجاد و اجرای کانتینر)
۳. بجای استفاده از Dockerfile از base image جنگو استفاده کینم.
البته این راه رو توصیه نمیکنم. چون dependencyهای هر پروژه (requirements.txt) متفاوت هستش. حتی ممکنه شما قصد داشته باشید از ورژن خاصی از پایتون یا جنگو استفاده کنید. پس بهتره برای پروژه جنگو از base image استفاده نکنیم و تمام موارد مورد نیاز رو با استفاده از Dockerfile و requirements.txt مشخص کنیم و image مناسب رو بسازیم.
در انتها بعد از اجرا کردن جنگو، میبایست تنظیمات پیشفرض جنگو رو متناسب با سرویس db که در docker-compose.yml تعریف کردید، تغییر بدید.
# settings.py import os [...] DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': os.environ.get('POSTGRES_NAME'), 'USER': os.environ.get('POSTGRES_USER'), 'PASSWORD': os.environ.get('POSTGRES_PASSWORD'), 'HOST': 'db', 'PORT': 5432, } }
تنها با استفاده از دستور docker compose down میتونید اینکار رو انجام بدید.
اگر به نحوه اجرای دستورات docker compose up و docker build ( در مرحله ۲ توضیحش دادم ) دقت کرده باشید متوجه میشید که هنگام اجرای هر دو دستور Dockerfile هم اجرا میشه و داکر شروع میکنه به ساختن imageای که توسط Dockerfile مشخص کردیم. ( البته در مثال ما چون image یکبار ساخته شده در مرحله بعدی با اینکه داکرفایل اجرا میشه اما image دیگه ساخته نمیشه)
چون هرکانتینر باید از روی یک image ساخته بشه و داخل فایل docker-compose.yml برای سرویس web به وسیله دستور build مشخص کردیم که کانتینر براساس image ای که مشخصاتش داحل Dockerfile هست ساخته بشه.
در پروژه های تجاری و حتی پروژه های کوچک ما قطعا بیش از یک سرویس وجود داره.
مفهوم docker compose برای این بوجود آمده تا بجای اینکه دونه دونه همه کانتینرها رو بسازیم، صرفا با یک دستور همه کانتینرها ایجاد بشن.
پس با ساخت و نوشتن دستورالعملهای مناسب داخل فایل docker-compose.yml میتونیم براحتی همه سرویس ها رو اجرا کنیم.
در صورتی که برای برخی سرویس ها مثل جنگو نیاز داشته باشیم که image مناسب رو خودمون بسازیم تا کانتینر بر اساس اون اجر بشه، تنها با استفاده از Dockerfile و استفاده از دستور build بجای image داخل docker-compose.yml میتونیم اینکار رو انجام بدیم. (پس Dockerfile برای هرپروژه ای لازم نیست)
مثالی که اینجا زدم با استفاده از فریمورک جنگو و postgrSQL بود. شما میتونید هرسرویس دیگری را کاملا مشابه همین مثال با استفاده docker compose بالا بیارید. تنها تفاوتی که وجود خواهد داشت دستورالعمل های داخل docker-compose.yml و فایل Dockerfile ( اگر نیاز داشته باشید به این فایل) خواهد بود.
نکته ای که باید از این پست متوجه بشید اینه که docker-compose.yml و Dockerfile چی هستند. ( البته من سینتکس و بادگیری نوشتن این دو فایل رو توضیح ندادم) و از همه مهتر عملکرد داکر کامپوز به چه صورت هستش.