مدیریت سرور

نحوه نصب و راه اندازی لاراول با Docker Compose در اوبونتو ۲۰.۰۴

برای آموختن نحوه نصب و راه اندازی لاراول با داکر در اوبونتو 20.04 تا انتهای این مقاله با ما همراه باشید.

کانتینری کردن یک برنامه به فرآیند تطبیق یک برنامه کاربردی و اجزای آن اشاره دارد تا بتوان آن را در محیط های سبک وزن به نام کانتینر اجرا کرد. چنین محیط هایی ایزوله و یکبار مصرف هستند و می توان از آنها برای توسعه، آزمایش و استقرار برنامه های کاربردی در تولید استفاده کرد.

در این مقاله، ما از Docker Compose برای کانتینری کردن یک برنامه لاراول برای توسعه استفاده خواهیم کرد. وقتی کارتان تمام شد، یک برنامه آزمایشی لاراول خواهید داشت که روی سه کانتینر سرویس مجزا اجرا می شود:

یک سرویس برنامه که PHP7.4-FPM را اجرا می کند.
یک سرویس db که MySQL 5.7 را اجرا می کند.
یک سرویس nginx که از سرویس برنامه برای تجزیه کد PHP قبل از ارائه برنامه لاراول به کاربر نهایی استفاده می کند.

برای اجازه دادن به فرآیند توسعه ساده و تسهیل اشکال‌زدایی برنامه، ما فایل‌های برنامه را با استفاده از حجم‌های مشترک همگام نگه می‌داریم. همچنین نحوه استفاده از دستورات exec docker-compose را برای اجرای Composer و Artisan در کانتینر برنامه را خواهیم دید.

مرحله ۱ – دریافت برنامه آزمایشی

برای شروع، ما برنامه آزمایشی Laravel را از مخزن Github آن دریافت می کنیم.

برای به دست آوردن کد برنامه سازگار با این آموزش، Release tutorial-1.0.1 را در دایرکتوری خود با استفاده از دستور زیر دانلود کنید.

cd ~
curl -L https://github.com/do-community/demo-laravel-demo/archive/tutorial-1.0.1.zip -o demo.zip

برای باز کردن کد برنامه به دستور unzip نیاز داریم. اگر قبلاً این بسته را نصب نکرده اید، اکنون این کار را با دستور زیر انجام دهید.

sudo apt update
sudo apt install unzip

اکنون، محتویات برنامه را از حالت فشرده خارج کرده و برای دسترسی آسان تر، دایرکتوری را تغییر نام دهید.

unzip demo.zip
mv demo-laravel-demo-tutorial-1.0.1 demo-website

با اجرای دستور زیر به دایرکتوری جدید بروید.

cd demo-website

در مرحله بعد، یک فایل پیکربندی env برای راه اندازی برنامه ایجاد می کنیم.

مرحله ۲ – تنظیم فایل env برنامه

فایل های پیکربندی لاراول در دایرکتوری به نام config در داخل دایرکتوری روت برنامه قرار دارند. علاوه بر این، یک فایل env برای تنظیم پیکربندی های وابسته به محیط، مانند اعتبارنامه ها و هر گونه اطلاعاتی که ممکن است بین نسخه ها متفاوت باشد، استفاده می شود. این فایل در کنترل بازبینی گنجانده نشده است.

هشدار: فایل پیکربندی محیط حاوی اطلاعات حساس در مورد سرور شما، از جمله اعتبار پایگاه داده و کلیدهای امنیتی است. به همین دلیل، هرگز نباید این فایل را به صورت عمومی به اشتراک بگذارید.

مقادیر موجود در فایل env بر مقادیر تنظیم شده در فایل های پیکربندی معمولی که در دایرکتوری پیکربندی قرار دارند، اولویت دارند. هر نصب در یک محیط جدید به یک فایل محیطی متناسب نیاز دارد تا مواردی مانند تنظیمات اتصال پایگاه داده، گزینه های اشکال زدایی، URL برنامه و موارد دیگری که ممکن است بسته به محیطی که برنامه اجرا می شود متفاوت باشد، تعریف کند.

اکنون یک فایل env جدید ایجاد می‌کنیم تا گزینه‌های پیکربندی را برای محیط توسعه که در حال تنظیم هستیم سفارشی کنیم. لاراول با یک فایل example.env ارائه می‌شود که می‌توانیم آن را برای ایجاد فایل خود کپی کنیم.

cp .env.example .env

این فایل را با استفاده از nano یا ویرایشگر متن دلخواه خود باز کنید:

nano .env

فایل env فعلی از برنامه آزمایشی ما حاوی تنظیماتی برای استفاده از پایگاه داده محلی MySQL با ۱۲۷.۰.۰.۱ به عنوان میزبان پایگاه داده است. ما باید متغیر DB_HOST را به روز کنیم تا به سرویس پایگاه داده ای که در محیط Docker خود ایجاد خواهیم کرد اشاره کند. در این راهنما، ما سرویس پایگاه داده خود را db می نامیم. مقدار فهرست شده DB_HOST را با نام سرویس پایگاه داده جایگزین کنید:

APP_NAME=demo website
APP_ENV=dev
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost:8000

LOG_CHANNEL=stack

DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=demo
DB_USERNAME=demo_user
DB_PASSWORD=password
 ...

در صورت تمایل می توانید نام پایگاه داده، نام کاربری و رمز عبور را نیز تغییر دهید. این متغیرها در مرحله بعد مورد استفاده قرار می گیرند، جایی که ما فایل docker-compose.yml را برای پیکربندی سرویس های خود راه اندازی می کنیم.

پس از اتمام ویرایش فایل را ذخیره کنید. اگر از نانو استفاده می‌کنید، می‌توانید این کار را با فشار دادن Ctrl+x و سپس Y و Enter برای تأیید انجام دهید.

مرحله ۳ – راه اندازی Dockerfile برنامه

اگرچه هر دو سرویس MySQL و Nginx ما بر اساس تصاویر پیش‌فرض به‌دست‌آمده از Docker Hub خواهند بود، ما هنوز باید یک تصویر سفارشی برای کانتینر برنامه بسازیم که یک Dockerfile جدید برای آن ایجاد خواهیم کرد.

تصویر ما بر اساس تصویر رسمی PHP php:7.4-fpm از Docker Hub خواهد بود. بر روی این محیط اولیه PHP-FPM، ما چند ماژول اضافی PHP و ابزار مدیریت وابستگی Composer را نصب خواهیم کرد.

ما همچنین یک کاربر سیستم جدید ایجاد خواهیم کرد. این مورد برای اجرای دستورات artisan و composer در حین توسعه برنامه ضروری است. تنظیم uid تضمین می‌کند که کاربر داخل کانتینر همان uid کاربر سیستم شما را در دستگاه میزبان شما، یعنی جایی که Docker را اجرا می‌کنید، داشته باشد. به این ترتیب، هر فایلی که توسط این دستورات ایجاد می شود، با مجوزهای صحیح در هاست کپی می شود. همچنین به این معنی است که شما می توانید از ویرایشگر کد انتخابی خود در دستگاه میزبان برای توسعه برنامه ای که در داخل کانتینرها اجرا می شود استفاده کنید.

یک Dockerfile جدید با دستور زیر ایجاد نمایید.

nano Dockerfile

مطالب زیر را در Dockerfile خود کپی کنید.

FROM php:7.4-fpm

# Arguments defined in docker-compose.yml
ARG user
ARG uid

# Install system dependencies
RUN apt-get update && apt-get install -y \
    git \
    curl \
    libpng-dev \
    libonig-dev \
    libxml2-dev \
    zip \
    unzip

# Clear cache
RUN apt-get clean && rm -rf /var/lib/apt/lists/*

# Install PHP extensions
RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd

# Get latest Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer

# Create system user to run Composer and Artisan Commands
RUN useradd -G www-data,root -u $uid -d /home/$user $user
RUN mkdir -p /home/$user/.composer && \
    chown -R $user:$user /home/$user

# Set working directory
WORKDIR /var/www

USER $user

فراموش نکنید که پس از اتمام کار، فایل را ذخیره کنید.

Dockerfile ما با تعریف تصویر پایه ای که استفاده می کنیم شروع می شود: php: 7.4-fpm.

پس از نصب بسته های سیستمی و پسوندهای PHP، Composer را با کپی کردن فایل اجرایی composer از آخرین تصویر رسمی آن در تصویر برنامه خودمان نصب می کنیم.

سپس یک کاربر سیستم جدید با استفاده از آرگومان های user و uid که در ابتدای Dockerfile اعلام شده بودند ایجاد و راه اندازی می شود. این مقادیر در زمان ساخت توسط Docker Compose تزریق خواهند شد.

در نهایت، دایرکتوری(dir) کاری پیش فرض را به صورت /var/www تنظیم می کنیم و به کاربر تازه ایجاد شده تغییراتی اعمال می‌کنیم. این مورد اطمینان حاصل می کند که به عنوان یک کاربر معمولی متصل می شوید و هنگام اجرای دستورات composer و artisan در کانتینر برنامه، در دایرکتوری مناسبی هستید.

مرحله ۴ – تنظیم Nginx پیکربندی و فایل های تخلیه پایگاه داده

هنگام ایجاد محیط‌های توسعه با Docker Compose، اغلب لازم است فایل‌های پیکربندی یا مقداردهی اولیه را با کانتینرهای سرویس به اشتراک بگذارید تا آن سرویس‌ها را راه‌اندازی کنید. این کار ایجاد تغییرات در فایل های پیکربندی را برای تنظیم دقیق محیط خود در حین توسعه برنامه تسهیل می کند.

اکنون یک پوشه با فایل‌هایی راه‌اندازی می‌کنیم که برای پیکربندی و مقداردهی اولیه کانتینرهای سرویس ما استفاده می‌شود.

برای راه اندازی Nginx، یک فایل demo.conf را به اشتراک می گذاریم که نحوه ارائه برنامه را پیکربندی می کند. پوشه docker-compose/nginx را با استفاده از دستور زیر اجرا نمایید.

mkdir -p docker-compose/nginx

یک فایل جدید به نام demo.conf در آن دایرکتوری باز کنید.

nano docker-compose/nginx/demo.conf

پیکربندی Nginx زیر را در آن فایل کپی کنید:

server {
    listen 80;
    index index.php index.html;
    error_log  /var/log/nginx/error.log;
    access_log /var/log/nginx/access.log;
    root /var/www/public;
    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass app:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
    location / {
        try_files $uri $uri/ /index.php?$query_string;
        gzip_static on;
    }
}

این فایل Nginx را برای گوش دادن به پورت ۸۰ پیکربندی می کند و از index.php به عنوان صفحه فهرست پیش فرض استفاده می کند. روت سند را روی /var/www/public تنظیم می کند و سپس Nginx را برای استفاده از سرویس برنامه در پورت ۹۰۰۰ برای پردازش فایل های php پیکربندی می کند.

پس از اتمام ویرایش فایل را ذخیره کرده و ببندید.

یک پوشه جدید برای فایل های اولیه MySQL خود در داخل پوشه docker-compose ایجاد کنید.

mkdir docker-compose/mysql

یک فایل sql جدید باز کنید:

nano docker-compose/mysql/init_db.sql

کد زیر را به فایل اضافه کنید.

DROP TABLE IF EXISTS `places`;

CREATE TABLE `places` (
  `id` bigint(۲۰) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(۲۵۵) COLLATE utf8mb4_unicode_ci NOT NULL,
  `visited` tinyint(۱) NOT NULL DEFAULT '۰',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=۱۲ DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

INSERT INTO `places` (name, visited) VALUES ('Berlin',۰),('Budapest',۰),('Cincinnati',۱),('Denver',۰),('Helsinki',۰),('Lisbon',۰),('Moscow',۱),('Nairobi',۰),('Oslo',۱),('Rio',۰),('Tokyo',۰);

پس از اتمام، فایل را ذخیره کرده و ببندید.

ما راه اندازی Dockerfile برنامه و فایل های پیکربندی سرویس را به پایان رساندیم. در مرحله بعد، Docker Compose را برای استفاده از این فایل‌ها هنگام ایجاد سرویس‌هایمان راه‌اندازی می‌کنیم.

مرحله ۵ – ایجاد یک محیط چند کانتینره با Docker Compose

Docker Compose شما را قادر می سازد تا محیط های چند کانتینری را برای برنامه های در حال اجرا در Docker ایجاد کنید. از تعاریف سرویس برای ساخت محیط های کاملاً قابل تنظیم با کانتینرهای متعدد استفاده می کند که می توانند شبکه ها و حجم داده ها را به اشتراک بگذارند. این امکان یکپارچگی بین اجزای برنامه را فراهم می کند.

برای تنظیم تعاریف سرویس خود، یک فایل جدید به نام docker-compose.yml ایجاد می کنیم. به طور معمول، این فایل در روت پوشه برنامه قرار دارد و محیط کانتینری شده شما را تعریف می کند، از جمله تصاویر پایه ای که برای ساخت کانتینرها استفاده می کنید و نحوه تعامل سرویس های شما.

ما سه سرویس مختلف را در فایل docker-compose.yml خود تعریف خواهیم کرد: app، db و nginx.

سرویس برنامه یک تصویر به نام فهرست سفر را بر اساس Dockerfile که قبلاً ایجاد کرده‌ایم می‌سازد. ظرف تعریف شده توسط این سرویس یک سرور php-fpm را برای تجزیه کد PHP اجرا می کند و نتایج را به سرویس nginx که در یک کانتینر جداگانه اجرا می شود، ارسال می کند. سرویس mysql محفظه ای را تعریف می کند که سرور MySQL 5.7 را اجرا می کند. خدمات ما یک شبکه پل به نام demo را به اشتراک خواهند گذاشت.

یک فایل docker-compose.yml جدید در روت پوشه برنامه ایجاد کنید.

nano docker-compose.yml

یک فایل docker-compose.yml معمولی با یک تعریف نسخه شروع می شود و به دنبال آن یک گره خدمات، که تحت آن همه سرویس ها تعریف می شوند، شروع می شود. شبکه های اشتراکی معمولاً در پایین آن فایل تعریف می شوند.

برای شروع، این کد boilerplate را در فایل docker-compose.yml خود کپی کنید:

version: "3.7"
services:


networks:
  demo:
     driver: bridge

اکنون گره خدمات را ویرایش می کنیم تا شامل برنامه، خدمات db و nginx شود.

سرویس app:

سرویس app یک بخش با نام demo-app راه اندازی می کند. این یک تصویر Docker جدید بر اساس یک Dockerfile می‌سازد که در همان مسیر فایل docker-compose.yml قرار دارد. تصویر جدید به صورت محلی تحت نام لیست دمو ذخیره خواهد شد.

حتی اگر ریشه سندی که به عنوان برنامه ارائه می‌شود در nginx قرار دارد، ما به فایل‌های برنامه در جایی داخل کانتینر برنامه نیز نیاز داریم، بنابراین می‌توانیم وظایف خط فرمان را با ابزار Laravel Artisan اجرا کنیم.

تعریف سرویس زیر را در گره خدمات خود، در داخل فایل docker-compose.yml کپی کنید.

  app:
    build:
      args:
        user: sammy
        uid: 1000
      context: ./
      dockerfile: Dockerfile
    image: demo
    container_name: demo-app
    restart: unless-stopped
    working_dir: /var/www/
    volumes:
      - ./:/var/www
    networks:
      - demo

این تنظیمات موارد زیر را انجام می دهند:

build: این پیکربندی به Docker Compose می‌گوید که با استفاده از مسیر مشخص شده و Dockerfile برای دستورالعمل‌ها، یک تصویر محلی برای سرویس برنامه بسازد. آرگومان‌های user و uid به Dockerfile تزریق می‌شوند تا دستورات ایجاد کاربر را در زمان ساخت سفارشی‌سازی کنند.
image: نامی که برای تصویر در حال ساخت استفاده می شود.
Container_name: نام کانتینر را برای این سرویس تنظیم می کند.
راه اندازی مجدد: تعیین می‌کند که سرویس همیشه راه اندازی مجدد شود، مگر اینکه سرویس متوقف شود.
working_dir: دایرکتوری پیش فرض این سرویس را به صورت /var/www تنظیم می کند.
volumes: یک حجم مشترک ایجاد می کند که محتویات دایرکتوری فعلی را با /var/www داخل ظرف همگام می کند. توجه داشته باشید که این ریشه سند شما نیست، زیرا در ظرف nginx زندگی می کند.
شبکه ها: این سرویس را برای استفاده از شبکه ای به نام demo تنظیم می کند.

سرویس db:

سرویس db از تصویر MySQL 5.7 از پیش ساخته شده از Docker Hub استفاده می کند. از آنجایی که Docker Compose به طور خودکار فایل‌های متغیر env را که در همان دایرکتوری فایل docker-compose.yml قرار دارد بارگیری می‌کند، می‌توانیم تنظیمات پایگاه داده خود را از فایل Laravel.env که در مرحله قبل ایجاد کردیم، دریافت کنیم.

دقیقاً بعد از سرویس برنامه، تعریف سرویس زیر را در گره خدمات خود بگنجانید:

  db:
    image: mysql:5.7
    container_name: demo-db
    restart: unless-stopped
    environment:
      MYSQL_DATABASE: ${DB_DATABASE}
      MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
      MYSQL_PASSWORD: ${DB_PASSWORD}
      MYSQL_USER: ${DB_USERNAME}
      SERVICE_TAGS: dev
      SERVICE_NAME: mysql
    volumes:
      - ./docker-compose/mysql:/docker-entrypoint-initdb.d
    networks:
      - demo

این تنظیمات موارد زیر را انجام می دهند:

image: تصویر Docker را که باید برای این کانتینر استفاده شود را تعریف می کند. در این مورد، ما از یک تصویر MySQL 5.7 از Docker Hub استفاده می کنیم.
container_name: نام کانتینر را برای این سرویس تنظیم می کند: demo-db.
راه اندازی مجدد: همیشه این سرویس را راه اندازی مجدد کنید، مگر اینکه صراحتاً متوقف شده باشد.
محیط: متغیرهای محیطی را در ظرف جدید تعریف می کند. ما از مقادیر به دست آمده از فایل Laravel .env برای راه اندازی سرویس MySQL خود استفاده می کنیم که به طور خودکار یک پایگاه داده و کاربر جدید را بر اساس متغیرهای محیط ارائه شده ایجاد می کند.
volumes: حجمی را برای به اشتراک گذاری پایگاه داده sql ایجاد می کند که برای مقداردهی اولیه پایگاه داده برنامه استفاده می شود. تصویر MySQL به طور خودکار فایل‌های sql را که در پوشه /docker-entrypoint-initdb.d داخل کانتینر قرار دارند وارد می‌کند.
شبکه ها: این سرویس را برای استفاده از شبکه ای به نام Demo تنظیم می کند.

سرویس nginx

سرویس nginx از یک تصویر Nginx از پیش ساخته شده در بالای Alpine، یک توزیع سبک وزن لینوکس استفاده می کند. یک کانتینری به نام demo-nginx ایجاد می‌کند و از تعریف پورت‌ها برای ایجاد تغییر مسیر از پورت ۸۰۰۰ در سیستم میزبان به پورت ۸۰ در داخل کانتینر استفاده می‌کند.

دقیقاً بعد از سرویس db، تعریف سرویس زیر را در گره خدمات خود بگنجانید:

 nginx:
image: nginx:1.17-alpine
container_name: demo-nginx
restart: unless-stopped
ports:
  - ۸۰۰۰:۸۰
volumes:
  - ./:/var/www
  - ./docker-compose/nginx:/etc/nginx/conf.d
networks:
 - demo

این تنظیمات موارد زیر را انجام می دهند:

image: تصویر Docker را که باید برای این کانتینر استفاده شود را تعریف می کند. در این مورد، ما از تصویر Alpine Nginx 1.17 استفاده می کنیم.
container_name: نام کانتینر را برای این سرویس تنظیم می کند: demo-nginx.
راه اندازی مجدد: همیشه این سرویس را راه اندازی مجدد کنید، مگر اینکه صراحتاً متوقف شده باشد.
پورت ها: یک تغییر مسیر پورت را تنظیم می کند که امکان دسترسی خارجی از طریق پورت ۸۰۰۰ به وب سرور در حال اجرا بر روی پورت ۸۰ را در داخل ظرف فراهم می کند.
volumes: دو جلد مشترک ایجاد می کند. اولی محتویات دایرکتوری فعلی را با /var/www داخل ظرف همگام می کند. به این ترتیب، هنگامی که تغییرات محلی در فایل های برنامه ایجاد می کنید، به سرعت در برنامه ای که توسط Nginx در داخل کانتینر ارائه می شود منعکس می شوند. جلد دوم مطمئن می شود که فایل پیکربندی Nginx ما، واقع در docker-compose/nginx/demo.conf، در پوشه پیکربندی Nginx ظرف کپی شده است.
شبکه ها: این سرویس را برای استفاده از شبکه ای به نام Demo تنظیم می کند.

پیکربندی فایل docker-compose.yml تمام شد.

مرحله ۶ – اجرای برنامه با Docker Compose
اکنون از دستورات docker-compose برای ساختن تصویر برنامه و اجرای سرویس هایی که در تنظیمات خود مشخص کرده ایم استفاده می کنیم.

با دستور زیر تصویر برنامه را بسازید:

docker-compose build app

تکمیل این دستور ممکن است چند دقیقه طول بکشد.

پس از اتمام ساخت، می توانید محیط را در حالت پس زمینه با استفاده از اجرا نمایید:

docker-compose up -d

با این کار کانتینرهای شما در پس زمینه اجرا می شود. برای نمایش اطلاعات در مورد وضعیت سرویس های فعال خود، دستور زیر را اجرا کنید:

docker-compose ps

محیط شما اکنون آماده و در حال اجرا است، اما ما هنوز باید چند دستور را اجرا کنیم تا راه اندازی برنامه را به پایان برسانیم. می‌توانید از دستور docker-compose exec برای اجرای دستورات در کانتینرهای سرویس استفاده کنید، مانند یک ls -l برای نشان دادن اطلاعات دقیق درباره فایل‌ها در فهرست برنامه:

docker-compose exec app ls -l

اکنون composer install را برای نصب برنامه‌های وابسته اجرا می کنیم:

docker-compose exec app composer install

آخرین کاری که باید قبل از آزمایش برنامه انجام دهیم، تولید یک کلید کاربردی منحصر به فرد با ابزار خط فرمان لاراول است. این کلید برای رمزگذاری نشست‌های کاربر و سایر داده های حساس استفاده می شود:

docker-compose exec app php artisan key:generate

اکنون به مرورگر خود بروید و به نام دامنه یا آدرس IP سرور خود در پورت ۸۰۰۰ دسترسی پیدا کنید:

http://server_domain_or_IP:8000
توجه: اگر این نسخه آزمایشی را روی دستگاه محلی خود اجرا می کنید، از http://localhost:8000 برای دسترسی به برنامه از مرورگر خود استفاده کنید.

 

می توانید از دستور logs برای بررسی گزارش های تولید شده توسط سرویس های خود استفاده کنید:

docker-compose logs nginx

اگر می‌خواهید محیط Docker Compose خود را با حفظ وضعیت همه سرویس‌های آن متوقف کنید، دستور زیر را اجرا کنید:

docker-compose pause

با استفاده از دستور زیر می توانید خدمات خود را از سر بگیرید:

docker-compose unpause

برای خاموش کردن محیط Docker Compose و حذف همه کانتینرها، شبکه‌ها و حجم‌های آن، دستور زیر را اجرا کنید:

docker-compose down

 

در این راهنما، ما یک محیط Docker با سه کانتینر با استفاده از Docker Compose برای تعریف زیرساخت خود در یک فایل YAML راه‌اندازی کرده‌ایم.

از این مرحله به بعد، می توانید بدون نیاز به نصب و راه اندازی وب سرور محلی برای توسعه و آزمایش، روی برنامه لاراول خود کار کنید. علاوه بر این، شما با یک محیط کار خواهید کرد که می تواند به راحتی تکرار و توزیع شود، که می تواند در هنگام توسعه برنامه شما و همچنین هنگام حرکت به سمت یک محیط تولید مفید باشد.

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

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

نشانی ایمیل شما منتشر نخواهد شد.