حاويات المهنية للتطبيقات Node.js باستخدام Docker

مؤلف المادة ، الذي ننشر ترجمته اليوم ، هو مهندس DevOps. يقول أنه يجب أن يستخدم عامل الميناء . على وجه الخصوص ، يتم استخدام نظام إدارة الحاويات هذا في المراحل المختلفة من دورة حياة تطبيقات Node.js. باستخدام Docker ، وهي تقنية شائعة جدًا مؤخرًا ، تتيح لك تحسين عملية التطوير والإخراج لمشاريع Node.js في الإنتاج.

الصورة

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

ما هو عامل ميناء؟


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

إنشاء مشروع Node.js


قبل حزم مشروع Node.js في حاوية Docker ، نحتاج إلى إنشاء هذا المشروع. دعونا نفعل ذلك. هنا هو ملف package.json لهذا المشروع:

 { "name": "node-app", "version": "1.0.0", "description": "The best way to manage your Node app using Docker", "main": "index.js", "scripts": {   "start": "node index.js" }, "author": "Ankit Jain <ankitjain28may77@gmail.com>", "license": "ISC", "dependencies": {   "express": "^4.16.4" } } 

لتثبيت تبعيات المشروع ، قم بتشغيل الأمر npm install . في سياق هذا الأمر ، من بين أشياء أخرى ، سيتم إنشاء ملف package-lock.json . قم الآن بإنشاء ملف index.js ، والذي سيحتوي على رمز المشروع:

 const express = require('express'); const app = express(); app.get('/', (req, res) => { res.send('The best way to manage your Node app using Docker\n'); }); app.listen(3000); console.log('Running on http://localhost:3000'); 

كما ترون ، فقد وصفنا هنا خادمًا بسيطًا يعرض بعض النص استجابةً لطلباته.

إنشاء Dockerfile


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

Dockerfile هو ملف نصي يحتوي على إرشادات لإنشاء صورة Docker لتطبيق ما. تصف الإرشادات الموجودة في هذا الملف ، إذا لم يتم الدخول في التفاصيل ، إنشاء طبقات لنظام الملفات متعدد المستويات ، والذي يحتوي على كل ما يحتاجه التطبيق للعمل. يمكن للنظام الأساسي Docker تخزين طبقات الصور في ذاكرة التخزين المؤقت ، والتي عند إعادة استخدام الطبقات الموجودة بالفعل في ذاكرة التخزين المؤقت ، تسرع عملية بناء الصور.

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

إنشاء Dockerfile فارغة:

 touch Dockerfile 

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

 FROM node:8 

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

 #   ARG APP_DIR=app RUN mkdir -p ${APP_DIR} WORKDIR ${APP_DIR} 

بما أننا نستخدم صورة Node ، فسيتم بالفعل تثبيت منصات Node.js و npm فيها. باستخدام ما هو موجود بالفعل في الصورة ، يمكنك تنظيم تثبيت تبعيات المشروع. باستخدام علامة --production (أو إذا NODE_ENV تعيين NODE_ENV البيئة NODE_ENV على production ) لن تقوم npm بتثبيت الوحدات النمطية المدرجة في قسم devDependencies من ملف devDependencies .

 #   COPY package*.json ./ RUN npm install #     # RUN npm install --production 

نحن هنا نقوم بنسخ ملف package*.json إلى الصورة ، بدلاً من ، على سبيل المثال ، نسخ جميع ملفات المشروع. نقوم بذلك فقط لأن تعليمات Dockerfile RUN و COPY و ADD تنشئ طبقات صور إضافية ، حتى تتمكن من استخدام ميزات التخزين المؤقت لطبقات النظام الأساسي Docker. من خلال هذا النهج ، في المرة التالية التي نجمع فيها صورة مماثلة ، سيعرف Docker ما إذا كان من الممكن إعادة استخدام طبقات الصور الموجودة بالفعل في ذاكرة التخزين المؤقت ، وإذا كان الأمر كذلك ، فستستفيد مما هو موجود بالفعل ، بدلاً من إنشاء طبقات جديدة طبقات. يتيح لك ذلك توفير الوقت بشكل خطير عند تجميع الطبقات أثناء العمل في المشروعات الكبيرة ، والتي تتضمن العديد من وحدات npm.

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

تحتوي تعليمات ADD ، بالمقارنة مع COPY ، على بعض الميزات ، والتي ، مع ذلك ، ليست مطلوبة دائمًا. على سبيل المثال ، نحن نتحدث عن خيارات لتفريغ أرشيفات .tar وتنزيل الملفات بواسطة عنوان URL.

 #    COPY . . 

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

 #   ,      EXPOSE 3000 

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

 #   CMD ["npm", "start"] 

إليك ما سيبدو عليه Dockerfile النهائي:

 FROM node:8 #   ARG APP_DIR=app RUN mkdir -p ${APP_DIR} WORKDIR ${APP_DIR} #   COPY package*.json ./ RUN npm install #     # RUN npm install --production #    COPY . . #   ,      EXPOSE 3000 #   CMD ["npm", "start"] 

تجميع الصور


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

 docker build --build-arg <build arguments> -t <user-name>/<image-name>:<tag-name> /path/to/Dockerfile 

في حالتنا ، سيبدو كما يلي:

 docker build --build-arg APP_DIR=var/app -t ankitjain28may/node-app:V1 . 

يحتوي Dockerfile على عبارة ARG تصف الوسيطة APP_DIR . هنا نضع معناها. إذا لم يتم ذلك ، فسيأخذ القيمة التي تم تعيينها إليه في الملف ، أي app .

بعد تجميع الصورة ، تحقق مما إذا كان Docker يراها. للقيام بذلك ، قم بتشغيل الأمر التالي:

 docker images 

استجابة لهذا الأمر ، يجب أن يكون الإخراج التالي تقريبًا.


صور عامل الميناء

إطلاق الصور


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

 docker run -p <External-port:exposed-port> -d --name <name of the container> <user-name>/<image-name>:<tag-name> 

في حالتنا ، سيبدو كما يلي:

 docker run -p 8000:3000 -d --name node-app ankitjain28may/node-app:V1 

سنطلب من النظام معلومات حول حاويات العمل باستخدام هذا الأمر:

 docker ps 

استجابة لهذا ، يجب على النظام إخراج شيء مثل التالي:


حاويات قفص الاتهام

حتى الآن ، كل شيء يسير كما هو متوقع ، على الرغم من أننا لم نحاول بعد الوصول إلى التطبيق الذي يعمل في الحاوية. وهي حاوية لدينا ، المسمى node-app ، تستمع على المنفذ 8000 . لمحاولة الوصول إليه ، يمكنك فتح متصفح والذهاب إليه في localhost:8000 . بالإضافة إلى ذلك ، للتحقق من صحة الحاوية ، يمكنك استخدام الأمر التالي:

 curl -i localhost:8000 

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


التحقق من صحة الحاوية

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

توصيات


فيما يلي بعض الاقتراحات التي تستحق الدراسة من أجل زيادة قوة Docker وإنشاء صور مضغوطة قدر الإمكان.

▍1. قم دائمًا بإنشاء ملف .dockerignore


في مجلد المشروع الذي تخطط لوضعه في الحاوية ، ستحتاج دائمًا إلى إنشاء ملف .dockerignore . يسمح لك بتجاهل الملفات والمجلدات غير المطلوبة عند إنشاء الصورة. باستخدام هذا النهج ، يمكننا تقليل سياق البنية المزعوم ، والذي سيتيح لنا تجميع الصورة بسرعة وتقليل حجمها. يدعم هذا الملف قوالب أسماء الملفات ، يشبه هذا الملف ملف .gitignore . يوصى بإضافة أمر إلى .dockerignore بسبب تجاهل /.git للمجلد / /.git ، لأن هذا المجلد يحتوي عادة على مواد كبيرة (خاصة أثناء تطوير المشروع) وإضافته إلى الصورة يؤدي إلى زيادة في حجمه. بالإضافة إلى ذلك ، فإن نسخ هذا المجلد إلى صورة لا معنى له.

▍2. استخدم عملية تجميع الصور متعددة المراحل


ضع في اعتبارك المثال عندما نجمع مشروعًا لمؤسسة معينة. يستخدم هذا المشروع العديد من حزم npm ، ويمكن لكل حزمة تثبيت حزم إضافية يعتمد عليها. يؤدي تنفيذ كل هذه العمليات إلى قضاء وقت إضافي في عملية تجميع الصورة (على الرغم من أن ذلك بفضل قدرات التخزين المؤقت لـ Docker ليس بالأمر الهين). والأسوأ من ذلك ، أن الصورة الناتجة التي تحتوي على تبعيات مشروع معين كبيرة جدًا. هنا ، إذا كنا نتحدث عن مشاريع الواجهة الأمامية ، فيمكننا أن نتذكر أن هذه المشاريع عادة ما تتم معالجتها باستخدام حزم مثل webpack ، والتي تجعل من الممكن بسهولة حزم كل ما يحتاجه التطبيق في عملية البيع. نتيجة لذلك ، ملفات حزمة npm لمثل هذا المشروع غير ضرورية. وهذا يعني أنه يمكننا التخلص من هذه الملفات بعد بناء المشروع باستخدام نفس webpack.

مسلحين بهذه الفكرة ، حاول القيام بذلك:

 #   COPY package*.json ./ RUN npm install --production # - COPY . . RUN npm run build:production #    npm- RUN rm -rf node_modules 

مثل هذا النهج ، لن يناسبنا. كما سبق وقلنا ، فإن تعليمات RUN و ADD و COPY تنشئ طبقات تم تخزينها مؤقتًا بواسطة Docker ، لذلك نحن بحاجة إلى إيجاد طريقة للتعامل مع تثبيت التبعيات وتجميع المشروع والإزالة اللاحقة للملفات غير الضرورية بأمر واحد. على سبيل المثال ، قد يبدو كالتالي:

 #      COPY . . #  ,      RUN npm install --production && npm run build:production && rm -rf node_module 

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

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

 FROM node:8 As build #  RUN mkdir /app && mkdir /src WORKDIR /src #   COPY package*.json ./ RUN npm install #     # RUN npm install --production #       COPY . . RUN npm run build:production #    ,     FROM node:alpine #      build   app COPY --from=build ./src/build/* /app/ ENTRYPOINT ["/app"] CMD ["--help"] 

من خلال هذا النهج ، تكون الصورة الناتجة أصغر بكثير من الصورة السابقة ، ونستخدم أيضًا node:alpine الصورة node:alpine ، وهي نفسها صغيرة جدًا. وهنا مقارنة بين زوج من الصور ، يمكن من خلالها أن نرى أن صورة node:alpine أصغر بكثير من صورة node:8 .


مقارنة الصور من مستودع العقدة

.3. استخدام عامل التخزين المؤقت


حاول استخدام قدرات التخزين المؤقت لـ Docker لإنشاء صورك. لقد سبق أن package*.json بهذه الميزة عند العمل مع ملف تم الوصول إليه بواسطة package*.json الاسم package*.json . هذا يقلل من وقت بناء الصورة. ولكن هذه الفرصة لا ينبغي أن تستخدم بتهور.

لنفترض أننا وصفنا في Dockerfile تثبيت حزم في صورة تم إنشاؤها من صورة Ubuntu:16.04 الأساسية Ubuntu:16.04 :

 FROM ubuntu:16.04 RUN apt-get update && apt-get install -y \   curl \   package-1 \   .   . 

عندما يقوم النظام بمعالجة هذا الملف ، إذا كان هناك الكثير من الحزم المثبتة ، فستستغرق عمليات التحديث والتثبيت الكثير من الوقت. لتحسين الموقف ، قررنا الاستفادة من قدرات التخزين المؤقت للطبقة في Docker وإعادة كتابة Dockerfile كما يلي:

 FROM ubuntu:16.04 RUN apt-get update RUN apt-get install -y \   curl \   package-1 \   .   . 

الآن ، عند تجميع الصورة لأول مرة ، كل شيء يسير كما ينبغي ، لأن ذاكرة التخزين المؤقت لم تتشكل بعد. تخيل الآن أننا بحاجة إلى تثبيت حزمة أخرى ، package-2 . للقيام بذلك ، نعيد كتابة الملف:

 FROM ubuntu:16.04 RUN apt-get update RUN apt-get install -y \   curl \   package-1 \   package-2 \   .   . 

نتيجة لهذا الأمر ، لن يتم تثبيت package-2 أو تحديثها. لماذا؟ الحقيقة هي أنه عند تنفيذ تعليمات RUN apt-get update ، لا يرى Docker أي فرق بين هذه التعليمات والتعليم الذي تم تنفيذه مسبقًا ، ونتيجة لذلك ، فإنه يأخذ البيانات من ذاكرة التخزين المؤقت. وهذه البيانات قديمة بالفعل. عند معالجة عملية RUN apt-get install تعليمة RUN apt-get install يقوم النظام بتنفيذها ، لأنه لا يبدو كأنه تعليمة مماثلة في Dockerfile السابق ، ولكن أثناء التثبيت ، قد تحدث أخطاء أو سيتم تثبيت الإصدار القديم من الحزم. نتيجة لذلك ، اتضح أنه يجب تنفيذ أوامر update والتثبيت ضمن نفس تعليمات RUN ، كما هو مذكور في المثال الأول. التخزين المؤقت ميزة رائعة ، لكن الاستخدام المتهور لهذه الميزة يمكن أن يؤدي إلى مشاكل.

▍4. تقليل عدد طبقات الصور


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

ملخص


في هذه المقالة ، نظرنا في عملية تعبئة تطبيقات Node.js في حاويات Docker والعمل مع هذه الحاويات. بالإضافة إلى ذلك ، قدمنا ​​بعض التوصيات التي ، بالمناسبة ، يمكن استخدامها ليس فقط عند إنشاء حاويات لمشاريع Node.js.

أعزائي القراء! إذا كنت تستخدم Docker بشكل احترافي عند العمل مع مشاريع Node.js ، فيرجى مشاركة التوصيات حول الاستخدام الفعال لهذا النظام مع المبتدئين.

Source: https://habr.com/ru/post/ar440656/


All Articles