اجرای دستور های npm با داکر و آشنایی با عبارت ENTRYPOINT

اجرای دستور های npm با داکر و آشنایی با عبارت ENTRYPOINT

در قسمت قبل دیدیم که چگونه می توان از docker compose و یک کانتینر composer استفاده کرد تا دستور‌های آن را بدون نیاز به نصب نرم افزار، در سیستم میزبان اجرا کنیم. همین کار را می توان برای npm و artisan هم انجام داد. به عبارت دیگر بدون نصب node و PHP در سیستم خودمان، دستور های npm و artisan را می توانیم اجرا کنیم. 

فایل docker-compose.yml مان را ویرایش کرده و بخش npm را اضافه می کنیم.

version: '3.8'

services:
  nginx:
    build:
      context: .
      dockerfile: nginx.dockerfile
    ports:
      - 80:80
    volumes:
      - ./src:/var/www/html
    depends_on:
      - mysql
      - php
  mysql:
    image: mysql:5.7
    ports:
      - 3306:3306
    environment:
      MYSQL_DATABASE: sokanacademy
      MYSQL_USER: sokanacademy
      MYSQL_PASSWORD: secret
      MYSQL_ROOT_PASSWORD: secret
    volumes:
      - ./mysql:/var/lib/mysql
  php:
    build:
      context: .
      dockerfile: php.dockerfile
    volumes:
      - ./src:/var/www/html
  composer:
    image: composer:2
    volumes:
      - ./src:/var/www/html
    working_dir: /var/www/html
  npm:
    image: node:current-alpine
    volumes: 
      - ./src/var/www/html

یک سرویس با نام npm اضافه کردیم که از ایمیج node:current-alpine ساخته می شود.

مانند سایر کانتینر ها مسیر پروژه را به عنوان volume مشخص کردیم.

ایمیج node به صورت پیش فرض دستور npm را اجرا نمی کند اما تغییر این پیش فرض کار ساده ای است. این کار را با استفاده از برچسب entrypoint انجام می دهیم. اما عبارت entrypoint به چه معناست؟

ENTRYPOINT در dockerfile چیست؟

به طور معمول هر dockerfile ای که نوشته می شود یک هدف مشخص را دنبال می کند. با کمک عبارت ENTRYPOINT در dockerfile، دستور اصلی ای که توسط کانتینر داکر اجرا می شود را مشخص می کنیم. به بیان دیگر، کاری که کانتینر برای آن ساخته شده و تنها هدف کانتینر با ENTRYPOINT مشخص می شود. مهم است بدانیم دستوری که به عنوان entrypoint مشخص می کنیم را نمی توان توسط دستور هایی که سیستم میزبان می دهد بازنویسی کرد. در عمل، دستور های سیستم میزبان به entrypoint اضافه می شوند. مقدار عبارت ENTRYPOINT در dockerfile را به دو شکل shell و exec می توان تعریف کرد. یک نمونه از شکل shell را در زیر مشاهده می کنید:

ENTRYPOINT json-server db.json

دستور زیر هم نمونه ای از شکل exec است:

ENTRYPOINT [“json-server”, “db.json”]

تفاوت شکل shell و exec در مشخص کردن entrypoint چیست؟

زمانی که از شکل shell استفاده می کنیم، دستور ما به عنوان ورودی دستور bin/sh -c/ اجرا می شود. دستوری که در نمونه بالا دیدیم با حالت shell به این دستور تفسیر می شود:

/bin/sh -c json-server db.json

در مقابل shell، حالت exec دستور ما را به صورت آرایه ای از رشته ها دریافت می کند و آن را به صورت مستقیم اجرا می کند. دستوری که در نمونه بالا دیدیم با حالت exec به این دستور تفسیر می شود:

Json-server db.json

با در نظر داشتن توضیحاتی که درمورد entrypoint گفته شد، نیاز است تا دستور npm را به شکل exec به عنوان entrypoint ایمیج node تعریف کنیم تا همه دستور هایی که در این کانتینر اجرا می کنیم در ادامه دستور npm قرار داده شده و اجرا شوند.

فایل docker-compose.yml ما به شکل زیر در می آید:

version: ‘3.8’

services:
  nginx:
    build:
      context: .
      dockerfile: nginx.dockerfile
    ports:
      - 80:80
    volumes:
      - ./src:/var/www/html
    depends_on:
      - mysql
      - php
  mysql:
    image: mysql:5.7
    ports:
      - 3306:3306
    environment:
      MYSQL_DATABASE: sokanacademy
      MYSQL_USER: sokanacademy
      MYSQL_PASSWORD: secret
      MYSQL_ROOT_PASSWORD: secret
    volumes:
      - ./mysql:/var/lib/mysql
  php:
    build:
      context: .
      dockerfile: php.dockerfile
    volumes:
      - ./src:/var/www/html
  composer:
    image: composer:2
    volumes:
      - ./src:/var/www/html
    working_dir: /var/www/html
  npm:
    image: node:current-alpine
    volumes: 
      - ./src/var/www/html
    entrypoint: [“npm”]

اکنون می توانیم با استفاده از دستور docker compose run و استفاده از سرویس npm ای که تعریف کردیم همه دستور‌های npm را اجرا کنیم.

docker compose run --rm npm install

با اجرای این دستور، ابتدا ایمیج node از داکر هاب در سیستم ما دانلود و سپس دستور npm install اجرا می شود.

اما اجرای npm install با خطای زیر مواجه می شود.

دلیل این خطا این است که، دستور npm install ما در مسیر root اجرا شده است. در حالی که باید در مسیر پروژه که var/www/html/ است اجرا شود. برای رفع این خطا باید برچسب working_dir را مشخص کنیم و مسیر پروژه را به آن بدهیم.

version: '3.8'
services:
  nginx:
    build:
      context: .
      dockerfile: nginx.dockerfile
    ports:
      - 80:80
    volumes:
      - ./src:/var/www/html
    depends_on:
      - mysql
      - php
  mysql:
    image: mysql:5.7
    ports:
      - 3306:3306
    environment:
      MYSQL_DATABASE: sokanacademy
      MYSQL_USER: sokanacademy
      MYSQL_PASSWORD: secret
      MYSQL_ROOT_PASSWORD: secret
    volumes:
      - ./mysql:/var/lib/mysql
  php:
    build:
      context: .
      dockerfile: php.dockerfile
    volumes:
      - ./src:/var/www/html
  composer:
    image: composer:2
    volumes:
      - ./src:/var/www/html
    working_dir: /var/www/html
  npm:
    image: node:current-alpine
    volumes:
      - ./src:/var/www/html
    entrypoint: ["npm"]
    working_dir: /var/www/html

اکنون اجرای دستور docker compose run --rm npm install بدون خطا اجرا می شود.

ممکن است اجرای دستور هایی مانند composer و npm کمی بیشتر از زمانی که بدون داکر اجرا می شدند طول بکشد. علت این موضوع این است که بخش محدودی از منابع سیستم در اختیار داکر قرار دارد. اما نکته‌ی مثبت آن، اجرای این دستور ها بدون نیاز به نصب نرم افزار در سیستم میزبان است.

اکنون می توانیم asset های پروژه را با دستور run dev کامپایل کنیم.

docker compose run --rm npm run dev

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

در قسمت بعدی قابلیت اجرای دستور های artisan را اضافه خواهیم کرد.

دوره در حال تکمیل است ... rocket