روش‌های زیادی وجود داره که به کمک اون‌ها می‌تونین برنامه‌های react رو بسازین و اجرا کنین.
یکی از روش‌های ساخت برنامه‌ی react استفاده از NodeJS یا جاواست و روش دوم اینه که برای ایجاد برنامه‌ی react و سرویس‌دهی به محتوای استاتیک از وب‌‌سرور NGINX استفاده کنین.

وقتی شما با NGINX و داکر کار می‌کنین، مجبور نیستین مسائلی مثل مدت زمان اجرای برنامه در سرور یا کدهای مربوط به سرور رو مدیریت کنین. ساخت برنامه و سرویس‌دهی به محتوای استاتیک (اطلاعات ایستای) تولید شده با سرور NGINX، تمام اون چیزیه که بهش نیاز دارین.
در این پست قصد داریم با یک مثال،‌ نحوه‌ی اجرای روش دوم رو گام‌به‌گام با هم بررسی کنیم.

. . .

معرفی کلی

توی این پروژه، از react به عنوان کتابخانه‌ی JS، از NGINX به عنوان یک وب‌سرور، و از داکر برای اجرای کانتینرها و مدیریت ایمیج‌های داکر استفاده می‌کنیم.


NGINX در حال سرویس‌دهی به فایل‌های استاتیک


اگر به تصویر بالا نگاه کنین، می‌بینین که react، برنامه رو ایجاد می‌کنه و تمام محتوای استاتیک برنامه رو توی پوشه‌ی build/ قرار می‌ده.
حالا ما این موارد رو در مسیر پیش‌فرض NGINX، یعنی usr/share/nginx/html/ قرار می‌دیم.
( NGINX سرویس‌دهی به محتوای وب رو از این مکان انجام می‌ده).

. . .

پیش‌نیازها

خب برای انجام این کار، پیش‌نیازهایی وجود داره:

باید NGINX رو در داکر اجرا کنین و موارد استاتیک رو در NGINX قرار بدین و کل تنظیمات لازم رو داخل داکر اجرا کنین.

برای نصب وابستگی‌ها هم باید nodejs رو نصب کنین.

قبل از مطالعه‌ی این پست آموزشی، لازمه که همه‌ی موارد زیر رو نصب کنین تا بتونین رو سیستم خودتون این مراحل رو دنبال کنین:

. . .

پروژه‌ نمونه

تصویر زیر داره سرویس‌دهی NGINX و داکر به محتوای استاتیک برنامه‌ی react رو نشون می‌ده. 

همون‌طور که می‌بینین ما برنامه‌ی ساده‌ای داریم با یک هدر، فوتر و یک پیغام. 


برنامه‌ی ساده React 

ما در این پست پروژه‌ای رو بررسی می‌کنیم که شما می‌تونین سورس پروژه رو از گیت‌هاب دانلود کرده و روی سیستم‌تون اجرا کنین:  

// clone the project
git clone https://github.com/bbachi/react-nginx-docker

// install and start the dependencies
npm install
npm start

// build the docker image
docker build -t react-ui .
// run the app
docker run -d --name reactui -p 80:80 react-ui


خب، گفتیم که یک برنامه‌ی ساده‌ی react داریم با سه بخش هدر، فوتر و پیغام‌های موجود در داشبورد یا صفحه.

فایل‌های Header.js ،Footer.js و App.js رو می‌‌تونین در ادامه ببینین:‌


بخش Header.js:

import React from 'react';

const Header = () => {

    return (
        <div class="header">
            Simple React App
        </div>
    )
    
};

export default Header


بخش Footer.js:

import React from 'react';

const Footer = () => {

    return (
        <div class="footer">
            2020
        </div>
    )
    
};

export default Footer


بخش App.js:

import React from 'react';
import Header from './header/header'
import Footer from './footer/footer'
import './App.css';

function App() {
  return (
    <div className="App">
      <Header />
      <div class="dashboard">
        <h1>Simple React App served by NGINX and Docker</h1>
      </div>
      <Footer />
    </div>
  );
}

export default App;

. . .

با فرآیندهای NGINX بیشتر آشنا شویم

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

-فرآیندهای NGINX به یک فرآیند اصلی و چندین فرآیند کارگر تقسیم می‌شه:

فرآیند اصلی، مسئولیت تعیین تنظیمات لازم و نگهداری فرآیندهای کارگر رو به عهده داره و فرآیندهای کارگر هم مسئولیت مدیریت درخواست‌های واقعی رو به عهده دارن. شما می‌تونین تعداد فرآیندهای کارگر رو در فایل تنظیمات که در مسیر  usr/local/etc/nginx/ ، etc/nginx/ یا usr/local/nginx/conf/  قرار داره، تعریف کنین.

-فایل تنظیمات شامل directive هایی است که ماژول‌ها یا context‌ها رو شکل میده. این directive ها دو نوع هستند: directive های ساده و directive های بلوک:

یک directive ساده، نام‌ها و پارامترهایی داره که با space از هم دیگه جدا شدن و در انتهای هر کدوم علامت ؛ گذاشته می‌شه، مثل ;Listen 80.
directive بلوک، مثل directive ساده است؛ اما، اطلاعات بیش‌تری در اون وجود داره که در داخل آکولاد قرار می‌گیره، مثل:   {;listen 80; root /usr/share/nginx/html}

فایل Nginx.conf

بیایین فایل تنظیمات NGINX‌‌‌‌ رو که توی این پروژه استفاده کردیم، با هم مرور کنیم:

در ادامه فایل nginx.conf رو می‌بینین که در مکان root پروژه و در پوشه‌ی nginx. قرار داره.

-محیط فایل تنظیمات با نام context شناخته می‌شه که این context‌ها می‌تونن به صورت تو‌در‌تو تعریف بشن:
همون طور که در فایل nginx.conf می‌بینین، اولین دسته از  context‌ها،‌ context‌های اصلی هستن.
مثلا event‌ها و فرآیندهای کارگر در context اصلی تعریف می‌شن و context بعدی رو داریم که با http شروع می‌شه.
ما یه context دیگه‌ای داخل http داریم به نام server، که به پورت 80 گوش می‌کنه و از مکان root یعنی usr/share/nginx/html/،  به محتوای استاتیک سرویس‌دهی می‌کنه.

به تمام بخش‌هایی که داخل آکولادها نوشته می‌شه، بلوک declaration گفته می‌شه.
ما می‌تونیم داخل declaration ،http context‌های مختلفی از server داشته باشیم.
 علاوه بر این، می‌تونیم داخل declaration ،server context‌های مختلفی از location رو داشته باشیم.  

Nginx.conf به صورت زیر است:

worker_processes 4;

events { worker_connections 1024; }

http {
    server {
        listen 80;
        root  /usr/share/nginx/html;
        include /etc/nginx/mime.types;

        location /appui {
            try_files $uri /index.html;
        }
    }
}

. . .

پیاده‌سازی

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

-خب برای شروع یک فایل به نام dockerfile برای این پروژه ایجاد کنین: 

# stage1 as builder
FROM node:10-alpine as builder

# copy the package.json to install dependencies
COPY package.json package-lock.json ./

# Install the dependencies and make the folder
RUN npm install && mkdir /react-ui && mv ./node_modules ./react-ui

WORKDIR /react-ui

COPY . .

# Build the project and copy the files
RUN npm run build


FROM nginx:alpine

#!/bin/sh

COPY ./.nginx/nginx.conf /etc/nginx/nginx.conf

## Remove default nginx index page
RUN rm -rf /usr/share/nginx/html/*

# Copy from the stage 1
COPY --from=builder /react-ui/build /usr/share/nginx/html

EXPOSE 3000 80

ENTRYPOINT ["nginx", "-g", "daemon off;"]


جزئیات هر کدوم رو در ادامه بهتون می‌گیم:

"بررسی مرحله‌ اول کد بالا":

  • همون‌طور که می‌بینین، اول باید مشخص کنین ایمیج شما بر مبنای کدوم ایمیج ساخته می‌شه. این ایمیج همه وابستگی‌ها رو به صورت خودکار برای node.js نصب می‌کنه تا بتونین برنامه‌ی react خودتون رو روی اون بسازین.
    نام این ایمیج رو builder بذارین. بنابراین در مرحله‌ی اول از node:10-alpine به عنوان ایمیج پایه استفاده می‌کنین.
  • فایل Package.json رو کپی کنین تا همه‌ی وابستگی‌ها رو بتونین نصب کنین.
  • فایل‌های باقی‌مانده‌ی پروژه‌‌ی ری‌اکت رو به دایرکتوری کاری موجود کپی کنین.
  • دستور npm run build اسکریپت "build" رو ایجاد و اجرا می‌کنه، که می‌تونه برنامه‌ی شما رو اجرا کنه.

در واقع با اجرای دستور npm run build برنامه رو به صورت فایل‌های استاتیک فشرده شده‌ در میارین و نسخه‌ی production رو می‌سازین.
الان شما پروژه رو با react-script‌ها ساختین و همه‌ی فایل‌های استاتیک ساخته شده در پوشه‌ی build/ قرار گرفتن.

"بررسی مرحله‌ دوم کد بالا":

  • همون‌طور که در کد بالا می‌بینین، مرحله دوم با دستور FROM آغاز شده که در اون تعیین می‌کنین می‌خواین از nginx استفاده کنین، یعنی ایمیج پایه‌ی nginx:alpine. 
  • اولین دستور COPY، باعث می‌شه که فایل‌ nginx.conf از ایمیج پایه‌ی nginx، به ایمیج داکری که می‌سازین کپی بشه.  
  • خط بعد فایل index رو از مکان root حذف می‌کنه. 
  • COPY دوم، اعلام می‌کنه که می‌خواین همه‌ی فایل‌ها رو از builder (نام ایمیج ساخته شده در مرحله‌ی اول)، کپی کنین. پس فایل‌های مرحله‌ی اول در یک ایمیج داکر مجزا قرار می‌گیره.

یا به عبارتی،‌ برنامه‌ی react ساخته شده از پوشه‌ی  build (در مرحله‌ی اول)، به پوشه‌ی html  مربوط به NGINX (مکان root)، کپی می‌شه.
(سرویس‌دهی به محتوا از ان مکان انجام می‌شه).

ساخت ایمیج و اجرای پروژه

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

docker build -t react-ui  


برای این که برنامه‌ی react تون رو اجرا کنین، باید یک کانتینر داکر رو راه‌اندازی کنین که از ایمیج داکر شما استفاده کنه:

 docker run -d --name reactui -p 80:80 react-ui 


برای دیدن برنامه به آدرس  http://localhost:80  مراجعه کنین.


 پروژه‌ی در حال اجرا در localhost


موارد مهمی که باید به آن‌ها توجه کنین

پورت کانتینر و پورت listen مربوط به nginx، باید با هم برابر باشن، یعنی پورت 80.
در غیر این صورت موقع اجرای پروژه، پیام ERR_EMPTY_RESPONSE رو دریافت می‌کنین.

// container port
docker run -d --name react-ui -p 80:80 reactui
// nginx conf
http {   
   server {
      listen 80;
   }
}


شما باید این directive رو در فایل include ،nginx.conf کنین.
در غیر این صورت همه‌ی style‌ها به صورت متن ساده در مرورگر ارائه می‌شن:

include /etc/nginx/mime.types;


استفاده از دستور exec در کانتینر در حال اجرا 

وقتی کانتینر در حال اجراست، می‌تونین با استفاده از دستور exec، محتوای سیستم فایل رو ببینین:

docker exec -it reactui /bin/sh


در واقع می‌تونین تمام محتوای موجود در مسیر usr/share/nginx/html/ رو ببینین:


. . .

چکیده‌

-NGINX می‌تونه به عنوان یک وب‌سرور یا  reverse proxy، برای سرویس‌دهی به محتوای ثابت استفاده بشه.

-همه‌ی تنظیمات NGINX رو می‌تونین توی فایل nginx.conf قرار بدین.

-شما باید برنامه‌ی react رو بسازین و برای سرویس‌دهی به همه‌ی فایل‌های استاتیک، باید اون‌ها رو در محل root از NGINX، قرار بدین.

-تو این پست، شما از داکر برای اجرای کانتینرها و مدیریت ایمیج‌های داکر استفاده کردین. 

-علاوه بر این، شما از ساخت چند مرحله‌ای برای کاهش اندازه‌ی ایمیج نهایی، و حذف فایل‌های غیر ضروری از محیط production، استفاده کردین.

-ایمیج داکر رو با  دستور docker build -t react-ui ساختین.

-کانتینر رو با دستور docker run -d --name reactui -p 80:80 react-ui اجرا کردین.

-گفتیم خیلی مهمه که پورت کانتینر در حال اجرا و پورت Listen در فایل nginx.conf، با هم یکی باشن؛ در غیر این صورت، با خطای ERR_EMPTY_RESPONSE مواجه می‌شین. 

و در نهایت برای پیدا کردن محتوای سیستم‌فایل، از دستور docker exec -it reaktui / bin / sh، استفاده کردین.

. . .

نتیجه‌گیری

NGINX یک وب‌سرور با کارایی بالاست که به سرویس‌دهی به فایل‌های ثابت می‌پردازه، امنیت رو بهبود می‌ده و دسترسی و مقیاس‌پذیری برنامه‌های وب رو راحت‌تر می‌کنه.

اگه الزامی به ساخت برنامه‌های UI با جاوا یا node js وجود نداره، می‌تونین  برنامه‌ی UI رو بسازین و سرویس‌دهی به محتوای ثابت رو با وب سرور NGINX انجام بدین.

اگه دوست دارین بدونین چطوری می‌تونین یک برنامه‌ی ری اکت رو با استفاده از داکر و NGINX مستقر کنین، پیشنهاد می‌کنم به این پست هم سر بزنین.


منبع:

NGINX and Docker-