برنامه نویسی

Docker برای مبتدیان: ایجاد محیط توسعه Backend شما

من در حال حاضر در یک استارت‌آپ در مراحل اولیه کار می‌کنم که در آن به قدری روی جنبه تهاجمی چیزها، مانند توسعه ویژگی‌های جدید تمرکز کرده‌ایم، که از دفاع خود، یعنی آزمایش غفلت کرده‌ایم.

به طور خاص، ما هنوز محیط توسعه خود را محدود نکرده‌ایم، و به همان DB (RDS) در توسعه‌دهنده و محلی ارجاع می‌دهیم، که باعث ایجاد موانع قابل‌توجهی برای توسعه تیم می‌شود – بله، این تا حدودی کمدی از خطاها است.

من که در درجه اول مسئول بخش مقدماتی و هوش مصنوعی بودم، با Docker آشنایی چندانی نداشتم. با این حال، متوجه شدم که برای جلوگیری از از هم پاشیدن توسعه تیم ما، معرفی Docker به محیط توسعه ما به یک ضرورت تبدیل شده است. در اینجا اهداف اصلی این تصمیم وجود دارد:

  1. کاهش بار روی RDS در محیط توسعه (عدم استفاده از RDS).
  2. حذف اثرات مهاجرت بین اعضای تیم (حل مشکل DB مشترک).
  3. تسریع در راه اندازی محیط توسعه (تسریع در روند ساخت و ساز).
  4. بهبود دردسر راه اندازی مجدد سرور به دلیل تایم اوت های بیکار.

من تصمیم گرفته ام که DB موجود خود را به یک DB کانتینری منتقل کنم و از docker-compose برای راه اندازی backend و DB استفاده کنم. من روش را در زیر شرح داده ام. بیایید داکر را در آغوش بگیریم و کمی هماهنگی را به روند توسعه تیم خود بازگردانیم!

1. ایجاد فایل های مرتبط با Docker

ما در حال مدیریت خدمات خود هستیم که شامل چندین فرانت اند (./frontend/) و باطن (./backend/)، در monorepo (فرانت اند React است، بک اند NestJS است).

در حالی که docker-compose به ما امکان می‌دهد این سرویس‌ها را به طور جمعی راه‌اندازی کنیم، برخی از فرانت‌اندها در حال توسعه فعال نیستند، بنابراین در حال حاضر، ما تصمیم گرفته‌ایم تنها باطن و DB لازم را در کانتینرهای Docker راه‌اندازی کنیم.

ایجاد Dockerfile

ابتدا اجازه دهید Dockerfile را ایجاد کنیم (Dockerfile.dev) برای باطن، به شرح زیر است.

FROM node:18.15.0

# Set timezone to Tokyo (JST)
ENV TZ=Asia/Tokyo
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"]
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

منطقه زمانی روی JST تنظیم شده است زیرا DB موجود (RDS) در JST پیکربندی شده است. همچنین، ما مشکلی با شکست مرحله نصب هاسکی داشتیم، بنابراین آن را طوری تنظیم کرده‌ایم که هنگام نصب وابستگی‌ها با 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 برای تطبیق این.

یادداشت 1

در 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 command.

# 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
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

تبصره 2

پس از راه‌اندازی کانتینر، تغییرات در قسمت پشتیبان بارگیری مجدد نشدند. لذا اضافه کردم ./backend:/app به حجم های باطن، نقشه برداری از فهرست هاست و کانتینر.

نکته 3

قبلاً اشاره کردم که ما در حال مدیریت یک سرویس مونورپو هستیم و فرانت‌اند را کانتینری نمی‌کنیم. با این حال، از آنجایی که این احتمال وجود دارد که frontend در آینده کانتینری شود، من آن را قرار دادم docker-compose.yml در دایرکتوری ریشه برای بارگذاری ./backend/Dockerfile.dev، این جمله را بیان کردم:

build:
  context: ./backend
  dockerfile: Dockerfile.dev
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

من آن را برای خواندن تنظیمات اتصال MySQL تنظیم کرده ام env_file: ./backend/.env.

2. اضافه کردن متغیرهای محیطی

اطلاعات پیکربندی DB را به آن اضافه کنید ./backend/.env به عنوان متغیرهای محیطی (هر مقدار).

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 در سمت چپ صفحه را فشار دهید.
  3. تنظیمات اتصال را به صورت زیر تنظیم کنید:
    • نام اتصال: هر نام اتصال (مثال: db-local-docker)
    • نام میزبان: localhost (یا آدرس IP میزبانی که Docker در آن اجرا می شود)
    • بندر: 3306 (شماره پورت تنظیم شده است docker-compose.yml)
    • نام کاربری: MYSQL_USER از ./backend/.env
    • رمز عبور: MYSQL_PASSWORD از ./backend/.env
  4. کلیک [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)
  • نام کاربری: نام کاربری مورد استفاده برای اتصال به پایگاه داده (مثلاً admin)
  • 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)
  • نام کاربری: نام کاربری برای اتصال به پایگاه داده (مثلاً مدیر)
  • 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. هنگامی که صفحه “واردات داده” ظاهر می شود، “Import from Self-Contained File” را انتخاب کنید، سپس روی دکمه “…” در سمت راست کلیک کنید تا فایل SQL را که می خواهید وارد کنید انتخاب کنید.
  5. پایگاه داده مقصد را برای وارد کردن از منوی کشویی “Default Target Schema” انتخاب کنید.
  6. روی دکمه “شروع واردات” در بخش “پیشرفت واردات” کلیک کنید.

توضیحات تصویر

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا