اذهب إلى المحتوى

بناء تطبيق Node.js باستخدام Docker


Abdessamad El Omari

تتيح منصة Docker للمطورين تحزيم وتنفيذ التطبيقات على شكل حاويات (containers). وتعدّ الحاوية عملية (process) منعزلة تعمل على نظام تشغيل مشترك، وتوفر بديلاً أخفّ من الأجهزة الافتراضية (virtual machines) . رغم أن الحاويات ليست جديدة، إلا أن لها فوائد عديدة، من بينها عزل العمليات وتوحيد البيئة، وتزداد أهميتها نظرًا لتزايد إقبال المطورين على استخدام بنية التطبيقات الموزعة.

عند بناء تطبيق وتوسيع نطاقه باستخدام Docker، تكون نقطة البداية عادةً هي إنشاء صورة للتطبيق، والتي يمكنك تنفيذها بعد ذلك في حاوية. تتضمن الصورة شيفرة التطبيق والمكتبات وملفات التكوين ومتغيرات البيئة ووقت التشغيل. ويضمن استخدام صورة ما أن تكون البيئة في حاويتك موحدة ومتضمّنة فقط لما هو ضروري لإنشاء التطبيق وتنفيذه.

ستنشئ في هذا الدرس صورة تطبيق لموقع ويب ثابت يستخدم إطار عمل Express و Bootstrap. وستنشئ بعد ذلك حاوية باستخدام تلك الصورة ورفعها إلى Docker Hub للاستخدام المستقبلي. أخيرًا، ستتمكّن من سحب الصورة المخزنة من مستودع Docker Hub الخاص بك وتنشئ حاوية أخرى، مع توضيح كيف يمكنك إعادة إنشاء التطبيق وتوسيع نطاقه.

المتطلبات الأساسية

سوف تحتاج من أجل متابعة هذه السلسلة إلى العناصر التالية:

الخطوة الأولى: تثبيت الاعتماديات لتطبيقك

لإنشاء الصورة، ستحتاج أولاً إلى إنشاء ملفات التطبيق الخاصة بك والتي يمكنك بعد ذلك نسخها إلى حاويتك. ستتضمن هذه الملفات المحتوى الثابت للتطبيق والشيفرة والاعتماديات.

أنشئ في البداية مجلًدًا لمشروعك في المجلّد الرئيسي للمستخدم غير الجذري. سنستدعي node_project الخاص بنا، لكن يمكنك استبداله بشيء آخر:

$ mkdir node_project

انتقل إلى هذا المجلّد:

$ cd node_project

سيكون هذا هو المجلّد الرئيسي للمشروع.

أنشئ بعد ذلك ملف [package.json](https://docs.npmjs.com/files/package.json) باعتماديات مشروعك ومعلومات التعريف الأخرى. افتح الملف باستخدام nano أو المحرر المفضل لديك:

$ nano package.json

أضف المعلومات التالية حول المشروع، بما في ذلك اسم المشروع وصاحبه والترخيص ونقطة الدخول والاعتماديات. تأكد من استبدال معلومات صاحب المشروع باسمك ومعلومات الاتصال الخاصة بك:

  • الملف ‎:~/node_project/package.json
{
  "name": "nodejs-image-demo",
  "version": "1.0.0",
  "description": "nodejs image demo",
  "author": "Sammy the Shark <sammy@example.com>",
  "license": "MIT",
  "main": "app.js",
  "keywords": [
    "nodejs",
    "bootstrap",
    "express"
  ],
  "dependencies": {
    "express": "^4.16.4"
  }
}

يحتوي هذا الملف على اسم المشروع وصاحبه والترخيص الذي تتم مشاركته بموجبه. ينصح npm بجعل اسم المشروع قصيرًا وذا دلالة وصفية مع تجنب التكرار في سجل npm. لقد أدرجنا ترخيص MIT في حقل الترخيص، مما يتيح الاستخدام المجاني لشيفرة التطبيق وتوزيعه.

بالإضافة إلى ذلك، يحدد الملف العناصر التالية:

  • "main": نقطة دخول التطبيق app.js، ستقوم بإنشاء هذا الملف بعد ذلك.
  • "dependencies": اعتماديات المشروع، في هذه الحالة، Express إصدار 4.16.4 أو أعلى منه.

ورغم أن هذا الملف لا يحتوي على مستودعٍ، فيمكنك إضافته باتباع هذه الإرشادات حول إضافة مستودع إلى ملف package.json الخاص بك. وتعدّ هذه إضافةً جيدةً إذا كنت تقوم بإصدار تطبيقك.

احفظ الملف وأغلقه عندما تنتهي من إجراء التعديلات.

لتثبيت اعتماديات مشروعك، نفّذ الأمر التالي:

$ npm install

سيؤدي ذلك إلى تثبيت الحزم التي أدرجتها في ملف package.json في مجلّد المشروع الخاص بك.

يمكننا الآن الانتقال إلى بناء ملفات التطبيق.

الخطوة الثانية: إنشاء ملفات التطبيق

سنعمل على إنشاء موقع ويب يقدم للمستخدمين معلومات حول أسماك القرش. سيكون لدى لتطبيق نقطة دخول رئيسية و ملفّ app.js ومجلّد views يتضمن الأصول الثابتة للمشروع. ستوفر صفحة الهبوط index.html للمستخدمين بعض المعلومات الأولية ورابطًا نحو صفحة تحتوي على معلومات أكثر تفصيلًا عن أسماك القرش، sharks.html. سننشئ في مجلّد views كلًّا من صفحة الهبوط و الصفحة sharks.html.

في البداية، افتح ملفّ app.js في مجلّد المشروع الرئيسي لتحديد مسارات المشروع:

$ nano app.js

سيعمل الجزء الأول من الملف على إنشاء تطبيق Express وكائنات الموجِّه، وتحديد المجلّد الأساسي والمنفذ كثوابت:

  • الملف ‎:~/node_project/app.js
const express = require('express');
const app = express();
const router = express.Router();

const path = __dirname + '/views/';
const port = 8080;

تحمّل الداّلة require الوحدة express التي نستخدمها فيما بعد لإنشاء الكائنات app و router. سيؤدي الكائن router وظيفة التوجيه الخاصة بالتطبيق، وعندما نحدد مسارات طرق HTTP، سنضيفها إلى هذا الكائن لتحديد كيفية تعامل التطبيق مع الطلبات.

يعين هذا الجزء من الملف أيضًا ثابتتي المسار path والمنفذ port: *path: يحدد المجلّد الأساسي، والذي سيكون المجلّد الفرعي ل views داخل مجلّد المشروع الحالي.

  • port: يطلب من التطبيق الاستماع على المنفذ 8080.

بعد ذلك، حدّد مسارات التطبيق باستخدام الكائن router:

  • الملف ‎~/node_project/app.js:
router.use(function (req,res,next) {
  console.log('/' + req.method);
  next();
});

router.get('/', function(req,res){
  res.sendFile(path + 'index.html');
});

router.get('/sharks', function(req,res){
  res.sendFile(path + 'sharks.html');
});

تحمّل الدالّة router.use دالّة وسيطة تعمل على تسجيل طلبات الموجه وتمررها إلى مسارات التطبيق. تُحدّد هذه المسارات في الدوالّ الموالية، والتي تنصّ على أن تنفيذ الأمر GET على عنوان URL للمشروع الأساسي يجب أن يُرجع الصفحة index.html، بينما يجب أن يُرجع تنفيذ الأمر GET على المسار sharks/ الصفحة sharks.html.

ختامًا، صل بين البرمجية الوسيطة router والأصول الثابتة للتطبيق واجعل التطبيق يستمع على المنفذ 8080:

~/node_project/app.js
...

app.use(express.static(path));
app.use('/', router);

app.listen(port, function () {
  console.log('Example app listening on port 8080!')
})

سيبدو ملف app.js النهائي كما يلي:

const express = require('express');
const app = express();
const router = express.Router();

const path = __dirname + '/views/';
const port = 8080;

router.use(function (req,res,next) {
  console.log('/' + req.method);
  next();
});

router.get('/', function(req,res){
  res.sendFile(path + 'index.html');
});

router.get('/sharks', function(req,res){
  res.sendFile(path + 'sharks.html');
});

app.use(express.static(path));
app.use('/', router);

app.listen(port, function () {
  console.log('Example app listening on port 8080!')
})

احفظ الملف وأغلقه عند الانتهاء.

بعد ذلك، دعنا نضيف بعض المحتوى الثابت إلى التطبيق. ابدأ بإنشاء المجلد views:

$ mkdir views

افتح ملف صفحة الهبوط index.html:

$ nano views/index.html

أضف الشيفرة التالية إلى الملف، الذي سيعمل على استيراد Bootstrap وإنشاء مكوّن jumbotron مع رابط إلى صفحة المعلومات المفصّلة sharks.html:

  • الملف ‎~/node_project/views/index.html:
<!DOCTYPE html>
<html lang="en">

<head>
    <title>About Sharks</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
    <link href="css/styles.css" rel="stylesheet">
    <link href="https://fonts.googleapis.com/css?family=Merriweather:400,700" rel="stylesheet" type="text/css">
</head>

<body>
    <nav class="navbar navbar-dark bg-dark navbar-static-top navbar-expand-md">
        <div class="container">
            <button type="button" class="navbar-toggler collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"> <span class="sr-only">Toggle navigation</span>
            </button> <a class="navbar-brand" href="#">Everything Sharks</a>
            <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
                <ul class="nav navbar-nav mr-auto">
                    <li class="active nav-item"><a href="/" class="nav-link">Home</a>
                    </li>
                    <li class="nav-item"><a href="/sharks" class="nav-link">Sharks</a>
                    </li>
                </ul>
            </div>
        </div>
    </nav>
    <div class="jumbotron">
        <div class="container">
            <h1>Want to Learn About Sharks?</h1>
            <p>Are you ready to learn about sharks?</p>
            <br>
            <p><a class="btn btn-primary btn-lg" href="/sharks" role="button">Get Shark Info</a>
            </p>
        </div>
    </div>
    <div class="container">
        <div class="row">
            <div class="col-lg-6">
                <h3>Not all sharks are alike</h3>
                <p>Though some are dangerous, sharks generally do not attack humans. Out of the 500 species known to researchers, only 30 have been known to attack humans.
                </p>
            </div>
            <div class="col-lg-6">
                <h3>Sharks are ancient</h3>
                <p>There is evidence to suggest that sharks lived up to 400 million years ago.
                </p>
            </div>
        </div>
    </div>
</body>

</html>

يتيح شريط التنقل في الأعلى للمستخدمين المرور بين الصفحة الرئيسية وصفحة أسماك القرش. في المكون الفرعي navbar-nav، نستخدم الصنف active في Bootstrap للإشارة إلى الصفحة الحالية للمستخدم. لقد حددنا أيضًا الطرق المؤدية إلى الصفحات الثابتة لدينا، والتي تتوافق مع الطرق التي حددناها في app.js:

  • الملف ‎~/node_project/views/index.html:
...
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
   <ul class="nav navbar-nav mr-auto">
      <li class="active nav-item"><a href="/" class="nav-link">Home</a>
      </li>
      <li class="nav-item"><a href="/sharks" class="nav-link">Sharks</a>
      </li>
   </ul>
</div>
...

بالإضافة إلى ذلك، أنشأنا رابطًا إلى صفحة معلومات سمك القرش في زر jumbotron الخاص بنا:

  • الملف ‎~/node_project/views/index.html:
...
<div class="jumbotron">
   <div class="container">
      <h1>Want to Learn About Sharks?</h1>
      <p>Are you ready to learn about sharks?</p>
      <br>
      <p><a class="btn btn-primary btn-lg" href="/sharks" role="button">Get Shark Info</a>
      </p>
   </div>
</div>
...

يوجد أيضًا رابط إلى ورقة أنماط مخصصة في عنصر الترويسة header:

  • الملف ‎~/node_project/views/index.html:
...
<link href="css/styles.css" rel="stylesheet">
...

سننشئ ورقة الأنماط هذه في نهاية هذه الخطوة.

احفظ الملف وأغلقه عند الانتهاء.

يمكننا، من خلال صفحة الهبوط، إنشاء صفحة معلومات أسماك القرش sharks.html، والتي ستوفر للمستخدمين المهتمين مزيدًا من المعلومات حول أسماك القرش.

افتح الملف:

$ nano views/sharks.html
  • الملف ‎~/node_project/views/sharks.html:
<!DOCTYPE html>
<html lang="en">

<head>
    <title>About Sharks</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
    <link href="css/styles.css" rel="stylesheet">
    <link href="https://fonts.googleapis.com/css?family=Merriweather:400,700" rel="stylesheet" type="text/css">
</head>
<nav class="navbar navbar-dark bg-dark navbar-static-top navbar-expand-md">
    <div class="container">
        <button type="button" class="navbar-toggler collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"> <span class="sr-only">Toggle navigation</span>
        </button> <a class="navbar-brand" href="/">Everything Sharks</a>
        <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
            <ul class="nav navbar-nav mr-auto">
                <li class="nav-item"><a href="/" class="nav-link">Home</a>
                </li>
                <li class="active nav-item"><a href="/sharks" class="nav-link">Sharks</a>
                </li>
            </ul>
        </div>
    </div>
</nav>
<div class="jumbotron text-center">
    <h1>Shark Info</h1>
</div>
<div class="container">
    <div class="row">
        <div class="col-lg-6">
            <p>
                <div class="caption">Some sharks are known to be dangerous to humans, though many more are not. The sawshark, for example, is not considered a threat to humans.
                </div>
                <img src="https://assets.digitalocean.com/articles/docker_node_image/sawshark.jpg" alt="Sawshark">
            </p>
        </div>
        <div class="col-lg-6">
            <p>
                <div class="caption">Other sharks are known to be friendly and welcoming!</div>
                <img src="https://assets.digitalocean.com/articles/docker_node_image/sammy.png" alt="Sammy the Shark">
            </p>
        </div>
    </div>
</div>

</html>

لاحظ أنه في هذا الملف، نستخدم مرة أخرى الصنف active للإشارة إلى الصفحة الحالية.

احفظ الملف وأغلقه عند الانتهاء.

ختامًا ، أنشئ ورقة الأنماط المخصصة CSS التي ربطتها بالصفحتين index.html و sharks.html، وذلك بإنشاء ملف css أولاً في المجلّد views:

$ mkdir views/css

افتح ورقة الأنماط:

nano views/css/styles.css

أضف الشيفرة التالية التي ستحدد اللون والخط المطلوب لصفحاتنا:

  • الملف ‎~/node_project/views/css/styles.css:
.navbar {
    margin-bottom: 0;
}

body {
    background: #020A1B;
    color: #ffffff;
    font-family: 'Merriweather', sans-serif;
}

h1,
h2 {
    font-weight: bold;
}

p {
    font-size: 16px;
    color: #ffffff;
}

.jumbotron {
    background: #0048CD;
    color: white;
    text-align: center;
}

.jumbotron p {
    color: white;
    font-size: 26px;
}

.btn-primary {
    color: #fff;
    text-color: #000000;
    border-color: white;
    margin-bottom: 5px;
}

img,
video,
audio {
    margin-top: 20px;
    max-width: 80%;
}

div.caption: {
    float: left;
    clear: both;
}

بالإضافة إلى تعيين الخط واللون، يحدّد هذا الملف أيضًا حجم الصور بتحديد عرض أقصى يبلغ 80٪. هذا سيمنعها من شغل مساحة في الصفحة أكبر مما نريد.

احفظ الملف وأغلقه عند الانتهاء.

بعد إنشاء ملفات التطبيق وتثبيت اعتماديات المشروع، تكون جاهزًا لتشغيل التطبيق.

إذا كنت قد تابعت دليل إعداد الخادم الأولي المذكور في المتطلبات الأساسية، فسيكون لديك جدار حماية نشط يسمح فقط بحركة مرور SSH. للسماح بحركة المرور عبر المنفذ 8080، نفّذ الأمر التالي :

$ sudo ufw allow 8080

لتشغيل التطبيق، تأكد من وجودك في المجلد الرئيسي للمشروع:

$ cd ~/node_project

ابدأ تشغيل التطبيق باستخدام node app.js:

$ node app.js

انتقل بمتصفّحك إلى http://your_server_ip:8080. وستظهر لك صفحة الهبوط التالية:

landing_page.png

انقر على زر الحصول على معلومات القرش Get shark info. وستظهر لك صفحة المعلومات التالية:

sharks.png

لديك الآن تطبيق قيد التشغيل. عندما تكون جاهزًا، أوقف الخادم بكتابة CTRL+C. يمكننا الآن الانتقال إلى إنشاء ملف Dockerfile الذي سيتيح لنا إعادة إنشاء هذا التطبيق وتوسيع نطاقه حسب الرغبة.

الخطوة الثالثة: كتابة ملف Dockerfile

يحدد ملف Dockerfile الخاص بك ما سيتم تضمينه في حاوية التطبيق عند تنفيذه. ويتيح لك استخدام هذا الملفّ تحديد بيئة الحاوية وتجنب التناقضات مع الاعتماديات أو إصدارات وقت التشغيل.

باتباع هذه الإرشادات حول إنشاء حاويات محسّنة، سنجعل صورة التطبيق أكثر فاعلية قدر الإمكان عن طريق تقليل عدد طبقات الصورة وتحديد وظيفة الصورة في غرض واحد هو إعادة إنشاء ملفات التطبيق والمحتوى الثابت.

في المجلّد الرئيسي لمشروعك، أنشئ الملف Dockerfile:

$ nano Dockerfile

تُنشَأ صور Docker باستخدام سلسلة متتالية من الصور ذات الطبقات التي تعتمد على بعضها بعضًا. ستكون خطوتنا الأولى هي إضافة الصورة الأساسية للتطبيق والتي ستشكل نقطة انطلاق إنشاء التطبيق.

لنستخدم الصورة node:10-alpine. ويمكننا الحصول على الصورة alpine من مشروع Alpine Linux لكي تساعدنا في تقليل حجم الصور لدينا.

أضف تعليمات FROM التالية لتعيين الصورة الأساسية للتطبيق:

  • الملف ‎~/node_project/Dockerfile:
FROM node:10-alpine

تتضمن هذه الصورة Node.js و npm. ويجب أن يبتدئ كل ملفّ Dockerfile بتعليمات FROM.

بشكل افتراضي، تشتمل صورة Docker Node على مستخدم Node غير جذري يمكنك استخدامه لتجنب تشغيل حاوية التطبيق باستخدام الحساب الجذري. إنها ممارسة أمان موصى بها لتجنب تشغيل الحاويات باستخدام root وتقييد الصلاحيات داخل الحاوية في تلك المطلوبة فقط لتنفيذ عملياتها. لذلك، سوف نستخدم المجلّد الرئيسي لمستخدم Node كمجلّد العمل لتطبيقنا ونعيّنه كمستخدم داخل الحاوية. لمزيد من المعلومات حول أفضل الممارسات عند العمل مع صورة Docker Node، راجع دليل أفضل الممارسات هذا إذا كانت لغتك الانجليزية جيدة.

لضبط الأذونات على شيفرة تطبيقنا في الحاوية، دعنا ننشئ المجلّد الفرعي node_modules في ‎/home/node رفقة المجلّد app. سيضمن إنشاء هذه المجلّدات أنها تتوفّر على الأذونات التي نريدها، والتي ستكون مهمة عندما ننشئ وحدات node محلية في الحاوية باستخدام npm install. بالإضافة إلى إنشاء هذه المجلّدات، سنعطي ملكيتها للمستخدم node: -الملف ‎~/node_project/Dockerfile:

...
RUN mkdir -p /home/node/app/node_modules && chown -R node:node /home/node/app

عيّن بعد ذلك مجلّد العمل للتطبيق على ‎/home/node/app:

  • الملف ~/node_project/Dockerfile :
...
WORKDIR /home/node/app

إذا لم يتم تعيين مجلّد عمل WORKDIR، فسوف يُنشئ Docker واحدًا افتراضيًا، لذلك من الجيد تعيينه بشكل صريح.

بعد ذلك، انسخ ملفات package.json و package-lock.json (بالنسبة لملفات الإصدار الخامس npm فما فوق):

  • الملف ‎~/node_project/Dockerfile:
...
COPY package*.json ./

تتيح إضافة تعليمة COPY قبل تنفيذ npm install تثبيت أو نسخ شيفرة التطبيق الاستفادة من آلية التخزين المؤقت لـ Docker. في كل مرحلة من مراحل البناء، سيقوم Docker بالتحقق مما إذا كان يحتوي على طبقة تم تخزينها في ذاكرة التخزين المؤقت لتلك التعليمات المحددة. إذا غيّرنا الحزمة package.json، فسيُعاد بناء هذه الطبقة، لكن إذا لم نفعل ذلك، فسوف تسمح هذا التعليمة لـ Docker باستخدام طبقة الصورة الحالية وتخطي إعادة تثبيت وحدات node.

للتأكد من أن جميع ملفات التطبيق مملوكة للمستخدم node غير الجذري، بما في ذلك محتويات المجلّد node_modules، حوّل المستخدم إلى node قبل تنفيذ npm install:

  • الملف ‎-/node_project/Dockerfile:
...
USER node

بعد نسخ اعتماديات المشروع وتبديل مستخدمنا، يمكننا تنفيذ install npm:

  • الملف ‎~/node_project/Dockerfile:
...
RUN npm install

بعد ذلك، انسخ شيفرة تطبيقك مع الأذونات المناسبة إلى مجلّد التطبيق على الحاوية:

  • الملف ‎~/node_project/Dockerfile:
...
COPY --chown=node:node . .

سيضمن هذا أن ملفات التطبيق مملوكة من قبل مستخدم node غير الجذري.

أخيرًا، اعرض المنفذ 8080 على الحاوية وابدأ تشغيل التطبيق:

  • الملف ‎~/node_project/Dockerfile:
...
EXPOSE 8080

CMD [ "node", "app.js" ]

لا ينشر الأمر EXPOSE المنفذَ، ولكنه يعمل بدلاً من ذلك كوسيلة لتوثيق المنافذ على الحاوية التي سيتم نشرها في وقت التشغيل. يقوم CMD بتنفيذ الأمر لبدء التطبيق، في هذه الحالة، node app.js. لاحظ أنه يجب أن يكون هناك تعليمة CMD واحدة فقط في كل Dockerfile. إذا ضمّنت أكثر من واحدة، فستُفعّل الأخيرة فقط.

هناك العديد من الأشياء التي يمكنك القيام بها باستخدام Dockerfile. للحصول على قائمة كاملة بالتعليمات، يرجى الرجوع إلى التوثيق المرجعي لملفات Dockerfile.

يكون الملفّ Dockerfile الكامل على هذا النحو:

  • الملف ‎~/node_project/Dockerfile:
FROM node:10-alpine

RUN mkdir -p /home/node/app/node_modules && chown -R node:node /home/node/app

WORKDIR /home/node/app

COPY package*.json ./

USER node

RUN npm install

COPY --chown=node:node . .

EXPOSE 8080

CMD [ "node", "app.js" ]

احفظ الملف وأغلقه عند الانتهاء من التحرير.

قبل بناء صورة التطبيق، دعنا نضيف ملف ‎.dockerignore ونظرًا لأنه يعمل بطريقة مشابهة لملف .gitignore، فإن ملف ‎.dockerignore يحدّد ماهي الملفات والمجلّدات الموجودة في مجلّد مشروعك والتي لا ينبغي نسخها إلى حاويتك.

افتح الملف dockerignore.:

$ nano .dockerignore

أضف داخل الملف وحدات node المحلية وسجلات npm وملف Dockerfile وملف dockerignore.:

  • الملف ‎~/node_project/.dockerignore:
node_modules
npm-debug.log
Dockerfile
.dockerignore

إذا كنت تعمل باستخدام Git، فستحتاج أيضًا إلى إضافة مجلّد git. وملف gitignore.

احفظ الملف وأغلقه عند الانتهاء.

أنت الآن جاهز لإنشاء صورة التطبيق باستخدام الأمر docker build. سيسمح لك استخدام الراية t- مع docker build بتعليم الصورة باسم سهل التذكّر. ونظرًا لأننا سنقوم بنقل الصورة إلى Docker Hub، فلنضمّن اسم مستخدم Docker Hub الخاص بنا في العلامة. سنعلّم الصورة باستخدام nodejs-image-demo، ولكن لا تتردد في استبدالها باسم تختاره. تذكر أيضًا استبدال your_dockerhub_username باسم مستخدم Docker Hub الخاص بك:

$ docker build -t your_dockerhub_username/nodejs-image-demo .

تحدّد النقطة . أن موضع البناء هو المجلّد الحالي.

سوف يستغرق الأمر دقيقة أو دقيقتين لبناء الصورة. بمجرد اكتمال الأمر، يمكنك التحقق من صورك:

$ docker images

سيظهر لك في المخرجات ما يلي:

output
REPOSITORY                                         TAG                 IMAGE ID            CREATED             SIZE
your_dockerhub_username/nodejs-image-demo          latest              1c723fb2ef12        8 seconds ago       73MB
node                                               10-alpine           f09e7c96b6de        3 weeks ago        70.7MB

أصبح الآن من الممكن إنشاء حاوية بهذه الصورة باستخدام docker run. وسنضمّن ثلاث علامات مع هذا الأمر:

  • ‎-p : تنشر هذه الراية المنفذ على الحاوية وتقدّمه كمنفذ على المضيف host. سنستخدم المنفذ 80 على المضيف، ولكن يجب ألا تتردد في تعديل هذا عند الضرورة إذا كان لديك عملية أخرى تعمل على هذا المنفذ. لمزيد من المعلومات حول كيفية عمل هذا، راجع هذه النقاش في توثيقات Docker حول ربط المنافذ.
  • ‎-d : تشغّل هذه العلامة الحاوية في الخلفية.
  • ‎-name : هذا يتيح لنا إعطاء الحاوية اسمًا سهل التذكر.

نفّذ الأمر التالي لبناء الحاوية:

docker run --name nodejs-image-demo -p 80:8080 -d your_dockerhub_username/nodejs-image-demo

بمجرد تشغيل حاويتك، يمكنك فحص قائمة الحاويات قيد التشغيل باستخدام docker ps:

$ docker ps

سيظهر لك الإخراج التالي:

Output
CONTAINER ID        IMAGE                                                   COMMAND             CREATED             STATUS              PORTS                  NAMES
e50ad27074a7        your_dockerhub_username/nodejs-image-demo               "node app.js"       8 seconds ago       Up 7 seconds        0.0.0.0:80->8080/tcp   nodejs-image-demo

بعد تشغيل حاويتك، يمكنك الآن الولوج إلى تطبيقك بالانتقال بمتصفحك إلى http://your_server_ip. ستظهر لك صفحتك الهبوط مرة أخرى:

landing_page.png

الآن وبعد بناء صورة لتطبيقك، يمكنك رفعها إلى Docker Hub للاستخدام المستقبلي.

الخطوة الرابعة: استخدام مستودع للعمل بالصور

برفعك لصورة التطبيق الخاصة بك إلى سجلّ مثل Docker Hub، فأنت تجعلها متاحة للاستخدام المستقبلي عندما تكون بصدد بناء حاوياتك وتوسيع نطاقها. سنوضح كيف يعمل هذا عن طريق رفع صورة التطبيق إلى مستودع ثم استخدام الصورة لإعادة إنشاء حاويتنا.

الخطوة الأولى لرفع الصورة هي تسجيل الدخول إلى حساب Docker Hub الذي أنشأته في المتطلبات الأساسية:

$ docker login -u your_dockerhub_username 

أدخل كلمة مرور حساب Docker Hub، وسيؤدي التسجيل بهذه الطريقة إلى إنشاء ملف ‎~/.docker/config.json في المجلّد الرئيسي لمستخدمك بالبيانات الاعتمادية لDocker Hub.

يمكنك الآن رفع صورة التطبيق إلى Docker Hub باستخدام العلامة التي أنشأتها مسبقًا، your_dockerhub_username/nodejs-image-demo

$ docker push your_dockerhub_username/nodejs-image-demo

دعنا نختبر الآن أهمّية سجلّ الصور بتدمير حاوية التطبيق الحالية والصورة وإعادة بنائها باستخدام الصورة التي في مستودعنا.

استعرض أولاً حاوياتك التي توجد قيد التشغيل:

$ docker ps

سيظهر لك الإخراج التالي:

Output
CONTAINER ID        IMAGE                                       COMMAND             CREATED             STATUS              PORTS                  NAMES
e50ad27074a7        your_dockerhub_username/nodejs-image-demo   "node app.js"       3 minutes ago       Up 3 minutes        0.0.0.0:80->8080/tcp   nodejs-image-demo

باستخدام CONTAINER ID الظاهر في المخرجات، أوقف حاوية التطبيق قيد التشغيل. تأكد من استبدال المعرّف أدناه بمعرّف الحاوية CONTAINER ID:

$ docker stop e50ad27074a7

اعرض قائمة صورك باستخدام الراية ‎-a :

$ docker images -a

سيظهر لك الإخراج التالي مع اسم صورتك، your_dockerhub_username/nodejs-image-demo، إلى جانب صورة node وباقي الصور الأخرى الخاصة ببنائك:

Output
REPOSITORY                                           TAG                 IMAGE ID            CREATED             SIZE
your_dockerhub_username/nodejs-image-demo            latest              1c723fb2ef12        7 minutes ago       73MB
<none>                                               <none>              2e3267d9ac02        4 minutes ago       72.9MB
<none>                                               <none>              8352b41730b9        4 minutes ago       73MB
<none>                                               <none>              5d58b92823cb        4 minutes ago       73MB
<none>                                               <none>              3f1e35d7062a        4 minutes ago       73MB
<none>                                               <none>              02176311e4d0        4 minutes ago       73MB
<none>                                               <none>              8e84b33edcda        4 minutes ago       70.7MB
<none>                                               <none>              6a5ed70f86f2        4 minutes ago       70.7MB
<none>                                               <none>              776b2637d3c1        4 minutes ago       70.7MB
node                                                 10-alpine           f09e7c96b6de        3 weeks ago         70.7MB

احذف الحاوية المتوقفة وجميع الصور، بما في ذلك الصور غير المستخدمة أو المعلّقة، باستخدام الأمر التالي:

$ docker system prune -a

اكتب y في المحثّ عند الإخراج لتأكيد رغبتك في إزالة الحاوية والصور المتوقفة. وينبغي التوضيح أن هذا سيؤدي أيضًا إلى حذف ذاكرة التخزين المؤقت للبناء.

لقد حذفت الآن كلًا من الحاوية التي تشغّل صورة التطبيق والصورة نفسها. لمزيد من المعلومات حول إزالة حاويات Docker والصور، يرجى الاطلاع على كيفية التعامل مع الحاويات.

بعد حذف كل الصور والحاويات الخاصة بك ، يمكنك الآن سحب صورة التطبيق من Docker Hub:

$ docker pull your_dockerhub_username/nodejs-image-demo

اعرض قائمة صورك مرة أخرى:

$ docker images

ستظهر لك صورة تطبيقك:

Output
REPOSITORY                                     TAG                 IMAGE ID            CREATED             SIZE
your_dockerhub_username/nodejs-image-demo      latest              1c723fb2ef12        11 minutes ago      73MB

يمكنك الآن إعادة بناء حاويتك باستخدام الأمر التالي من الخطوة 3:

docker run --name nodejs-image-demo -p 80:8080 -d your_dockerhub_username/nodejs-image-demo

اعرض قائمة الحاويات قيد التشغيل:

$ docker ps
Output
CONTAINER ID        IMAGE                                                   COMMAND             CREATED             STATUS              PORTS                  NAMES
f6bc2f50dff6        your_dockerhub_username/nodejs-image-demo               "node app.js"       4 seconds ago       Up 3 seconds        0.0.0.0:80->8080/tcp   nodejs-image-demo

تصفّح http://your_server_ip مرة أخرى لعرض التطبيق قيد التشغيل.

الخلاصة

في هذا الدرس، عملت على بناء تطبيق ويب ثابت باستخدام Express و Bootstrap، بالإضافة إلى صورة Docker لهذا التطبيق. استخدمت هذه الصورة لإنشاء حاوية ورفعت الصورة إلى Docker Hub. بعد ذلك، تمكنت من تدمير صورتك وحاوياتك وإعادة إنشائها باستخدام مستودع Docker Hub.

ترجمة -وبتصرف- للمقال How To Build a Node.js Application with Docker لصاحبته Kathleen Juell


تفاعل الأعضاء

أفضل التعليقات

لا توجد أية تعليقات بعد



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...