عبد الصمد العماري

عند إنشائك لتطبيقات حديثة عديمة الحالة (stateless)، فإن عملية إعداد الحاويات لمكونات التطبيق ستكون هي الخطوة الأولى في النشر والتوسيع على الأنظمة الأساسية الموزعة. إذا كنت قد استخدمت Docker Compose في التطوير، فسوف تعمل على تحديث التطبيق وحاوياته بما يلي:

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

سيكون لديك أيضًا تعريفات خدمة مكتوبة تحدّد كيف ستشتغل صور حاوياتك.

لتشغيل خدماتك على نظام أساسي موزّع مثل Kubernetes، ستحتاج إلى ترجمة تعريفات خدمة Compose إلى كائنات Kubernetes. سيسمح لك ذلك بتوسيع نطاق تطبيقك بنوع من المرونة. وتعدّ kompose إحدى الأدوات التي يمكن أن تسرع عملية الترجمة إلى Kubernetes، وهي أداة تحويل تساعد المطورين على نقل سير عمل Compose إلى منسّق للحاويات مثل Kubernetes أو OpenShift.

سوف تعمل في هذا البرنامج التعليمي على ترجمة خدمات Compose إلى كائنات Kubernetes باستخدام kompose. ستستخدم تعريفات الكائنات التي توفرها kompose كنقطة بداية، كما ستجري تعديلات للتأكد من أن إعداداتك ستستخدم الأسرار (secrets) والخدمات (services) وطلبات وحدة التخزين الثابتة (PersistentVolumeClaims) على النحو المتوقّع في Kubernetes. عند نهاية الدرس، سيكون لديك تطبيق Node.js بنسخة واحدة لقاعدة بيانات MongoDB تعمل على نظام Kubernetes. سيعكس هذا الإعداد وظائف الشيفرة الموضحة في كيفية إعداد تطبيق node.js لسير عملٍ يعتمد على الحاويات باستخدام Docker Compose وسيكون نقطة انطلاق جيدة لإنشاء حلّ جاهز للإنتاج يتناسب مع احتياجاتك.

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

  • عنقود Kubernetes 1.10+‎ مع تفعيل التحكم في الوصول المستند إلى الدور role-based access control (RBAC)‎. سيستخدم هذا الإعداد عنقود DigitalOcean Kubernetes، لكن تبقى لك حرية الاختيار في إنشاء عنقود باستخدام طريقة أخرى.
  • أداة سطر الأوامر kubectl المثبتة على جهازك المحلي أو خادم التطوير وإعدادها للاتصال بعنقودك. يمكنك قراءة المزيد حول تثبيت kubectl في التوثيق الرسمي.
  • Docker مثبت على جهازك المحلي أو خادم التطوير. إذا كنت تعمل على نظام أوبونتو 18.04، اتبع الخطوتين 1 و 2 لكيفية تثبيت واستخدام Docker على أوبونتو 18.04؛ خلاف ذلك، اتبع التوثيق الرسمي للحصول على معلومات حول التثبيت على أنظمة التشغيل الأخرى. تأكد من إضافة مستخدمك غير الجذري إلى مجموعة Docker، كما هو موضح في الخطوة 2 من البرنامج التعليمي المرتبط.
  • حساب Docker Hub. للحصول على نظرة عامة حول كيفية إعداده، راجع هذه المقدمة إلى Docker Hub.

الخطوة الأولى: تثبيت kompose

للبدء في استخدام kompose، انتقل إلى صفحة إصدارات GitHub للمشروع، وانسخ الرابط إلى الإصدار الحالي. الصق هذا الرابط في الأمر curl التالي لتنزيل أحدث إصدار من kompose:

curl -L https://github.com/kubernetes/kompose/releases/download/v1.18.0/kompose-linux-amd64 -o kompose

للحصول على تفاصيل حول التثبيت على أنظمة غير تابعة لنظام لينكس، يرجى الرجوع إلى إرشادات التثبيت.

أنشئ الملف التنفيذي (binary):

chmod +x kompose

انقله إلى مسارك PATH:

sudo mv ./kompose /usr/local/bin/kompose

ثم تحقق من تثبيته بشكل صحيح. يمكنك إجراء فحص للإصدار:

kompose version

إذا كان التثبيت ناجحًا، فسيظهر لك الإخراج التالي:

Output
1.18.0 (06a2e56)

بعد تثبيت kompose وجاهزيته للاستخدام، يمكنك الآن استنساخ شيفرة المشروع Node.js الذي سيُترجَم إلى Kubernetes.

الخطوة الثانية: استنساخ وتحزيم التطبيق

لاستخدام تطبيقنا على Kubernetes، سنحتاج إلى استنساخ شيفرة المشروع وتحزيم التطبيق حتى تتمكن خدمة kubelet من سحب الصورة.

ستكون خطوتنا الأولى هي استنساخ مستودع node-mongo-docker-dev من حسابDigitalOcean Community GitHub. يتضمن هذا المستودع شيفرة الإعداد الموضح في كيفية إعداد تطبيق node.js لسير عملٍ يعتمد على الحاويات باستخدام Docker Compose، والذي يستخدم تطبيق Node.js لشرح كيفية إعداد بيئة تطوير باستخدام Docker Compose. يمكنك العثور على مزيد من المعلومات حول التطبيق نفسه في سلسلة من الحاويات إلى Kubernetes باستخدام Node.js.

استنسخ المستودع في مجلّد يسمى node_project:

git clone https://github.com/do-community/node-mongo-docker-dev.git node_project

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

cd node_project

يحتوي مجلّد node_project على ملفات ومجلدات لتطبيق معلومات سمك القرش الذي يعمل على مدخلات المستخدم. لقد حُدِّث للعمل على الحاويات وأزيلت منه معلومات التكوين الحساسة والمحددة في شيفرة التطبيق وأُعيد تشكيلها من أجل حقنها عند تنفيذ التطبيق، كما أُلغيَ تحميل حالة التطبيق إلى قاعدة بيانات MongoDB.

لمزيد من المعلومات حول تصميم التطبيقات الحديثة عديمة الحالة، يرجى الاطلاع على هيكلة التطبيقات ل Kubernetes وتحديث التطبيقات لKubernetes.

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

استخدم الأمر docker build لبناء الصورة باستخدام الراية t-، والتي تتيح لك تعليمها باسم لا يُنسى. في هذه الحالة، علّم الصورة باسم مستخدمك Docker Hub وسمّها node kubernetes أو أيّ اسم من اختيارك:

docker build -t your_dockerhub_username/node-kubernetes .

تحدد النقطة . في الأمر أن سياق البناء هو المجلّد الحالي.

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

docker images

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

Output
REPOSITORY                                TAG                 IMAGE ID            CREATED             SIZE
your_dockerhub_username/node-kubernetes   latest              9c6f897e1fbc        3 seconds ago       90MB
node                                      10-alpine           94f3c8956482        12 days ago         71MB

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

docker login -u your_dockerhub_username 

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

ارفع صورة التطبيق إلى Docker Hub باستخدام الأمر docker push. ولا تنس أن تعوّض yourdockerhubusername باسم مستخدمك Docker Hub:

docker push your_dockerhub_username/node-kubernetes

لديك الآن صورة للتطبيق يمكنك سحبها لتشغيل تطبيقك على Kubernetes. ستكون الخطوة التالية هي ترجمة تعريفات خدمة التطبيق إلى كائنات .Kubernetes

الخطوة الثالثة: ترجمة الخدمات إلى كائنات Kubernetes باستخدام kompose

يحدّد ملف Docker Compose، المسمى هنا docker-compose.yaml، التعريفات التي ستعمل على تشغيل خدماتنا على Compose. الخدمة في "Compose" هي عبارة عن حاوية قيد التشغيل، وتحتوي تعريفات الخدمة على معلومات حول كيفية تشغيل صورة كل حاوية. في هذه الخطوة، سوف نترجم هذه التعريفات إلى كائنات Kubernetes باستخدام kompose لإنشاء ملفات .yaml سوف تحتوي هذه الملفات على خصائص كائنات Kubernetes التي تصف الحالة التي نريدها عليها.

سوف نستخدم هذه الملفات لإنشاء أنواع مختلفة من الكائنات: أوّلها الخدمات، والتي ستضمن بقاء العُلَب (pods) التي تشغّل حاوياتنا متاحةً. ثانيها عمليّات النشر، والتي سوف تحتوي على معلومات حول الحالة التي نريد عليها العلب. ثالثها PersistentVolumeClaim لتوفير تخزين لقاعدة البيانات. رابعها خريطة الإعداد ConfigMap لمتغيرات البيئة التي تُحقَن في وقت التشغيل. وآخرها سرٌّ (secret) لمستخدم قاعدة بيانات التطبيق وكلمة المرور. ستكون بعض هذه التعريفات في الملفات التي سينشئها لناkompose ، والبعض الآخر سوف نحتاج إلى إنشائه بأنفسنا.

سنحتاج بدايةّ إلى تعديل بعض التعاريف في ملف docker-compose.yaml للعمل على Kubernetes. سنُضمّن إشارة إلى صورة التطبيق التي بُنيت حديثًا في تعريف خدمتنا nodejs، كما سنحذف الروابط bind mounts والحجوم والأوامر الإضافية التي استخدمناها لتشغيل حاوية التطبيق قيد التطوير باستخدام Compose. بالإضافة إلى ذلك، سنعيد تحديد سياسات إعادة تشغيل كلتا الحاويتين بحيث تتوافق مع السلوك الذي المتوقع في Kubernetes.

افتح الملف باستخدام nano أو المحرر المفضل لديك:

nano docker-compose.yaml

يبدو التعريف الحالي لخدمة تطبيق nodejs كما يلي:

...
services:
  nodejs:
    build:
      context: .
      dockerfile: Dockerfile
    image: nodejs
    container_name: nodejs
    restart: unless-stopped
    env_file: .env
    environment:
      - MONGO_USERNAME=$MONGO_USERNAME
      - MONGO_PASSWORD=$MONGO_PASSWORD
      - MONGO_HOSTNAME=db
      - MONGO_PORT=$MONGO_PORT
      - MONGO_DB=$MONGO_DB 
    ports:
      - "80:8080"
    volumes:
      - .:/home/node/app
      - node_modules:/home/node/app/node_modules
    networks:
      - app-network
    command: ./wait-for.sh db:27017 -- /home/node/app/node_modules/.bin/nodemon app.js
...

بعدها أَجرِ التعديلات التالية على تعريف الخدمة:

  • استخدم صورة node-kubernetes بدلاً من ملف Dockerfile المحلي.
  • عدّل سياسة إعادة تشغيل الحاوية restart من unless-stopped إلى always.
  • احذف قائمة الحجوم volumes وتعليمات الأوامر command.

سيبدو تعريف الخدمة النهائية الآن كما يلي:

...
services:
  nodejs:
    image: your_dockerhub_username/node-kubernetes
    container_name: nodejs
    restart: always
    env_file: .env
    environment:
      - MONGO_USERNAME=$MONGO_USERNAME
      - MONGO_PASSWORD=$MONGO_PASSWORD
      - MONGO_HOSTNAME=db
      - MONGO_PORT=$MONGO_PORT
      - MONGO_DB=$MONGO_DB 
    ports:
      - "80:8080"
    networks:
      - app-network
…

بعد ذلك، انزل إلى تعريف الخدمة db. ثم أجر التعديلات التالية:

  • غيّر سياسة إعادة التشغيل restart للخدمة always.

  • احذف ملف env. فبدلاً من استخدام قيمٍ من ملف env.، سنمرّر القيم الخاصة بـ MONGO_INITDB_ROOT_USERNAME و MONGO_INITDB_ROOT_PASSWORD إلى حاوية قاعدة البيانات باستخدام السّر Secret الذي سننشئه في الخطوة الرابعة.

سيبدو تعريف خدمة db الآن كما يلي:

...
  db:
    image: mongo:4.1.8-xenial
    container_name: db
    restart: always
    environment:
      - MONGO_INITDB_ROOT_USERNAME=$MONGO_USERNAME
      - MONGO_INITDB_ROOT_PASSWORD=$MONGO_PASSWORD
    volumes:  
      - dbdata:/data/db   
    networks:
      - app-network
... 

أخيرًا، في الجزء السفلي من الملف، احذف الحجوم node_modules من مفتاح المستوى الأعلى volumes. وسيبدو المفتاح عندها كما يلي:

...
volumes:
  dbdata:

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

سنحتاج، قبل ترجمة تعريفاتنا للخدمة، إلى كتابة ملف env. الذي سيستخدمه kompose لإنشاء خريطة الإعداد ConfigMap بمعلوماتنا غير الحساسة. الرجاء مراجعة الخطوة الثانية من كيفية إعداد تطبيق node.js لسير عملٍ يعتمد على الحاويات باستخدام Docker Compose للمزيد من التوضيح حول هذا الملف.

في ذلك الدرس، أضفنا env. إلى ملفنا gitignore. للتأكد من عدم نسخه إلى التحكم في الإصدار. هذا يعني أنه لم يُنسَخ عندما استنسخنا مستودع node-mongo-docker-dev في الخطوة الثانية من هذا الدرس. لذلك سوف نحتاج إلى إعادة إنشائه الآن.

أنشئ هذا الملف إذًا:

nano .env

سوف يستخدم kompose هذا الملف لإنشاء خريطة إعداد ConfigMap لتطبيقنا. ومع ذلك، بدلاً من تعيين كافة المتغيرات من تعريف خدمة nodejs في ملفنا Compose، سنضيف فقط اسم قاعدة البيانات MONGO_DB و MONGO_PORT. سنعيّن اسم المستخدم وكلمة المرور لقاعدة البيانات بشكل منفصل عندما ننشئ يدويًا كائنًا Secret في الخطوة الرابعة.

أضف معلومات المنفذ واسم قاعدة البيانات التالية إلى ملف env.. لا تتردد في إعادة تسمية قاعدة بياناتك إذا كنت ترغب في ذلك:

MONGO_PORT=27017
MONGO_DB=sharkinfo

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

أنت الآن مستعدّ لإنشاء الملفات اعتمادًا على خصائص كائنك. ويقدم لك kompose خيارات متعددة لترجمة مواردك. إذ تستطيع:

  • إنشاء ملفات yaml بناءً على تعريفات الخدمة في ملفك docker-compose.yaml باستخدام kompose convert.
  • إنشاء كائنات Kubernetes مباشرة باستخدام kompose up.
  • إنشاء مخطط Helm باستخدام kompose convert -c.

في الوقت الحالي، سنحوّل تعريفاتنا للخدمة إلى ملفات yaml ثم نضيف الملفات التي ينشئها kompose وننقّحها. استخدام الأمر التالي لتحويل تعريفات الخدمة إلى ملفات yaml:

kompose convert

يمكنك أيضًا تسمية ملفات تكوين محددة أو متعددة باستخدام الراية f-. بعد تنفيذ هذا الأمر، سيُخرِج kompose معلوماتٍ حول الملفات التي أنشأتها:

INFO Kubernetes file "nodejs-service.yaml" created 
INFO Kubernetes file "db-deployment.yaml" created 
INFO Kubernetes file "dbdata-persistentvolumeclaim.yaml" created 
INFO Kubernetes file "nodejs-deployment.yaml" created 
INFO Kubernetes file "nodejs-env-configmap.yaml" created 

يتضمّن هذا الإخراج الملفات yaml مع خصائص خدمة ونشر وخريطة إعداد تطبيق Node، وكذلك طلب وحدة التخزين الثابتة ل dbdata ونشر قاعدة بيانات MongoDB.

تعدّ هذه الملفات نقطة انطلاق جيدة، ولكن لكي تتطابق وظائف تطبيقنا مع الإعداد الموضح في كيفية إعداد تطبيق node.js لسير عملٍ يعتمد على الحاويات باستخدام Docker Compose، سنحتاج إلى إجراء بعض الإضافات والتغييرات على الملفات التي أنشأها kompose.

الخطوة الرابعة: إنشاء أسرار Kubernetes

لكي يعمل تطبيقنا بالطريقة التي نتوقعها، سنحتاج إلى إجراء بعض التعديلات على الملفات التي أنشأها kompose. أول هذه التغييرات هو إنشاء سرٍّ لمستخدم قاعدة البيانات وكلمة المرور وإضافتها إلى عمليات نشر التطبيق وقاعدة البيانات. ويقدّم Kubernetes طريقتين للعمل بمتغيرات البيئة: ConfigMap وSecret. وقد أنشأ kompose بالفعل خريطة إعداد ConfigMap بالمعلومات غير السرية التي ضمّنناها في ملفنا env.، لذلك سننشئ الآن سرًّا بمعلوماتنا السرية: اسم المستخدم وكلمة المرور لقاعدة البيانات.

ستكون الخطوة الأولى في إنشاء السّرِّ يدويًا هي تحويل اسم المستخدم وكلمة المرور إلى base64، وهو نظام ترميز يسمح لك بنقل البيانات بشكل موحد، بما في ذلك البيانات الثنائية.

حوّل أولا اسم مستخدم قاعدة بياناتك:

echo -n 'your_database_username' | base64

دوّن القيمة التي تظهر لك في الإخراج. بعد ذلك، حوّل كلمة مرورك:

echo -n 'your_database_password' | base64

دوّن القيمة الظاهرة في الإخراج هنا أيضا. افتح ملف السّر:

nano secret.yaml

ملاحظة: تُحدّد كائنات Kubernetes عادة باستخدام YAML الذي يمنع بصرامةٍ علامات التبويب ويتطلب مسافتين للمسافة البادئة. إذا كنت ترغب في التحقق من تنسيق أيٍّ من ملفاتك yaml ، فيمكنك استخدام linter أو اختبار صياغة (syntax) تركيبك باستخدام kubectl create مع الرايتين dry-run-- و validate--:

kubectl create -f your_yaml_file.yaml --dry-run --validate=true

يُستحسن بشكل عام التحقق من صحة الصياغة قبل إنشاء الموارد باستخدام kubectl.

أضف الشيفرة التالية إلى الملف لإنشاء سرٍّ يحدّد MONGO_USERNAME و MONGO_PASSWORD باستخدام القيم المشفرة التي أنشأتها للتو. تأكد من تعويض القيم الوهمية هنا باسم المستخدم وكلمة المرور المشفرة:

  • الملف ‎~/node_project/secret.yaml:
apiVersion: v1
kind: Secret
metadata:
  name: mongo-secret
data:
  MONGO_USERNAME: your_encoded_username
  MONGO_PASSWORD: your_encoded_password

لقد سمّينا كائن السرّ mongo-secret، ولكن يمكنك تسميته كما تشاء.

احفظ هذا الملف وأغلقه عند الانتهاء من التحرير. وكما فعلت مع ملفك env. ، تأكد من إضافة secret.yaml إلى ملفك gitignore. لإبقائه خارج نطاق التحكم في الإصدار.

بعد تحرير secret.yaml، ستكون خطوتنا التالية هي ضمان استخدام عُلَب كلّ من التطبيق وقاعدة البيانات للقيم التي أضفناها إلى الملف. لنبدأ بإضافة إشارات مرجعية إلى السّرّ Secret في نشر التطبيق.

افتح الملف المسمى nodejs-publish.yaml:

nano nodejs-deployment.yaml

تتضمن مواصفات حاوية الملف متغيرات البيئة التالية المحددة تحت مفتاح env:

apiVersion: extensions/v1beta1
kind: Deployment
...
    spec:
      containers:
      - env:
        - name: MONGO_DB
          valueFrom:
            configMapKeyRef:
              key: MONGO_DB
              name: nodejs-env
        - name: MONGO_HOSTNAME
          value: db
        - name: MONGO_PASSWORD
        - name: MONGO_PORT
          valueFrom:
            configMapKeyRef:
              key: MONGO_PORT
              name: nodejs-env
        - name: MONGO_USERNAME

سنحتاج إلى إضافة إشارات مرجعية إلى السرّ في متغيرات MONGO_USERNAME و MONGO_PASSWORD المدرجة هنا، حتى يتمكن تطبيقنا من الوصول إلى تلك القيم. وبدلاً من تضمين مفتاح configMapKeyRef للإشارة إلى خريطة الإعداد لnodejs-env ، كما هو الحال مع قيم MONGO_DB و MONGO_PORT،، سنُضمِّن مفتاح secretKeyRef للإشارة إلى القيم الموجودة في السرّ secret.

أضف إشارات السرّ المرجعية التالية إلى المتغيرين MONGO_USERNAME و MONGO_PASSWORD:

apiVersion: extensions/v1beta1
kind: Deployment
...
    spec:
      containers:
      - env:
        - name: MONGO_DB
          valueFrom:
            configMapKeyRef:
              key: MONGO_DB
              name: nodejs-env
        - name: MONGO_HOSTNAME
          value: db
        - name: MONGO_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mongo-secret
              key: MONGO_PASSWORD
        - name: MONGO_PORT
          valueFrom:
            configMapKeyRef:
              key: MONGO_PORT
              name: nodejs-env
        - name: MONGO_USERNAME
          valueFrom:
            secretKeyRef:
              name: mongo-secret
              key: MONGO_USERNAME

احفظ الملف وأغلقه عند الانتهاء من التحرير. بعد ذلك ، سنضيف القيم نفسها إلى ملف db-publish.yaml. افتح الملف للتحرير:

nano db-deployment.yaml

سنضيف في هذا الملف إشارات مرجعية إلى السرّ في مفاتيح المتغيرات التالية: MONGO_INITDB_ROOT_USERNAME و MONGO_INITDB_ROOT_PASSWORD. تجعل صورة mongo هذه المتغيرات متاحة لتتمكّن من تعديل تهيئة نسخة قاعدة بياناتك.

ينشئ MONGO_INITDB_ROOT_USERNAME وMONGO_INITDB_ROOT_PASSWORD معًا مستخدمًا جذرًا في قاعدة بيانات المشرف admin مع التأكد من تفعيل التصديق على الهوية عند بدء تشغيل حاوية قاعدة البيانات.

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

أضف أسفل متغيرات MONGO_INITDB_ROOT_USERNAME وMONGO_INITDB_ROOT_PASSWORD إشارات مرجعية إلى قيم السرّ Secret:

apiVersion: extensions/v1beta1
kind: Deployment
...
    spec:
      containers:
      - env:
        - name: MONGO_INITDB_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mongo-secret
              key: MONGO_PASSWORD        
        - name: MONGO_INITDB_ROOT_USERNAME
          valueFrom:
            secretKeyRef:
              name: mongo-secret
              key: MONGO_USERNAME
        image: mongo:4.1.8-xenial
…

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

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

الخطوة الخامسة: إنشاء خدمة قاعدة البيانات وحاوية التطبيق الأولية

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

للمزيد حول كيفية تنفيذ هذه الوظيفة في Compose، يرجى الاطلاع على الخطوة الرابعة من إعداد تطبيق node.js لسير عملٍ يعتمد على الحاويات باستخدام Docker Compose.

افتح ملفًا لتحديد مواصفات خدمة قاعدة البيانات:

nano db-service.yaml  

أضف الشيفرة التالية إلى الملف لتعريف الخدمة:

  • الملف ‎~/node_project/db-service.yaml:
apiVersion: v1
kind: Service
metadata:
  annotations: 
    kompose.cmd: kompose convert
    kompose.version: 1.18.0 (06a2e56)
  creationTimestamp: null
  labels:
    io.kompose.service: db
  name: db
spec:
  ports:
  - port: 27017
    targetPort: 27017
  selector:
    io.kompose.service: db
status:
  loadBalancer: {}

سيُطابِق المحدد selector الذي أدرجناه هنا كائن الخدمة هذا مع علب (Pods) قاعدة بياناتنا، والتي عُرِّفت بالتسمية io.kompose.service: db بواسطة kompose في ملف .db-publish.yaml لقد سمّينا أيضًا هذه الخدمة db.

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

بعد ذلك، دعنا نضيف حقلًا لحاوية أولية إلى المصفوفة containers في nodejs-deployment.yaml سيؤدي هذا إلى إنشاء حاوية أوّلية يمكننا استخدامها لتأخير حاوية تطبيقنا عن الاشتغال حتى إنشاء خدمة db ذات علبة يمكن الوصول إليها. وهذا هو أحد الاستخدامات المحتملة للحاويات الأولية. لمعرفة المزيد عن حالات الاستخدام الأخرى، يرجى الاطلاع على التوثيق الرسمي.

افتح الآن الملف nodejs-publish.yaml:

nano nodejs-deployment.yaml

داخل العلبة Pod وبجانب المصفوفة containers، سنضيف حقلًا initContainers بحاوية مهمتها استقصاء الخدمة db.

أضف الشيفرة التالية أسفل الحقلين ports وresources وفوق restartPolicy في مصفوفة nodejs containers:

  • الملف ‎~/node_project/nodejs-deployment.yaml:
apiVersion: extensions/v1beta1
kind: Deployment
...
    spec:
      containers:
      ...
        name: nodejs
        ports:
        - containerPort: 8080
        resources: {}
      initContainers:
      - name: init-db
        image: busybox
        command: ['sh', '-c', 'until nc -z db:27017; do echo waiting for db; sleep 2; done;']
      restartPolicy: Always
...               

تستخدم هذه الحاوية الأولية صورة BusyBox، وهي صورة خفيفة الوزن تتضمن العديد من أدوات UNIX. في هذه الحالة، سنستخدم الأداة netcat لاستقصاء هل تقبل العلبة المرتبطة بالخدمة db الاتصالات TCP على المنفذ 27017.

يكرّر أمر الحاوية command هذا وظيفة السكربت wait-for الذي حذفناه من الملف docker-compose.yaml في الخطوة الثالثة. لمزيد من التوضيح حول كيفية وعلّة استخدام تطبيقنا للسكربت wait-for ، يرجى الاطلاع على الخطوة الرابعة من كيفية إعداد تطبيق node.js لسير عملٍ يعتمد على الحاويات باستخدام Docker Compose.

تشتغل الحاويات الأولية وفق نظام run to completion. هذا يعني في حالتنا هذه أن حاوية التطبيق Node لن تبدأ في الاشتغال حتى تبدأ حاوية قاعدة البيانات في الاشتغال وقبول الاتصالات على المنفذ 27017. يسمح لنا تعريف الخدمة db بضمان هذه الوظيفة بغض النظر عن الموقع المحدّد لحاوية قاعدة البيانات، والذي يمكنه أن يتغيّر.

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

بعد إنشائك لخدمة قاعدة البيانات ووضعك لحاوياتك الأولية للتحكم في ترتيب اشتغال الحاويات، يمكنك الانتقال إلى التحقق من متطلبات التخزين في PersistentVolumeClaim وعرض خدمة تطبيقك باستخدام LoadBalancer.

الخطوة السّادسة: تعديل PersistentVolumeClaim وعرض الواجهة الأمامية للتطبيق

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

دعنا نعدل أولاً مورد التخزين storage resource المحدد في PersistentVolumeClaim الذي أنشأناه. تتيح لنا هذه المطالبة (claim) توفير مساحة تخزين ديناميكية لإدارة حالة التطبيق.

للعمل ب PersistentVolumeClaims، يجب أن يكون لديك صنف تخزين StorageClass أنشأته وأعددته لتوفير موارد التخزين. في حالتنا هذه، ونظرًا لأننا نعمل على DigitalOcean Kubernetes، يعيّن صنف التخزين provisioner الافتراضي على dobs.csi.digitalocean.com.

يمكننا التحقق من ذلك عبر كتابة ما يلي:

kubectl get storageclass

إذا كنت تعمل مع مجموعة DigitalOcean، فسترى الإخراج التالي:

NAME                         PROVISIONER                 AGE
do-block-storage (default)   dobs.csi.digitalocean.com   76m

إذا كنت لا تعمل على عنقود DigitalOcean، فستحتاج إلى إنشاء StorageClass وإعداد مزوّد من اختيارك. للحصول على تفاصيل حول كيفية القيام بذلك، يرجى الاطلاع على التوثيق الرسمي.

عندما ينشئ kompose الملف dbdata-persistentvolumeclaim.yaml، فإنه يعيّن مورد التخزين storage resource على سعةٍ لا تلبي الحدّ المطلوب في مزوّد الخدمة لدينا. لذلك، سنحتاج إلى تعديل PersistentVolumeClaim الخاص بنا لاستخدام السعة الدنيا القابلة للتطبيق لوحدة تخزين DigitalOcean Block المحدّدة في 1 جيجابايت. ويمكنك تعديل هذه القيمة لتلبية متطلبات التخزين الخاصة بك.

افتح الملفّ dbdata-persistentvolumeclaim.yaml:

nano dbdata-persistentvolumeclaim.yaml

عوّض قيمة التخزين storage بـ 1Gi:

  • الملف ‎~/node_project/dbdata-persistentvolumeclaim.yaml:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  creationTimestamp: null
  labels:
    io.kompose.service: dbdata
  name: dbdata
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
status: {}

لاحظ أيضًا أنّ accessMode: ReadWriteOnce يعني أن الحجم المتوفّر كنتيجة لهذه الطلب سيكون للقراءة والكتابة من خلال عقدة واحدة فقط. يرجى الاطلاع على التوثيق لمزيد من المعلومات حول أوضاع الوصول المختلفة.

احفظ الملف وأغلقه عند الانتهاء. بعد ذلك، افتح nodejs-service.yaml:

nano nodejs-service.yaml

سنعمل على الكشف عن هذه الخدمة خارجيًا باستخدام ‎.DigitalOcean Load Balancer إذا كنت لا تستخدم عنقود DigitalOcean، فيرجى الرجوع إلى التوثيق ذا الصلة من مزوّد الخدمة السحابية للحصول على معلومات حول موازِنات الحمل الخاصة به. بدلاً من ذلك، يمكنك اتباع توثيق Kubernetes الرسمية الخاصة بإعداد عنقود عالي التوفّر باستخدام kubeadm، لكن في هذه الحالة لن تتمكن من استخدام PersistentVolumeClaims لتوفير التخزين.

حدّد ضمن مواصفات الخدمة، LoadBalancer في الحقل type الخاصّ بالخدمة:

  • الملف ‎~/node_project/nodejs-service.yaml:
apiVersion: v1
kind: Service
...
spec:
  type: LoadBalancer
  ports:
...

عندما ننشئ خدمة nodejs، سيُنشَأ مُوازِن للتحميل تلقائيًا، مما يوفر لنا عنوانًا خارجيًا IP يمكِّننا من الوصول إلى تطبيقنا.

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

الخطوة السابعة: بدء التطبيق والوصول إليه

لقد حان الوقت لإنشاء كائنات Kubernetes واختبار عمل التطبيق على النحو المتوقع.

لإنشاء الكائنات التي حددناها، سنستخدم kubectl create مع الراية f-، والتي سوف تتيح لنا تحديد الملفات التي أنشأها لنا Compose، بالإضافة إلى الملفات التي حرّرناها. نفّذ الأمر التالي لإنشاء تطبيق Node وخدمات قاعدة بيانات MongoDB وعمليات النشر، مع Secret وConfigMap وPersistentVolumeClaim:

kubectl create -f nodejs-service.yaml,nodejs-deployment.yaml,nodejs-env-configmap.yaml,db-service.yaml,db-deployment.yaml,dbdata-persistentvolumeclaim.yaml,secret.yaml

سيظهر لك الإخراج التالي مشيرًا إلى إنشاء الكائنات:

Output
service/nodejs created
deployment.extensions/nodejs created
configmap/nodejs-env created
service/db created
deployment.extensions/db created
persistentvolumeclaim/dbdata created
secret/mongo-secret created

للتحقق من اشتغال العلب Pods، اكتب ما يلي:

kubectl get pods

لا تحتاج إلى تحديد فضاء اسم (namespace) هنا، لأننا أنشأنا كائناتنا في مساحة اسمية الافتراضية. إذا كنت تعمل على مساحات اسمية متعددة، فتأكد من تضمين الراية n- عند تنفيذ هذا الأمر، بالإضافة إلى اسم مساحتك الاسمية.

سيظهر لك الإخراج التالي أثناء بدء تشغيل الحاوية db وحاوية تطبيقك الأولية:

Output
NAME                      READY   STATUS              RESTARTS   AGE
db-679d658576-kfpsl       0/1     ContainerCreating   0          10s
nodejs-6b9585dc8b-pnsws   0/1     Init:0/1            0          10s

بمجرد تشغيل تلك الحاوية وبدء تشغيل حاويات التطبيق وقاعدة البيانات، سيظهر لك هذا الإخراج:

Output
NAME                      READY   STATUS    RESTARTS   AGE
db-679d658576-kfpsl       1/1     Running   0          54s
nodejs-6b9585dc8b-pnsws   1/1     Running   0          54s

يشير Running STATUS إلى أن العلب الخاصة بك مرتبطة بالعُقَد وأن الحاويات المرتبطة بتلك العلب تعمل. ويشير READY إلى عدد الحاويات الموجودة في العلبة. لمزيد من المعلومات، يرجى الرجوع إلى توثيق دورة حياة العلبة.

ملحوظة: إذا رأيت مراحل غير متوقعة في العمود STATUS، تذكر أنه يمكنك استكشاف الأخطاء وإصلاحها باستخدام الأوامر التالية:

kubectl describe pods your_pod
kubectl logs your_pod

بعد تشغيل حاوياتك، يمكنك الآن الوصول إلى التطبيق. للحصول على العنوان IP الخاص بـ LoadBalancer، اكتب:

kubectl get svc

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

NAME         TYPE           CLUSTER-IP       EXTERNAL-IP      PORT(S)        AGE
db           ClusterIP      10.245.189.250   <none>           27017/TCP      93s
kubernetes   ClusterIP      10.245.0.1       <none>           443/TCP        25m12s
nodejs       LoadBalancer   10.245.15.56     your_lb_ip       80:30729/TCP   93s

العنوان EXTERNAL_IP المرتبط بخدمة nodejs هو عنوان IP يمكّنك من الوصول إلى التطبيق. إذا رأيت حالة <pending> في عمود EXTERNAL_IP،، فهذا يعني أن مُوازِن التحميل لا يزال قيد الإنشاء.

بمجرد رؤية عنوان IP في هذا العمود، انتقل إليه في متصفحك: http://your_lb_ip. ينبغي أن تظهر لك صفحة الهبوط التالية:

landing_page.png

انقر على زر الحصول على معلومات القرش. ستظهر صفحةّ فيها نموذج إدخال حيث يمكنك إدخال اسم سمك القرش ووصف لسلوكه العام:

shark_form.png

أضف في النموذج سمكة قرش من اختيارك. للتوضيح، سنضيف Megalodon Shark إلى حقل Shark Name، وAncient لحقل Shark Character:

shark_filled.png

انقر على زر الإرسال. ستظهر صفحة بها معلومات القرش معروضة لك:

shark_added.png

لديك الآن إعداد نسخة واحدة لتطبيق Node.js بقاعدة بيانات MongoDB تعمل على عنقود Kubernetes.

خاتمة

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

ترجمة -وبتصرف- للمقال How To Migrate a Docker Compose Workflow to Kubernetes لصاحبته Kathleen Juell

 

 





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


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



يجب أن تكون عضوًا لدينا لتتمكّن من التعليق

انشاء حساب جديد

يستغرق التسجيل بضع ثوان فقط


سجّل حسابًا جديدًا

تسجيل الدخول

تملك حسابا مسجّلا بالفعل؟


سجّل دخولك الآن