در این مقاله می خواهم درباره داکر Docker برای مبتدیان صحبت کنم.و در ابتدا با داکر آشنا خواهیم شد و سپس از داکر در پروژه بک اند استفاده خواهیم کرد.ممکن است در اوایل برنامه نویسی با Docker آشنایی چندانی نداشته باشید و فقط در حد شنیدن اسم آن باشد. اما بعد ها متوجه خواهید شد که داکر به دلایل زیر مهم است که درباره آن آشنایی داشته باشید:
- کاهش بار روی RDS در محیط توسعه (عدم استفاده از RDS).
- حذف اثرات مهاجرت بین اعضای تیم (حل مشکل DB مشترک).
- تسریع در راه اندازی محیط توسعه (تسریع در روند ساخت).
- بهبود دردسر راه اندازی مجدد سرور به دلیل تایم اوت های بیکار.
ما DB موجود خود را به یک DB کانتینری منتقل کنم و از docker-compose برای راه اندازی backend و DB استفاده خواهیم کرد.در ابتدا با داکر سپس نحوع استفاده از آن را یاد خواهیم گرفت.
داکر Docker چیست؟
داکر، زیرمجموعه ای از پروژه موبی، یک چارچوب نرم افزاری برای ساخت، اجرا و مدیریت کانتینرها بر روی سرورها و ابر است. اصطلاح "docker" ممکن است به ابزارها (فرمانها و دیمون) یا فرمت فایل Dockerfile اشاره داشته باشد.
قبلاً زمانی که میخواستید یک برنامه وب را اجرا کنید، یک سرور خریداری میکردید، لینوکس را نصب میکردید، یک stack LAMP راهاندازی میکردید و برنامه را اجرا میکردید. اگر برنامه شما محبوب شد، با راهاندازی سرور دوم، تعادل بار را به خوبی انجام دادید تا مطمئن شوید که برنامه در اثر ترافیک زیاد خراب نمیشود.
با این حال، زمان تغییر کرده است، و به جای تمرکز بر روی سرورهای منفرد، اینترنت بر روی آرایههایی از سرورهای وابسته و اضافی در سیستمی ساخته شده است که معمولاً the cloud نامیده میشود. به لطف نوآوری هایی مانند فضاهای نام هسته لینوکس و cgroup ها، مفهوم سرور را می توان از محدودیت های سخت افزاری حذف کرد و در عوض، اساساً به یک نرم افزار تبدیل شد. این سرورهای مبتنی بر نرمافزار کانتینر نامیده میشوند و ترکیبی از سیستمعامل لینوکس هستند که روی آن اجرا میشوند، بهعلاوه یک محیط زمان اجرا بیش از حد محلی.
کانتینرها Containers چیست؟
کانتینرها اغلب با ماشین های مجازی مقایسه می شوند، اما تفاوت های مهمی بین این دو وجود دارد. ماشینهای مجازی یک نسخه کامل از یک سیستم عامل را اجرا میکنند، در حالی که کانتینرها هسته میزبان را با سایر کانتینرها به اشتراک میگذارند. این باعث می شود کانتینرها بسیار سبک تر و کارآمدتر از ماشین های مجازی باشند.
برای شروع، یک کانتینر یک واحد نرم افزار مستقل است که شامل تمام وابستگی های مورد نیاز برای اجرای یک برنامه است. این امر بسته بندی و ارسال برنامه ها را بدون نگرانی در مورد مشکلات سازگاری آسان می کند. کانتینرهای داکر را می توان بر روی هر ماشینی که موتور داکر نصب کرده باشد اجرا کرد.
این کانتینرها از یکدیگر جدا شدهاند و ابزارها، کتابخانهها و فایلهای پیکربندی خود را در کنار هم قرار میدهند و میتوانند از طریق کانالهای کاملاً مشخص با یکدیگر ارتباط برقرار کنند.
فناوری کانتینر را می توان به سه دسته مختلف در نظر گرفت:
Builder: ابزار یا مجموعه ای از ابزارهای مورد استفاده برای ساخت یک کانتینر، مانند distrobuilder برای LXC، یا Dockerfile برای Docker.
Engine: برنامه ای است که برای اجرای یک کانتینر استفاده می شود. برای Docker، این به دستور docker و daemon dockerd اشاره دارد. برای دیگران، این می تواند به دیمون کانتینر و دستورات مربوطه (مانند podman) اشاره کند.
Orchestration: فناوری مورد استفاده برای مدیریت بسیاری از کانتینرها، از جمله Kubernetes و OKD.
کانتینرها اغلب هم یک برنامه کاربردی و هم پیکربندی را ارائه می دهند، به این معنی که یک sysadmin در مقایسه با زمانی که یک برنامه از یک منبع سنتی نصب می شود، نیازی به صرف زمان زیادی برای اجرای یک برنامه در یک کانتینر ندارد. Dockerhub و Quay.io مخازنی هستند که تصاویر را برای استفاده توسط موتورهای کانتینر ارائه می دهند.
1. ایجاد فایل های مرتبط با Docker
ما یک سرویس داریم که شامل چند فرانت اند (/frontend/.
) و بک اند (/backend/.
) می شود، در یک monorepo (فرانت اند React است، بک اند NestJS است).
در حالی که docker-compose به ما امکان میدهد این سرویسها را به طور جمعی راهاندازی کنیم، برخی از فرانتاندها در حال توسعه فعال نیستند، بنابراین در حال حاضر، ما تصمیم گرفتهایم تنها بک اند و DB لازم را در کانتینرهای Docker راهاندازی کنیم.
ایجاد Dockerfile
ابتدا اجازه دهید Dockerfile (Dockerfile.dev)
را برای Backend ایجاد کنیم، به صورت زیر:
FROM node:18.15.0
# Set timezone to Tokyo (IRST)
ENV TZ=Asia/Tehran
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
WORKDIR /app
# Copy package dependencies
COPY package*.json ./
# Ignore prepare script to avoid husky install errors
RUN yarn install --ignore-scripts
EXPOSE 8000
CMD ["yarn", "start:dev"]
منطقه زمانی روی IRST تنظیم شده است زیرا DB موجود (RDS) در IRST پیکربندی شده است. همچنین، در مرحله نصب هاسکی به مشکل خوردیم، بنابراین آن را طوری تنظیم کردهایم که هنگام نصب وابستگیها با Yarn با استفاده از گزینه ignore-scripts--
، اسکریپتها را نادیده بگیرد.
ایجاد docker-compose.yml
سپس فایل docker-compose.yml
را به صورت زیر ایجاد می کنیم. این فایل کانتینرهای backend و DB (MySQL) را مدیریت می کند.
version: "3.9"
services:
backend:
build:
context: ./backend
dockerfile: Dockerfile.dev
ports:
- "3010:3010" # Map local and container ports
depends_on:
- db # Wait for DB service to start
env_file: ./backend/.env # Specify environment variables
volumes:
- ./backend:/app # Map host and container directories
db:
image: mysql:8.0.28
platform: linux/x86_64
container_name: db
env_file: ./backend/.env # Specify environment variables
volumes:
- db-data:/var/lib/mysql # Persist data
ports:
- "3306:3306" # Map local and container ports
command: --default-authentication-plugin=mysql_native_password --sql_mode=NO_ENGINE_SUBSTITUTION
volumes:
db-data: # Define volume to persist DB data
با استفاده از Dockerfile.dev
و docker-compose.yml
که به تازگی ایجاد کرده ایم، اکنون می توانیم بک اند و DB را راه اندازی کنیم.
اگر به یک frontend نیاز دارید، می توانید یک Dockerfile را در /frontend/.
مثل مراحل مشابه بالا ایجاد کنید، و یک سرویس را به docker-compose.yml
اضافه کنید تا این مورد را انجام دهد.
دقت کنید در MySQL، بسته به پیکربندی DB، یک فیلد از نوع DATETIME
بدون مقدار پیشفرض میتواند به طور خودکار روی 0000-00-00 00:00:00
تنظیم شود. با این حال، این پیکربندی در کانتینر DB وجود نداشت و در نتیجه پس از راهاندازی کانتینر خطاهای INSERT
ایجاد شد.
سپس پیکربندی MySQL را به صورت زیر تأیید می کنیم:
SHOW VARIABLES;
هنگام بررسی sql_mode
، تنظیمات مختلفی بین DB کانتینر و DB موجود (RDS) پیدا می شود. بنابراین، sql_mode=NO_ENGINE_SUBSTITUTION--
را به دستور db اضافه کنید.
# Container DB
ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
# Existing DB (RDS)
NO_ENGINE_SUBSTITUTION
دقت کنید که ما در حال مدیریت یک سرویس مونورپو هستیم و فرانتاند را کانتینری نمیکنیم. با این حال، از آنجایی که این احتمال وجود دارد که frontend در آینده کانتینری شود، ما docker-compose.yml
را در فهرست اصلی قرار می دهیم. برای بارگیری backend/Dockerfile.dev/.
، عبارت زیر را انجام داده:
build:
context: ./backend
dockerfile: Dockerfile.dev
ما آن را تنظیم کرده ایم تا تنظیمات اتصال MySQL را از env_file
بخواند: backend/.env/.
.
2. اضافه کردن متغیرهای محیطی
اطلاعات پیکربندی DB را به backend/.env/.
به عنوان Environment Variables (هر مقدار) اضافه کنید.
MYSQL_ROOT_PASSWORD=
MYSQL_DATABASE=
MYSQL_USER=
MYSQL_PASSWORD=
برای مثال:
MYSQL_DATABASE=db_local
MYSQL_USER=admin
3. راه اندازی کانتینر
دستور زیر را در دایرکتوری ریشه اجرا کنید تا چندین کانتینر (بکاند، DB) راهاندازی شود.
$ docker-compose up
4. MySQL Workbench Setup
با استفاده از MySQL Workbench به MySQL DB در Docker متصل شوید.
1.MySQL Workbench را باز کنید.
2.روی دکمه [+] در لیست اتصالات MySQL در سمت چپ صفحه کلیک کنید.
تنظیمات اتصال را به صورت زیر تنظیم کنید:
نام اتصال: هر نام اتصال (مثال: db-local-docker)
نام Hostname (میزبان): localhost (یا آدرس IP میزبانی که Docker در آن اجرا می شود)
پورت: 3306 (شماره پورت در docker-compose.yml
تنظیم شده است)
نام کاربری: MYSQL_USER از backend/.env/.
رمز عبور: MYSQL_PASSWORD از backend/.env/.
3.برای انجام آزمایش اتصال، روی [Test Connection] کلیک کنید. اگر مشکلی وجود ندارد، برای ذخیره اتصال روی [OK] کلیک کنید.
5. استخراج کردن Dump از دیتابیس موجود
Dump (اطلاعات و داده های جدول) را از RDS برای MySQL DB که در محیط توسعه دهنده استفاده می شود، استخراج کنید.
شما از پورت ماشین محلی (<local_port>
) از طریق یک سرور پرش (<ssh_user>@<remote_server_ip>
) به پورت RDS (<remote_database_port>
) (تونل SSH) متصل خواهید شد.
برای جلوگیری از تداخل پورت، مانند زمانی که MySQL از قبل روی ماشین محلی در حال اجرا است، این بار از پورت های مختلف برای local_port
و remote_database_port
استفاده خواهیم کرد.
$ ssh -f -N -L <local_port>:<remote_database_url>:<remote_database_port> -i <path_to_your_ssh_key> <ssh_user>@<remote_server_ip>
local_port
: پورتی که میخواهید در دستگاه محلی خود باز کنید (به عنوان مثال، 3307)remote_database_url
: این URL دیتابیس راه دور است(به عنوان مثال database.db.coedadadas22.ap-northeast-1.rds.amazonaws.com)remote_database_port
: پورتی که توسط دیتابیس راه دور استفاده می شود (به عنوان مثال، 3306)path_to_your_ssh_key
: مسیر به کلید SSH شما (به عنوان مثال، ~/.ssh/db-pem-key.pem)ssh_user
: نام کاربری مورد استفاده برای اتصال به سرور راه دور (به عنوان مثال، ec2-user)remote_server_ip
: آدرس IP سرور راه دور (به عنوان مثال، 54.168.32.10)
شما به پورت (<local_port>
) لوکال هاست متصل خواهید شد و تمام نام جدول DB مربوطه (<database_name>
) را روی RDS در یک فایل متنی (<output_file>
) می نویسید.
$ mysql -h <localhost_ip> -P <local_port> -u <username> -p <database_name> -e 'show tables' | tail -n +2 > <output_file>
localhost_ip
: آدرس IP میزبانی که کلاینت MySQL در آن اجرا می شود (به عنوان مثال، 127.0.0.1)local_port
: پورت دستگاه محلی شما برای دسترسی به دیتابیس راه دور از طریق ارسال پورت SSH (به عنوان مثال، 3307)username
: نام کاربری مورد استفاده برای اتصال به دیتابیس (به عنوان مثال، مدیر)database_name
: نام دیتابیس ای که به آن متصل می شوید (به عنوان مثال db-prod)output_file
: نام فایل برای ذخیره نام جدول به دست آمده از دیتابیس (به عنوان مثال، all_tables.txt)
دیتابیس را بر اساس لیست جداولی که می خواهید صادر کنید، تخلیه کنید.
$ mysqldump -h <localhost_ip> -P <local_port> -u <username> -p <database_name> $(cat <tables_list_file>) > <output_file>
localhost_ip
: آدرس IP میزبان دیتابیس (به عنوان مثال، 127.0.0.1)local_port
: پورتی که دیتابیس به آن گوش می دهد (به عنوان مثال، 3307)username
: نام کاربری برای اتصال به دیتابیس (به عنوان مثال، مدیر)database_name
: نام دیتابیس برای ایجاد یک Dump از (به عنوان مثال، db-prod)tables_list_file
: فایل حاوی لیست جداول برای ایجاد یک Dump از (به عنوان مثال، all_tables.txt)output_file
: نام فایل برای ذخیره خروجی (فایل dump) (به عنوان مثال database_export.sql)
6. وارد کردن Dump به دیتابیس کانتینر
ما Dump را از MySQL Workbench به دیتابیس کانتینر وارد می کنیم.
1.MySQL Workbench را باز کنید.
2.از صفحه اصلی روی اتصال دیتابیس ای که می خواهید به آن متصل شوید کلیک کنید.
3.هنگامی که اتصال دیتابیس باز شد، "Server" -> "Data Import" را از نوار منو انتخاب کنید.
4.هنگامی که صفحه "Data Import" ظاهر شد، "Import from Self-Contained File" را انتخاب کنید، سپس روی دکمه "..." در سمت راست کلیک کنید تا فایل SQL مورد نظر برای وارد کردن را انتخاب کنید.
5.دیتابیس مقصد را برای وارد کردن از منوی کشویی "Default Target Schema" انتخاب کنید.
6.روی دکمه "Start Import" در بخش "Import Progress" کلیک کنید.
و تمام.
خلاصه
ما در این مقاله با بررسی داکر و نحوه استفاده از آن در پروژه بک اند را یاد گرفتیم و دلیل استفاده از این کار کاهش بار روی RDS در محیط توسعه ، حل مشکل DB مشترک ،تسریع در راه اندازی محیط توسعه و بهبود دردسر راه اندازی مجدد سرور به دلیل تایم اوت های بیکار می باشد.