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

إعداد تطبيق جانغو بواسطة Postgres وخادم إنجن إكس Nginx وGunicorn


Mostafa Almahmoud

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

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

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

ستحتاج قبل المتابعة في هذه المقالة إلى خادم أوبنتو 18.04 مُعد وجاهز وإلى مستخدم غير جذر يتمتع بصلاحيات "sudo" مهيأة وإلى جدار ناري مُفعّل. راجع دليل إعداد خادم أوبنتو 18.04 مبدئي للبدء.

الخطوة الأولى - تثبيت الحزم البرمجية من مستودعات أوبنتو

ابدأ بتنزيل وتثبيت جميع العناصر التي تحتاجها من مستودعات أوبنتو. استخدم مدير حزم بايثون pip لتثبيت مكونات إضافية لاحقة.

حدّث في البداية دليل الحزم apt المحلي:

$ sudo apt update

ثم ثبّت الحزم بحسب إصدار بايثون الذي يستخدمه مشروعك، فإذا كنت تستخدم جانغو مع بايثون 3 فنفذ الأمر التالي:

$ sudo apt install python3-pip python3-dev libpq-dev postgresql postgresql-contrib nginx curl

ننبه إلى أن جانغو 1.11 هو آخر إصدار من جانغو يدعم بايثون 2. لذلك، إذا كنت ستتفتح مشاريع جديدة، فننصحك باختيار بايثون 3، لكن إذا كنت ما تزال تريد استخدام بايثون 2 فنفّذ الأمر التالي:

$ sudo apt install python-pip python-dev libpq-dev postgresql postgresql-contrib nginx curl

سيثبت هذا pip وملفات تطوير بايثون اللازمة لبناء غوني كورن لاحقًا، وسيثبت أيضًا نظام قواعد بيانات Postgres والمكتبات اللازمة للتفاعل معها وخادم الويب إنجن إكس.

الخطوة الثانية - إنشاء قاعدة بيانات PostgreSQL ومستخدم لها

ستنشئ في هذه الخطوة قاعدة بيانات مع مستخدم قاعدة بيانات لتطبيق جانغو الخاص بك مع PostgreSQL -أو اختصارًا Postgres.

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

أُنشئ أثناء تثبيتك لنظام Postgres مستخدم نظام تشغيل اسمه "postgres" ليكون نظيرًا للمستخدم الإداري لنظام PostgreSQL الذي اسمه "postgres"، إذ ستحتاج لحساب هذا المستخدم لإنجاز المهام الإدارية. سجل الدخول إلى جلسة Postgres تفاعلية باستخدام sudo ومرّر اسم المستخدم مستعملًا الخيار u-:

$ sudo -u postgres psql

سيظهر لك محث PostgreSQL، إذ يمكنك إعداد متطلباتك. أنشئ أولًا قاعدة بيانات لمشروعك:

postgres=# CREATE DATABASE myproject;

ملاحظة: يجب أن تنتهي كل تعليمة Postgres بفاصلة منقوطة، لذا تأكد من أنك طبقت هذه القاعدة إذا واجهت أي مشاكل.

أنشئ مستخدم قاعدة بيانات مشروعك واختر كلمة مرور قوية:

postgres=# CREATE USER myprojectuser WITH PASSWORD 'password';

وسيكون الخرج على النحو التالي:

CREATE ROLE

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

بدايةً اضبط قيمة الترميز الافتراضي default encoding إلى "UTF-8" التي يتوقعها جانغو:

postgres=# ALTER ROLE myprojectuser SET client_encoding TO 'utf8';

وسيكون الخرج على النحو التالي:

ALTER ROLE

ثم حدّد مخطط عزل الإجراءات الافتراضي بالقيمة "read committed" لمنع عمليات القراءة من المعاملات التي لم تودع بعد uncommitted:

postgres=# ALTER ROLE myprojectuser SET default_transaction_isolation TO 'read committed';

وسيكون الخرج على النحو التالي:

ALTER ROLE

نظرًا لأن مشاريع جانغو ستُضبط على استخدام النطاق الزمني "UTC" افتراضيًّا، لذا حدد النطاق الزمني المناسب:

postgres=# ALTER ROLE myprojectuser SET timezone TO 'UTC';

وسيكون الخرج على النحو التالي:

ALTER ROLE

كل هذه طبعًا توصيات من مشروع جانغو.

الآن، اِمنح مستخدمك الجديد وصولًا إلى قاعدة بياناتك الجديدة ليتمكن من إدارتها:

postgres=# GRANT ALL PRIVILEGES ON DATABASE myproject TO myprojectuser;

وسيكون الخرج على النحو التالي:

GRANT

وبعد أن تنتهي، غادر محث PostgreSQL بتنفيذ الأمر التالي:

postgres=# \q

وبهذا يكون POstgreSQL الآن معدًّا بنجاح بحيث يمكن لجانغو الاتصال بمعلومات قاعدة البيانات وإدارتها.

الخطوة الثالثة - إنشاء بيئة بايثون افتراضية لمشروعك

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

ستحتاج لإنجاز ذلك إلى وصول إلى الأمر virtualenv الذي ينشئ البيئات الافتراضية. ابدأ بتثبيت هذا الأمر مستخدمًا pip، وإذا كنت تستخدم بايثون 3 فلا بُد من ترقية pip:

$ sudo -H pip3 install --upgrade pip

ثم ثبّت الحزمة:

$ sudo -H pip3 install virtualenv

إذا كنت تستخدم بايثون 2 فلا بُد من ترقية pip:

$ sudo -H pip install --upgrade pip

ثم ثبّت الحزمة:

$ sudo -H pip install virtualenv

مع تثبيت virtualenv، يمكنك البدء في تشكيل مشروعك. أنشئ أولًا المجلد الذي ستحفظ فيه ملفات مشروعك. سنسميه نحن هنا "myprojectdir" ويمكنك تسميته ما تشاء.

$ mkdir ~/myprojectdir

ثم انتقل إلى داخل المجلد:

$ cd ~/myprojectdir

ثم أنشئ بيئة بايثون الافتراضية داخل مجلد المشروع:

$ virtualenv myprojectenv

سينشئ هذا مجلدًا اسمه "myprojectenv" ضمن مجلد "myprojectdir"، وسيثبت داخله نسخةً محليةً من بايثون ونسخةً محليةً من pip. يمكنك استخدام هذا لتثبيت وضبط بيئة بايثون تعزل مشروعك عن بقية المشاريع.

لكن قبل تثبيت متطلبات بايثون لمشروعك ستحتاج إلى تفعيل البيئة الافتراضية:

$ source myprojectenv/bin/activate

يجب أن يتغير المحث الآن ليشير إلى أنك الآن تعمل ضمن بيئة بايثون افتراضية. سيبدو هذا مشابهًا لما يلي:

(myprojectenv)user@host:~/myprojectdir$

وهكذا بعد أن أصبحت بيئتك الافتراضية فعالة، ثبّت جانغو وغوني كورن وموائم PostgreSQL adaptor، اسمه psycopg2 بالنسخة المحلية من pip:

pip install django gunicorn psycopg2-binary

ملاحظة::عندما تُفعّل البيئة الافتراضية، أي عندما يُسبق المحث باسم المجلد "(myprojectenv)"، استخدم pip بدلًا من pip3 حتى لو كنت تستخدم بايثون 3. تُسمى نسخة الأداة للبيئة الافتراضية دائمًا باسم "pip"، بغض النظر عن نسخة بايثون.

الآن أصبح لديك كل البرمجيات اللازمة للبدء في مشروع جانغو.

الخطوة الرابعة - إنشاء وضبط مشروع جانغو جديد

بعد أن ثُبّتت مكونات بايثون، أصبح بإمكانك إنشاء ملفات مشروع جانغو الفعلية، وبما أن مجلد المشروع أصبح جاهزًا فيمكنك أن تطلب من جانغو أن يثبت الملف هنا، إذ سينشئ عندئذٍ مجلدًا في المستوى الثاني مع الشيفرة الفعلية وهذا أمرٌ طبيعي وسيضع سكريبت إدارة في هذا المجلد؛ وهذا مهمٌّ أنك تعرّف المجلد صراحةً بدلًا من السماح لجانغو باتخاذ قرارات متعلقة بمجلدك الحالي:

(myprojectenv) $ django-admin.py startproject myproject ~/myprojectdir

في هذه النقطة ستكون محتويات مجلد المشروع (في حالتنا هو "myprojectdir/~") هي:

  • "myprojectdir/manage.py/~": سكريبت إدارة مشروع جانغو.
  • "/myprojectdir/myproject/~": حزمة مشروع جانغو. سيحتوي هذا على الملفات: "init__.py__" و "settings.py" و "urls.py" و "wsgi.py".
  • "/myprojectdir/myprojectenv/~": مجلد البيئة الافتراضية الذي أنشأته من قبل.

تتمثل المرحلة التالية في ضبط الإعدادات لملفات المشروع الجديدة. افتح ملف الإعدادات بمحرر النصوص المفضل لديك. سنستخدم نحن محرر النصوص نانو nano:

(myprojectenv) $ nano ~/myprojectdir/myproject/settings.py

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

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

. . .
# The simplest case: just add the domain name(s) and IP addresses of your Django server
# ALLOWED_HOSTS = [ 'example.com', '203.0.113.5']
# To respond to 'example.com' and any subdomains, start the domain with a dot
# ALLOWED_HOSTS = ['.example.com', '203.0.113.5']
ALLOWED_HOSTS = ['your_server_domain_or_IP', 'second_domain_or_IP', . . ., 'localhost']

ملاحظة: تأكد من تضمين "localhost" ضمن الخيارات، لأنك ستحيلُ proxying الاتصالات من خلال نسخة إنجن إكس محلية.

ثم أوجد القسمَ الذي يضبط الوصول إلى قاعدة البيانات، وهو يبدأ بالكلمة DATABASES.الضبط الموجود مسبقًا في الملف هو لقاعدة بيانات SQLite، ولكن نظرًا لأنك أنشأت قاعدة بيانات PostgreSQL لمشروعك فلا بُد من ضبط هذه الإعدادات.

حدّث الإعدادات بمعلومات قاعدة بيانات PostgreSQL، ثم أخبر جانغو أن يستخدم الملائم psycopg2 الذي ثبتته باستخدام pip. تحتاج أيضًا إلى التزويد باسم قاعدة البيانات واسم المستخدم لمستخدم قاعدة البيانات الذي أنشأته توًّا وكلمة المرور لمستخدم قاعدة البيانات والتحديد أيضًا بإمكانية العثور على قاعدة البيانات على الحاسوب المحلي، أما الإعداد PORT فيمكنك تركه سلسلةً فارغة:

. . .

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'myproject',
        'USER': 'myprojectuser',
        'PASSWORD': 'password',
        'HOST': 'localhost',
        'PORT': '',
    }
}

. . .

ثم اذهب إلى نهاية الملف وأضف إعدادًا يشير إلى المكان الذي ينبغي أن توضع فيه الملفات الساكنة؛ وهذا ضروري ليتمكن إنجن إكس من معالجة الطلبات لتلك العناصر. يخبر السطر التالي جانغو أن يضع تلك الملفات الساكنة في مجلدٍ اسمه "static" في مجلد المشروع الأساسي:

. . .

STATIC_URL = '/static/'
import os
STATIC_ROOT = os.path.join(BASE_DIR, 'static/')

احفظ الملف ثم أغلقه عندما تنتهي، وإذا كنت تستخدم محرر النصوص نانو يمكنك فعل ذلك بالضغط على المفتاحين "CTRL + X"، ثم المفتاح "Y و "ENTER".

الخطوة الخامسة - إكمال الإعداد المبدئي للمشروع

ستكون الخطوة التالية تهجير مخطط قاعدة البيانات المبدئي إلى قاعدة بيانات PostgreSQL باستخدام سكريبت الإدارة التالي:

(myprojectenv) $ ~/myprojectdir/manage.py makemigrations
(myprojectenv) $ ~/myprojectdir/manage.py migrate

أنشئ مستخدمًا إداريًّا للمشروع:

(myprojectenv) $ ~/myprojectdir/manage.py createsuperuser

سيطلب منك اسم مستخدم وبريد إلكتروني وكلمة مرور مع تأكيدها.

اجمع كل المحتوى الساكن في موقع المجلد الذي ضبطته بتنفيذ الأمر التالي:

(myprojectenv) $ ~/myprojectdir/manage.py collectstatic

عندئذ ستوضع الملفات الساكنة في مجلد اسمه "static" ضمن مجلد المشروع.

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

(myprojectenv) $ sudo ufw allow 8000

أخيرًا افحص مشروعك بتشغيل خادم تطوير جانغو من خلال الأمر التالي:

(myprojectenv) $ ~/myprojectdir/manage.py runserver 0.0.0.0:8000

في متصفح الويب استعرض اسم نطاق الخادم أو عنوان IP متبوعًا برقم المنفذ "8000:"، كما يلي:

http://server_domain_or_IP:8000

عندئذ ستظهر لك الصفحة التالية وهي صفحة دليل جانغو الافتراضية:

صفحة دليل جانغو الافتراضية

إذا ألحقت "admin/" بنهاية عنوان URL في شريط العنوان، فسيُطلب منك اسم المستخدم وكلمة المرور الذين أنشأتهما بالأمر createsuperuser:

اسم المستخدم وكلمة المرور المضافين عبر بالأمر createsuperuser

يمكنك بعد الاستيثاق الوصول إلى واجهة جانغو الإدارية الافتراضية:

الوصول إلى واجهة جانغو الإدارية الافتراضية

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

الخطوة السادسة - اختبار قدرة غوني كورن على خدمة المشروع

اختبر الخادم غوني كورن قبل مغادرة البيئة الافتراضية للتأكد من أن بإمكانه أن يخدم التطبيق، وذلك من خلال الانتقال أولًا إلى داخل مجلد مشروعك:

(myprojectenv) $ cd ~/myprojectdir

ثم شغّل gunicorn ليحمّل وحدة WSGI للمشروع:

(myprojectenv) $ gunicorn --bind 0.0.0.0:8000 myproject.wsgi

سيشغل هذا الأمر خادم غوني كورن على نفس الواجهة التي كان يعمل عليها خادم تطوير جانغو. يمكنك العودة واختبار التطبيق مجددًا.

ملاحظة: لن يكون في الواجهة الإدارية أي أنماط مُطبّقة، لأن الخادم غوني كورن لا يعرف كيف يعثر على محتوى CSS الساكن المسؤول عن هذا الأمر.

لنلخص ما أنُجز، فقد مرّرتَ وحدةً إلى الخادم غوني كورن بتحديد مسار المجلد النسبي إلى ملف جانغو المسمى "wsgi.py" والذي يمثّل نقطة الدخول إلى تطبيقك باستخدام بنية وحدة بايثون. يُستخدم الخادم غوني كورن مثل واجهة لتطبيقك ويترجم طلبات العملاء من نوع HTTP إلى استدعاءات بايثون يمكن لتطبيقك معالجتها. أما داخل هذا الملف، فقد عُرّفت دالة application، التي تُستخدم للتواصل مع تطبيقك. وبإمكانك معرفة المزيد عن مواصفات WSGI إذا كنت مهتمًا بهذا الموضوع.

بعد أن تفرغ من الاختبار، اضغط على المفتاحين "CTRL + C" في نافذة الطرفية لإيقاف تشغيل الخادم غوني كورن، وبهذا تكون انتهيت من ضبط تطبيق جانغو وبإمكانك إلغاء تفعيل بيئتك الافتراضية:

(myprojectenv) $ deactivate

سيُحذف مؤشر البيئة الافتراضية في المحثّ الظاهر أمامك.

الخطوة السابعة - إنشاء مقبس systemd وملفات خدمة لخادم غوني كورن

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

سينُشأ مقبس غوني كورن عند الإقلاع ويبدأ بالاستماع للاتصالات، وعندما يحدث اتصال ستشغِّل خدمة systemd تلقائيًّا عملية غوني كورن لمعالجة الاتصال.

ابدأ بإنشاء وفتح ملف مقبس systemd لخادم غوني كورن مع صلاحيات sudo في محرر النصوص المفضل لديك:

$ sudo nano /etc/systemd/system/gunicorn.socket

أنشئ داخل الملف القسم [Unit] لوصف المقبس والقسم [Socket] لتعريف موقع المقبس والقسم [Install] للتأكد من أن المقبس يُنشأ في الوقت المناسب:

[Unit]
Description=gunicorn socket

[Socket]
ListenStream=/run/gunicorn.sock

[Install]
WantedBy=sockets.target

احفظ الملف وأغلقه عندما تنتهي، ثم أنشئ وافتح ملف خدمة systemd من أجل غوني كورن مع صلاحيات sudo في محرر النصوص المفضّل لديك، ويجب أن يطابق اسم ملف الخدمة اسم ملف المقبس باستثناء الامتداد:

$ sudo nano /etc/systemd/system/gunicorn.service

ابدأ بالقسم [Unit] المُستَخدم لتحديد البيانات الوصفية metadata والاعتماديات. أضف وصفًا لخدمتك هنا وأخبر نظام التهيئة "init system" أن يشغّل الخدمة فقط بعد الوصول إلى مستوى التشبيك المستهدف networking target. نظرًا لأن خدمتك تعتمد على المقبس من ملف المقبس، فستحتاج إلى تضمين الموجّه Requires للإشارة إلى تلك العلاقة:

[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target

ثم أضف القسم [Service] وحدّد المستخدم والمجموعة اللذين تريد أن تعمل العملية تحتهما. زوّد ملكيتك للعملية من خلال حساب مستخدم نظامي لأنها تمتلك كل الملفات المرتبطة، ثم زوّد ملكية مجموعتك إلى مجموعة "www-data" ليتمكن الخادم إنجن إكس من التواصل مع خادم غوني كورن.

بعد ذلك، ارسم خطة المجلد العامل وحدّد الأمر الذي ستنفّذه لتشغيل العملية، وفي حالتنا هذه حدّد المسار الكامل للملف التنفيذي للخادم غوني كورن المثبت ضمن بيئتك الافتراضية، ثم اربط العملية بمقبس يونيكس Unix الذي أنشأته ضمن المجلد "run/" لكي تتمكن العملية من التواصل مع خادم إنجن إكس. سجّل كافة البيانات على أداة الخرج المعياري لكي تتمكن العملية journald من جمع سجلات الخادم غوني كورن. يمكنك أيضًا هنا تحديد أي إضافات اختيارية لخادم غوني كورن، إذ حدّدنا في مثالنا ثلاث عمليات عاملة على النحو التالي:

[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target

[Service]
User=sammy
Group=www-data
WorkingDirectory=/home/sammy/myprojectdir
ExecStart=/home/sammy/myprojectdir/myprojectenv/bin/gunicorn \
          --access-logfile - \
          --workers 3 \
          --bind unix:/run/gunicorn.sock \
          myproject.wsgi:application

أخيرًا، أضف القسم [Install] الذي سيخبر systemd بماذا ستربط هذه الخدمة إذا فعّلتها للعمل عند الإقلاع، إذ أن الأفضل أن تعمل هذه الخدمة عندما يكون نظام المستخدمين المتعددين النظامي يعمل على النحو الصحيح والمطلوب:

[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target

[Service]
User=sammy
Group=www-data
WorkingDirectory=/home/sammy/myprojectdir
ExecStart=/home/sammy/myprojectdir/myprojectenv/bin/gunicorn \
          --access-logfile - \
          --workers 3 \
          --bind unix:/run/gunicorn.sock \
          myproject.wsgi:application

[Install]
WantedBy=multi-user.target

وبهذا يكتمل ملف خدمة systemd، والآن احفظ الملف وأغلقه، ثم شغّل مقبس غوني كورن. سينشئ هذا ملف المقبس في المسار "run/gunicorn.sock/" الآن وكذلك عند الإقلاع:

$ sudo systemctl start gunicorn.socket

ثم فعّله بحيث تشغّل systemd تلقائيًا خدمة gunicorn.service عندما يحدث اتصال مع ذاك المقبس لتتولى معالجته:

$ sudo systemctl enable gunicorn.socket

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

الخطوة الثامنة - التحقق من وجود ملف مقبس غوني كورن

افحص حالة العملية لتعرف ما إذا كانت قابلة للتشغيل:

$ sudo systemctl status gunicorn.socket

وسيكون الخرج على النحو التالي:

 gunicorn.socket - gunicorn socket
     Loaded: loaded (/etc/systemd/system/gunicorn.socket; enabled; vendor prese>
     Active: active (listening) since Thu 2021-12-02 19:58:48 UTC; 14s ago
   Triggers:  gunicorn.service
     Listen: /run/gunicorn.sock (Stream)
      Tasks: 0 (limit: 1136)
     Memory: 0B
     CGroup: /system.slice/gunicorn.socket

Dec 02 19:58:48 gunicorn systemd[1]: Listening on gunicorn socket.

ثم تحقق من وجود الملف "gunicorn.sock" ضمن المجلد "run/":

$ file /run/gunicorn.sock

وسيكون الخرج على النحو التالي:

/run/gunicorn.sock: socket

إذا أشار الأمرsystemctl status إلى حدوث خطأ، أو إذا لم تجد الملف "gunicorn.sock" في المجلد فإن هذه إشارة أننا لم ننجح في إنشاء مقبس غوني كورن. تفقّد سجلات مقبس غوني كورن بتنفيذ الأمر التالي:

$ sudo journalctl -u gunicorn.socket

افحص الملف "etc/systemd/system/gunicorn.socket/" لإصلاح أي مشاكل قبل المتابعة.

الخطوة التاسعة - فحص تنشيط المقبس

إذا شغلت فقط الوحدة gunicorn.socket، لن تكون الخدمة gunicorn.service نشطةً لأن المقبس لن يكون قد استقبل أي اتصالات. لذلك افحص الحالة:

$ sudo systemctl status gunicorn

وسيكون الخرج على النحو التالي:

 gunicorn.service - gunicorn daemon
   Loaded: loaded (/etc/systemd/system/gunicorn.service; disabled; vendor preset: enabled)
   Active: inactive (dead)

لفحص آلية تنشيط المقبس، أرسل اتصالًا إلى المقبس عبر curl:

$ curl --unix-socket /run/gunicorn.sock localhost

يفترض أن تتلقى خرج HTML من تطبيقك في الطرفية، وهذا يؤكد إقلاع خادم غوني كورن وأنه قادر على خدمة تطبيق جانغو الخاص بك. يمكنك التحقق من أن خدمة غوني كورن تعمل من خلال فحص الحالة مرة أخرى:

$ sudo systemctl status gunicorn

وسيكون الخرج على النحو التالي:

  gunicorn.service - gunicorn daemon
   Loaded: loaded (/etc/systemd/system/gunicorn.service; disabled; vendor preset
   Active: active (running) since Tue 2021-11-23 22:55:12 UTC; 11s ago
 Main PID: 11002 (gunicorn)
    Tasks: 4 (limit: 1151)
   CGroup: /system.slice/gunicorn.service
           ├─11002 /home/sammy/myprojectdir/myprojectenv/bin/python /home/sammy/
           ├─11018 /home/sammy/myprojectdir/myprojectenv/bin/python /home/sammy/
           ├─11020 /home/sammy/myprojectdir/myprojectenv/bin/python /home/sammy/
           └─11022 /home/sammy/myprojectdir/myprojectenv/bin/python /home/sammy/
. . .

إذا أشار الخرج من جرّاء تنفيذ curl أو الخرج من systemctl status إلى أن مشكلةً قد وقعت، افحص سجلات التفاصيل الإضافية:

$ sudo journalctl -u gunicorn

افحص الملف "etc/systemd/system/gunicorn.service/" بحثًا عن المشاكل، وإذا أجريت تغييرات على الملف "etc/systemd/system/gunicorn.service/"، فأعد تحميل العملية الخفية daemon لإعادة قراءة تعريف الخدمة:

$ sudo systemctl daemon-reload

ثم أعد تشغيل خدمة غوني كورن:

$ sudo systemctl restart gunicorn

إذا ظهرت أي مشاكل مثل هذه، فأصلحها قبل المتابعة.

الخطوة العاشرة - ضبط الخادم إنجن إكس لتمرير الخادم الوكيل إلى خادم غوني كورن

الآن بعد إعداد غوني كورن، ستضبط الخادم إنجن إكس لتمرير حركة البيانات في الشبكة إلى العملية. ابدأ بإنشاء وفتح كتلة خادم جديدة في مجلد إنجن إكس المسمى "sites-available" كما يلي:

$ sudo nano /etc/nginx/sites-available/myproject

افتح داخله كتلة خادم جديدة، وابدأ بتحديد أن هذه الكتلة ينبغي أن تستمع على المنفذ الطبيعي 80 وأن تستجيب لاسم نطاق خادمك أو عنوان IP الخاص به:

server {
    listen 80;
    server_name server_domain_or_IP;
}

ثم اطلب من الخادم إنجن إكس أن يتجاهل أي مشاكل متعلقة بإيجاد الأيقونة المفضلة favicon، وأخبره أيضًا أين يجد الأصول الساكنة التي جمعتها في مجلدك المسمى "myprojectdir/static/~". تمتلك جميع هذه الملفات سابقة URI معيارية بقيمة "static/"، لذا يمكنك إنشاء كتلة موقع لمطابقة تلك الطلبات:

server {
    listen 80;
    server_name server_domain_or_IP;

    location = /favicon.ico { access_log off; log_not_found off; }
    location /static/ {
        root /home/sammy/myprojectdir;
    }
}

أخيرًا، أنشئ كتلة location / {}‎ لمطابقة كافة الطلبات الأخرى، وضمّن داخلَ هذا الموقع الملفَّ المعياري "proxy_params" من تثبيت إنجن إكس، ثم حدّد حركة مرور بيانات الشبكة مباشرةً إلى مقبس غوني كورن:

server {
    listen 80;
    server_name server_domain_or_IP;

    location = /favicon.ico { access_log off; log_not_found off; }
    location /static/ {
        root /home/sammy/myprojectdir;
    }

    location / {
        include proxy_params;
        proxy_pass http://unix:/run/gunicorn.sock;
    }
}

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

يمكنك الآن تفعيل الملف بربطه مع المجلد "sites-enabled":

$ sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled

أجرِ اختبارًا لتتأكد من خلو ضبط الخادم إنجن إكس من الأخطاء الكتابية:

$ sudo nginx -t

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

$ sudo systemctl restart nginx

ونظرًا لأنك لا تحتاج بعد الآن إلى وصول إلى خادم التطوير، اضبط إعدادات الجدار الناري بحذف قاعدة المنفذ المفتوح "8000":

$ sudo ufw delete allow 8000

ثم اسمح لبيانات الشبكة العادية بالمرور من المنفذين "80" و"443" مما سيسمح بحدوث اتصالات HTTP و HTTPS على التوالي، وذلك باستخدام الأمر التالي:

$ sudo ufw allow 'Nginx Full'

يُفترض أن يكون بمقدورك الآن الذهاب إلى نطاق خادمك أو عنوان IP الخاص به لمشاهدة تطبيقك.

ملاحظة: بعد الانتهاء من ضبط إنجن إكس ستكون الخطوة التالية هي تأمين بيانات الشبكة إلى الخادم باستخدام بروتوكول SSL/TLS، وهذا مهم لأنه بدونه ستُرسل جميع المعلومات بما فيها كلمات المرور عبر الشبكة بصيغة نصيّةٍ صرفة plain text.

إذا كان لديك اسم نطاق فأسرعُ طريقة للحصول على شهادة SSL لتأمين بيانات الشبكة هو استخدام Let's Encrypt. يمكنك إعداده من خلال متابعة دليلنا كيف تؤمن Let's Encrypt باستخدام إنجن إكس على نظام أبونتو 18.04. اتبع الدليل باستخدام كتلة خادم إنجن إكس التي أنشأتها في هذا الدليل.

إذا لم يكن لديك اسم نطاق، فلا يزال بإمكانك تأمين موقعك للاختبار والتعلم باستخدام self-signed SSL Certificate، ونشدّد على اتباع العملية باستخدام كتلة خادم إنجن إكس التي أنشأتها في هذه المقالة.

الخطوة الحادية عشرة - استكشاف المشاكل وإصلاحها في خادمي إنجن إكس وغوني كورن

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

يظهر الخادم إنجن إكس الصفحة الافتراضية بدلا من إظهار تطبيق جانغو

إذا كان إنجن إكس يعرض الصفحة الافتراضية بدلًا من إحالة الخادم الوكيل إلى تطبيقك، فذلك يعني غالبًا أنك بحاجة إلى ضبط server_name ضمن الملف "etc/nginx/sites-available/myproject/" ليشير إلى عنوان IP لخادمك، أو اسم نطاقه.

يستخدم إنجن إكس الموجه server_name ليحدد كتلة الخادم التي سيستخدمها للاستجابة للطلبات؛ فإذا كانت تظهر لك صفحة إنجن إكس الافتراضية ففي هذا دلالة على الخادم إنجن إكس لم يستطع مطابقة الطلب مع كتلة الخادم صراحةً لذا تراجع إلى الكتلة الافتراضية المعرّفة في الملف "etc/nginx/sites-available/default/".

يجب أن يكون الموجه server_name في كتلة خادم المشروع أكثر تحديدًا من الموجّه المُختار في كتلة الخادم الافتراضية.

يعرض الخادم إنجن إكس الخطأ 502 Bad Gateway بدلا من عرضه تطبيق جانغو

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

والمكان الأساسي الذي يجب أن تبحث فيه عن مزيد من المعلومات هو سجل أخطاء إنجن إكس؛ فهو يخبرنا عمومًا عن الظروف التي سببت الخطأ أثناء حدث الإحالة من الخادم الوكيل Proxying. تفقد سجل أخطاء الخادم إنجن إكس بالتعليمة التالية:

$ sudo tail -F /var/log/nginx/error.log

والآن أسس طلبًا آخرًا في متصفحك لتوليد خطأ جديد (حاول إنعاش refresh الصفحة). يُفترض أن تتلقى رسالة خطأ جديدة مسجلة في السجل. إذا قرأت الرسالة وفهمتها فستضيّق نطاق المشكلة.

ربما تتلقى رسالة تشبه ما يلي:

 connect() to unix:/run/gunicorn.sock failed (2: No such file or directory)

التي تشير إلى أن إنجن إكس لم يستطع العثور على الملف "gunicorn.sock" في الموقع المُعطى. ينبغي مقارنة الموقع "proxy_pass" المعرف ضمن الملف "etc/nginx/sites-available/myproject/" مع الموقع الفعلي للملف "gunicorn.sock" الذي ولدته وحدة systemd المسماة "gunicorn.socket".

إذا لم تتمكن من العثور على الملف "gunicorn.sock" ضمن المجلد "run/"، فهذا يعني عمومًا أن ملف مقبس systemd لم يتمكن من إنشائه. عُد إلى القسم من مقالتنا هذه الذي يتكلم عن البحث عن ملف مقبس غوني كورن للسير وفق خطوات الإصلاح لمشكلات الخادم غوني كورن.

وقد تقرأ رسالةً أخرى تشبه التالية:

connect() to unix:/run/gunicorn.sock failed (13: Permission denied)

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

يمكن لهذا أن يحدث إذا كانت هناك محدودية في الأذونات في أي نقطة بين المجلد الجذر والملف "gunicorn.sock"، ويمكنك استعراض الأذونات وقيم الملكية لملف المقبس وكل من المجلدات الآباء له بتمرير المسار المطلق إلى ملف المقبس الخاص بك إلى الأمر namei:

$ namei -l /run/gunicorn.sock

وسيكون الخرج على النحو التالي:

f: /run/gunicorn.sock
drwxr-xr-x root root /
drwxr-xr-x root root run
srw-rw-rw- root root gunicorn.sock

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

يملك ملف المقبس في هذا المثال وكل مجلد من المجلدات التي تؤدي إليه أذونات قراءة read وتنفيذ execute (ينتهي عمود الأذونات للمجلدات بالامتداد r-x بدلًا من ---). يجب أن تكون العملية إنجن إكس قادرة على الوصول إلى المقبس بنجاح.

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

جانغو يعرض الرسالة could not connect to server: Connection refused

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

OperationalError at /admin/login/
could not connect to server: Connection refused
    Is the server running on host "localhost" (127.0.0.1) and accepting
    TCP/IP connections on port 5432?

التي يشير هذا إلى أن جانغو لم يتمكن من الاتصال بقاعدة بيانات Postgres. لذا تأكد أن نسخة Postgres تعمل كما يلي:

$ sudo systemctl status postgresql

إذا لم تكن تعمل، فيمكنك تشغيلها وضبط إمكانية تشغيلها تلقائيًا عند الإقلاع (إذا لم تكن معدةً هكذا من قبل):

$ sudo systemctl start postgresql
$ sudo systemctl enable postgresql

إذا استمر الخلل، فتأكد أن إعدادات قاعدة البيانات المعرفة في الملف "myprojectdir/myproject/settings.py/~" صحيحة.

مزيد من استكشاف الأخطاء وإصلاحها

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

قد تساعدك السجلات التالية في عملك:

  • فحص سجلات عملية إنجن إكس كما يلي:
sudo journalctl -u nginx
  • فحص سجلات الوصول إلى إنجن إكس كما يلي:
sudo less /var/log/nginx/access.log
  • فحص سجلات الخطأ لإنجن إكس كما يلي:
sudo less /var/log/nginx/error.log
  • فحص سجلات تطبيق غوني كورن كما يلي:
sudo journalctl -u gunicorn
  • فحص سجلات مقابس غوني كورن كما يلي:
sudo journalctl -u gunicorn.socket

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

إذا حدثت تطبيق جانغو، يمكن إعادة تشغيل العملية غوني كورن لتطبيق التغييرات بتنفيذ التالي:

$ sudo systemctl restart gunicorn

إذا غيرت ملفات خدمة أو مقبس غوني كورن أعد تحميل العملية الخفية daemon وأعد تشغيل العملية بتنفيذ التعليمات التالية:

$ sudo systemctl daemon-reload
$ sudo systemctl restart gunicorn.socket gunicorn.service

إذا غيرت تهيئة كتلة خادم إنجن إكس، افحص الضبط ثم إنجن إكس بتنفيذ ما يلي:

$ sudo nginx -t && sudo systemctl restart nginx

هذه الأوامر مفيدة جدًا لتطبيق التغييرات أثناء الضبط.

خاتمة

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

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

ترجمة - وبتصرف - للمقالة How To Set Up Django with Postgres, Nginx, and Gunicorn on Ubuntu 18.04 لصاحبها Justin Ellingwood.

اقرأ أيضًا


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

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

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



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

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

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

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   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.


×
×
  • أضف...