* tech-edition: كيفية إرساء تطبيق الويب Django بأناقة

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

حاويات ، يجعل الشحن أسهل! [مصدر]

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

يمكن أيضًا فحص الرمز في GitHub repo. يتم تمثيل خطوة بخطوة في سجل الالتزام.

الشروط

يستند هذا المقال إلى بعض الأساسيات وهي:

  • عامل ميناء & عامل ميناء يؤلف
  • بيثون 3.6.5 وجانغو 2.1
  • virtualenv و pip
  • شخص سخيف
  • فهم أساسي لـ Django (على سبيل المثال عن طريق تنفيذ البرنامج التعليمي Django)
  • العمل في محطة / لينكس شل

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

وانشاء

نبدأ بجعل دليل مشروع (mkdir docker-django) وإنشاء git repo (git init). لنكون صادقين ، أقوم عادةً بإنشاء الريبو على خادم git بعيد (أي GitHub في هذه الحالة) أولاً ثم استنساخه محليًا - يحفظ بعض المتاعب في إعداد جهاز التحكم عن بُعد. لنقم بإنشاء فرع تطوير جديد والخروج منه على الفور (git checkout -b develop). يتعلق الجزء الثاني من الإعداد بإدارة التبعية ، لذلك سنقوم بإنشاء بيئة افتراضية (virtualenv env) وتنشيطها (المصدر env / bin / activate). بعد ذلك ، سنقوم بتثبيت Django (النقطة pip Django> = 2.1) الآن ، سيؤدي ذلك إلى تثبيت Django محليًا في البيئة الافتراضية وهو ما نهدف إليه الآن. سنستخدم وظيفة Django لإعداد مشروع. لكننا نريد أيضًا الحفاظ على مزامنة تبعياتنا للبيئات الأخرى ، لذلك سنضيف التبعية إلى ملف requirements.txt (echo 'Django> = 2.1' >> requirements.txt) يستحق الالتزام الأول (git add * && git ارتكاب -m "...")

سيتم تنفيذ الجزء الثالث من الإعداد بواسطة Django: هيا نبدأ مشروع Django (django-admin startproject mysite). أستخدم Visual Studio Code كمحرر ، لذا سأستبعد إعداد الدليل بواسطته من التحكم في الإصدار (echo ".vscode /" >> .gitignore). سنقوم بإجراء اختبار تجريبي لإعداد المشروع من خلال تشغيل خادم محلي (python mysite / management.py runerver) وهذا سيسمح لنا بالتحقق من الخادم الذي يعمل محلياً على الموقع http: // localhost: 8000.

دعونا ننهي الإعداد عن طريق تنفيذ التزام سريع آخر (إضافة git المعتادة ... & git الالتزام ...).

الوضع النموذجي في التنمية: التطبيق المحلي وقاعدة البيانات في نظام الملفات المحلي.

يتم الآن تشغيل "التطبيق" محليًا وهو ما يحدث دائمًا أثناء التطوير. بالطبع ، ليس الكثير من التطبيق ، ولكن دعنا ننسى ذلك في الوقت الحالي. أود أن أزعم أن مشروع Django الافتراضي يشحن بالفعل ما يكفي لجعله تطبيقًا ، مثل تطبيق admin. لذلك سأستخدم هذه الوظيفة لرحلتنا فقط.

إرساء "التطبيق"

الآن وقد تم إرساء الأساس ، يمكننا بدء عملية إرساء التطبيق. كل شيء يبدأ بـ Dockerfile (touch Dockerfile) والذي يجب أن يبدو مثل هذا:

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

الآن ، يتم تشغيل التطبيق داخل حاوية Docker ، مع وجود قاعدة البيانات داخل الحاوية. هذا يؤدي إلى dataloss عندما يتم هدم الحاوية.

نحن نبدأ بناء الصورة (عامل بناء do-django-doerer: 0.0.1.). عادة ما يستغرق هذا بعض الوقت ، ولكن بمجرد الانتهاء من ذلك ، دعونا نمضي قدمًا ونختبره من خلال تشغيل "تطبيقنا" في حاوية (docker run -p 8001: 8001 docker-django: 0.0.1). نظرًا لأن الخادم الذي يتم تشغيله في الحاوية يستمع إلى المنفذ 8001 بدلاً من 8000 مقارنةً بـ "التطبيق" الذي يتم تشغيله محليًا ، فإننا نقوم بتعيين منفذ 8001 من الحاوية إلى المنفذ 8001 من أجهزتنا المحلية. دعنا نتحقق من أنه يستجيب على http: // localhost: 8001.

بمجرد بناء الصورة وتشغيلها بشكل جيد ، نقوم بتحويلها إلى الخدمة الأولى في تعريف docker-compose.yml جديد (touch docker-compose.yml ، والذي يجب أن يبدو كما يلي:

الآن يمكننا تشغيل خدمتنا ببساطة من خلال عامل إنشاء سريع. هذا رائع إلى حد كبير وهو ما نريد الوصول إليه بشكل أساسي ، والقدرة على تشغيل تطبيقنا باستخدام أمر واحد. يحتاج الأمر لتشغيل "التطبيق" في الحاوية إلى تشغيله مع تحديد 0.0.0.0 في الوقت الحالي. نظرًا لأن الحاويات لها شبكتها الخاصة ، فإن المضيف المحلي سوف يشير فقط إلى الحاوية نفسها. لاحظ أيضًا أنه يجب علينا إسقاط CMD من Dockerfile وتحديد الأمر الذي سيتم تشغيل الحاوية به في docker-compose.yml.

لذلك ، يعلمنا "التطبيق" لدينا بعمليات الترحيل غير المطبقة ، وبالتحديد التطبيقات الإضافية المضمنة في مشروع Django القياسي ولا تتوفر وحدة تحكم المشرف بعد لأن هذه الترحيلات لم يتم تطبيقها. كخطوة أولى ، يمكننا ترحيل قاعدة البيانات في الريبو المحلي لدينا (python mysite / management.py migrate). سينطبق هذا على db.sqlite3 المحلي في نظام الملفات لدينا ، ويمكن الآن الوصول إلى وحدة تحكم المشرف على "التطبيق" الذي يتم تشغيله محليًا على http: // localhost: 8000 / admin (بشرط أن يكون التطبيق قيد التشغيل).

لتنفيذ نفس عملية الترحيل مقابل الحاوية ، يمكننا تنفيذ الأمر في الحاوية (ترحيل عامل التصفية exec web python mysite / manager.py migrate) والتحقق من: http: // localhost: 8001 / admin

لاحظ أن الحاوية بالإضافة إلى الخادم بداخلها يمكن تشغيلهما ويمكنك إطلاق الأمر exec بشكل منفصل. إنها في الأساس نفس إطلاق قذيفة جديدة ، وتسجيل الدخول إلى الحاوية وتنفيذ الأمر. أصبح تطبيق admin متاحًا الآن ، ولكن لا يوجد مستخدم مسؤول حتى الآن.

لذلك ، سنساعد ذلك وننشئ مستخدمًا مسؤولًا في الحاوية. (عامل ميناء - يؤلف exec web python mysite / management.py createuperuser). دعنا نمضي قدمًا ونختبر ذلك في تطبيق المسؤول - يجب أن تكون قادرًا الآن على تسجيل الدخول إلى أداة الإدارة ومشاهدة مستخدم المسؤول عند النقر فوق "المستخدمون".

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

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

أحجام:
  - .:/الشفرة
عن طريق تعيين دليل داخل الحاوية إلى نظام الملفات المحلي ، يمكننا الحفاظ على الحالة المحلية وداخل الحاوية متزامنة.

يتم تعيين دليلنا الحالي المحلي إلى دليل الرمز في الحاوية. كملاحظة جانبية ، يتم استبعاد ملف db.sqlite3 المحلي من التحكم في الإصدار في حالتي لأنني قمت باستنساخ الريبو من الخادم البعيد حيث تم إنشاء .gitignore for Python تلقائيًا ، والذي يمثل بالفعل ملفات SQLite التي سيتم استبعادها.

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

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

مؤتمر نزع السلاح
بيثون mysite / manager.py startapp myapp

إضافة خدمات قاعدة البيانات

من المحتمل أن نكون قادرين على الوصول إلى حد بعيد باستخدام قاعدة بيانات SQLite الخاصة بنا لأنه من الممكن تشغيل خوادم هائلة في السحابة هذه الأيام ، لكننا نريد إنشاء تطبيق يمكنه التوسع أفقياً ويستخدم قاعدة بيانات كاملة مثل Postgres. لذلك ، دعونا نتحول إلى Postgres. سنفعل ذلك عن طريق إضافة خدمة قاعدة بيانات ، باختصار ديسيبل ، إلى عامل الإرساء - compose.yml:

ديسيبل:
  الصورة: بوستجرس
  الشبكات:
   - الخلفية
الشبكات:
  الخلفية:
    سائق: الجسر

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

متغيرات البيئة في عامل الميناء

من أجل الاتصال بقاعدة البيانات ، نحتاج إلى منح Django تفاصيل الاتصال وبيانات الاعتماد عن طريق إضافة قاعدة بيانات Postgres إلى settings.py:

POSTGRES_PASSWORD = os.environ.get ('POSTGRES_PASSWORD')
قواعد البيانات = {
    'الإفتراضي': {
        "المحرك": "django.db.backends.postgresql" ،
        "NAME": "postgres" ،
        "المستخدم": "postgres" ،
        "كلمة المرور": POSTGRES_PASSWORD ،
        "المضيف": "ديسيبل" ،
        "الميناء": "5432" ،
    }
}

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

يمكننا أيضًا تخزين أسرار أخرى مثل المفتاح السري لـ Django في ملف .env وغيرها من المعلومات التي تحدد بيئة التطوير الحالية لدينا:

POSTGRES_PASSWORD = سر
POSTGRES_USER = بوستجرس
DJANGO_SECRET_KEY = سر

من أجل إقامة اتصال مع Postgres ، يعتمد Django على حزمة Python psycopg2 ، لذلك سنضيف هذه التبعية لمتطلبات ملف متطلباتنا.txt:

جانغو> = 2.1
psycopg2-ثنائي

لنقم أيضًا بإضافة تبعيات إضافية إلى Dockerfile لدينا:

...
RUN apk التحديث و \
    إضافة apk - الظاهري بناء deps مجلس التعاون الخليجي بيثون ديف musl-dev && \
    apk إضافة postgresql-dev
...

هذا يعني أن إعادة بناء صورتنا ستكون ضرورية.

للإشارة ، قد يكون من الأسهل إلقاء نظرة على الالتزام هنا.

خدمة ويب منفصلة و ديسيبل يمكنها التواصل مع بعضها البعض.

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

هجرات البيانات لإعداد الخارق تلقائيا

يمكننا تشغيل عمليات الترحيل يدويًا مقابل خدمة قاعدة البيانات ومن ثم اختبار التطبيق لدينا ومعرفة ما إذا كان كل شيء يسير على ما يرام.

عامل ميناء يؤلف exec على شبكة الإنترنت بيثون
عامل ميناء يؤلف exec على شبكة الإنترنت بيثون

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

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

الثعبان mysite / ادارة. makemigrations - myapp فارغة

سيؤدي هذا إلى إنشاء عملية ترحيل فارغة ، يمكننا تغييرها إلى عملية ترحيل مثل هذا:

يجب أيضًا تحديد جميع متغيرات البيئة المستخدمة في عملية الترحيل هذه في ملف docker-compose.yml وكذلك ملف .env ، ولكن بمجرد أن يتم حفظ كل شيء في حالة مزامنة.

خدمات:
  على شبكة الإنترنت:
    [...]
    بيئة:
      POSTGRES_PASSWORD: $ {POSTGRES_PASSWORD}
      POSTGRES_USER: $ {POSTGRES_USER}
      DJANGO_DB_NAME: $ {DJANGO_DB_NAME}
      DJANGO_SU_NAME: $ {DJANGO_SU_NAME}
      DJANGO_SU_EMAIL: $ {DJANGO_SU_EMAIL}
      DJANGO_SU_PASSWORD: $ {DJANGO_SU_PASSWORD}
      DJANGO_SECRET_KEY: $ {DJANGO_SECRET_KEY}
[...]

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

الحصول على نظرة عامة أفضل على خدمة "db" الخاصة بنا مع pgadmin

لأغراض التطوير ، نريد أن نكون قادرين على رؤية مخطط Postgres الخاص بنا والبحث عن البيانات. الآن بدلاً من تثبيت عميل Postgres أو استخدام IDE الخاص بنا للقيام بذلك ، سنستفيد من قوة الحاويات لنشر أداة مسؤول. في الواقع ، لا تحتوي خدمة db الخاصة بنا في الوقت الحالي على أي منافذ معيّنة لجهازنا المحلي ، لذلك لن نتمكن في الواقع من الاتصال بها مع عميل JDBC محلي. لذلك ، دعونا نضيف بدلاً من ذلك خدمة pgadmin إلى عامل إنشاء التجميع لدينا .yml. لم أجد صورة رسمية ، لكن هناك صورة عامة هنا. نظرًا لأن هذه مجرد صورة مساعدة ، فسنختار الثقة بها. بالنسبة للأشياء في الإنتاج ، قد لا نريد القيام بذلك. لذلك ، فإن عامل الإرساء - compose.yml سيبدو بشكل أساسي كالتالي:

مرة أخرى ، نحتاج إلى التأكد من تحديد متغيرات البيئة الضرورية أيضًا في .env. حان الوقت لبدء تشغيل جميع الخدمات مرة أخرى وتحقق من أداة المشرف الخاصة بنا في Postgres على الموقع http: // localhost: 8080.

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

باستخدام بيانات الاعتماد من متغيرات البيئة ، يجب أن نكون قادرين على تسجيل الدخول. لإنشاء اتصال بقاعدة البيانات الخاصة بنا ، دعونا نضغط على "إضافة خادم". يفتح هذا نموذجًا يمكن أن يكون فيه "الاسم" أي شيء نريده ، مثل "اختبار" ، ثم نقر على علامة التبويب "اتصال" وقم بملء db كاسم مضيف ، وبيانات اعتماد قاعدة البيانات الخاصة بنا المعرفة في ملف .env لاسم المستخدم وكلمة المرور ، لذلك للحصول على أمثلة postgres والسرية. بمجرد إنشاء اتصال بـ db - سيطالبك إذا لم ينجح ذلك - يمكننا استعراض المخطط وإلقاء نظرة على بعض نماذج البيانات في قاعدة البيانات. أيام سعيدة لمشرفي DB! الآن ، على سبيل الراحة ، دعونا أيضًا نكشف عن المنفذ 5432 من الحاوية الخاصة بنا حتى يتمكن IDE الخاص بنا من إظهار المخطط من خلال النقر على المضيف المحلي.

بمساعدة أداة pgadmin ، يمكننا استكشاف مخطط قواعد البيانات بالإضافة إلى البيانات الموجودة في قاعدة البيانات.

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

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

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

إذا كنت ترغب في مناقشة ومناقشة مقاربتي لتطبيق Dockerizing تطبيق Django ، فلا تتردد في ترك تعليق أو التواصل على LinkedIn أو Twitter

انضم إلى مجتمعنا Slack وقراءة موضوعات Faun الأسبوعية الخاصة بنا ⬇

إذا كانت هذه المشاركة مفيدة ، فالرجاء النقر على زر التصفيق أدناه عدة مرات لإظهار دعمك للمؤلف! ⬇