يعتبر دوكر Docker من أشهر التطبيقات مفتوحة المصدر لإنشاء وإدارة ونشر استنساخ التطبيقات باستخدام الحاويات، فالحاوية هي حزمة تحتوي على متطلبات التطبيق للعمل على مستوى نظام التشغيل أي أن التطبيق المنشور باستخدام Docker يعمل في بيئته الخاصة ويُتعامل مع متطلباته بشكل منفصل.
أما Flask فهو إطار ويب مصغّر (micro-framework) مبني باستخدام لغة بايثون، وتعود تسميته بالإطار المصغّر لأنه لا يحتاج إلى أدوات محدّدة أو مكونات إضافيّة لكي يعمل، بالإضافة إلى أنه يتميّز بالخفّة والمرونة وبدرجة عالية من التنظيم مما يجعل المبرمجين يفضلونه على بقية الإطارات.
سيسمح لك نشر تطبيق Flask باستخدام Docker باستنساخ التطبيق على مختلف الخوادم بأقل إعدادات ممكنة، لذا سنرى كيفية إنشاء تطبيق Flask و نشره باستخدام Docker بالإضافة إلى كيفية تحديث التطبيق بعد نشره.
المتطلبات الأساسية
لمتابعة هذا الدرس، ستحتاج إلى ما يلي:
- مستخدم عادي - ليس جذر - مع صلاحيات sudo معّد باستخدام هذا الدليل
- خادم أوبنتو 18.04 مع Docker، يمكنك إعداده عن طريق اتباع الخطوات في هذا الدرس أو عن طريق استخدام ميّزة التثبيت الخاصة بـ DigitalOcean في هذا الدرس
- تثبيت Nginx بإتباع الخطوة الأولى من هذا الدرس
الخطوة الأولى - إعداد تطبيق Flask
ستحتاج إلى إنشاء هيكل مجلدات تطبيقك، لذلك أنشئ مجلدًا في /var/www
وسمّهِ على سبيل المثال TestApp:
sudo mkdir /var/www/TestApp
ثم انتقل إلى هذا المجلد باستخدام الأمر:
cd /var/www/TestApp
وبعد ذلك، أنشئ المجلد الرئيسي لتطبيق Flask:
sudo mkdir -p app/static app/templates
تشير راية -p
إلى أن mkdir سينشئ المجلد مع جميع المجلدات الرئيسية غير الموجودة، وفي هذه الحالة، سينشئ mkdir مجلد الأب app
حتى يتمكن من إنشاء مجلدات static
و templates
داخله.
سيحتوي المجلد app على جميع الملفات المتعلّقة بتطبيق Flask مثل الواجهات (views) والمخططات الأوليّة (blueprints). فالواجهة هي الشيفرة البرمجيّة التي تكتبها للاستجابة إلى طلبات تطبيقك، أما المخططات الأوليّة فتنشئ مكونات التطبيق وتدعم الأنماط الشائعة داخل التطبيق أو عبر تطبيقات مختلفة.
ستضع جميع الأصول مثل الصور وملفات CSS وملفات جافاسكربت في مجلد static
، وأما بالنسبة لقوالب HTML فستضعهم في مجلد templates
.
والآن، بعد أن أنشأنا هيكل المجلدات الأساسية، فسننشئ الملفات التي نحتاجها لتشغيل تطبيق Flask. أنشئ أولًا ملف __init__.py
داخل مجلد app
، سيجعل هذا الملف مفسر بايثون يتعامل مع مجلد app
كحزمة.
أنشئ ملف __init__.py
باستخدام الأمر التالي:
sudo nano app/__init__.py
تسمح لك الحزم في بايثون بجمع الوحدات إلى مساحات أسماء منطقيّة أو تسلّسلات هرميّة لكي تتمكن من تقسيم الشيفرة البرمجيّة إلى كتل منفصلة قابلة للإدارة ذات وظائف معيّنة.
بعد ذلك، ستضيف شيفرة برمجيّة إلى __init__.py
لإنشاء نسخة من Flask واستدعاء المنطق الموجود في ملف views.py
، والذي ستنشئه بعد إنهائك لهذا الملف. أضف الشيفرة البرمجيّة التاليّة إلى الملف الجديد:
from flask import Flask app = Flask(__name__) from app import views
ستنشئ الآن ملف views.py
في مجلد app
، سيحتوي هذا الملف على أغلب منطق التطبيق.
sudo nano app/views.py
بعد ذلك أضف هذه الشيفرة البرمجيّة إلى ملف views.py
، ستُعيد هذه الشيفرة البرمجيّة السلسلة النصيّة hello world! إلى زوار صفحة الويب.
from app import app @app.route('/') def home(): return "hello world!"
يسمى السطر @app.route
فوق الدالة بالمزخرِف ويعمل على تعديل الدالة التي بعده، وفي هذه الحالة، سيخبر المزخرِف Flask أي رابط URL ستنفّذ دالة home()
، وأما بالنسبة إلى النص hello world المُعاد من الدالة home فسيظهر للمستخدم في المتصفّح.
الآن، بعد الانتهاء من ملف views.py
، فنحن مستعدين لإنشاء ملف uwsgi.ini
الذي سيحتوي على إعدادات uWSGI لتطبيقنا وهذا الأخير عبارة عن خيار نشر لـ Nginx والذي هو خادم لكل من البروتوكول والتطبيق، أي يخدم بروتوكولات uWSGI و FastCGI و HTTP.
استخدم الأمر التالي لإنشاء هذا الملف:
sudo nano uwsgi.ini
بعد ذلك، أضف هذه الإعدادات إلى الملف لإعداد خادم uWSGI:
[uwsgi] module = main callable = app master = true
تعرّف هذه الشيفرة البرمجية الوحدة التي سيعمل منها تطبيق Flask، والتي هي في هذه الحالة ملف main.py
، ولقد أشرنا إليه بـ main. وبالنسبة إلى خيار callable فهو يخبر uWSGI باستخدام نسخة من app المصدّر من التطبيق الرئيسي. ويسمح الخيار master للتطبيق أن يعمل دائمًا ولن يتوقف إلا لبعض الوقت عند إعادة تحميل التطبيق كاملًا.
بعد ذلك، أنشئ ملف main.py
ليكون مدخل تطبيقك، فالمدّخل يخبر uWSGI عن كيفية التعامل مع تطبيقك.
sudo nano main.py
والآن، أضف السطر التالي إلى الملف حيث أن هذا الأخير سيستدعي نسخة من Flask يسمى app من حزمة التطبيق التي أنشأناها سابقًا.
from app import app
وفي النهاية، أنشئ الملف requirements.txt
لتحديد الاعتماديات التي سيثبتها مدير الحزم pip إلى نشر Docker الخاص بك:
sudo nano requirements.txt
أضف السطر التالي في الملف /var/www/TestApp/app/requirements.txt
لإضافة Flask كتبعيّة:
Flask==1.0.2
يحدد هذا السطر نسخة Flask التي يجب تثبيتها، والتي هي في وقت كتابة هذا المقال، النسخة 1.0.2، ويمكنك التأكد من التحديثات على الموقع الرسمي لـ Flask.
والآن لقد أنتهيت من إعداد تطبيق Flask ومستعد لإعداد Docker.
الخطوة الثانية - إعداد Docker
سننشئ في هذه الخطوة ملفين، Dockerfile و start.sh
لإنشاء نشر Docker الخاص بك، فملف Dockerfile هو مستند نصي يحتوي على الأوامر التي تُستخدم لتجميع الصورة (image) وأما بالنسبة لملف start.sh فهو سكربت shell الذي سيبني الصورة وسينشئ الحاوية من ملف Dockerfile.
أنشئ أولًا ملف Dockerfile:
sudo nano Dockerfile
بعد ذلك، أضف إعداداتك التي ترغب بها إلى Dockerfile، ستحدّد هذه الأوامر كيف ترغب ببناء الصورة وكيف ستضاف المتطلبات الإضافيّة.
-
الملف
/var/www/TestApp/Dockerfile
:
FROM tiangolo/uwsgi-nginx-flask:python3.6-alpine3.7 RUN apk --update add bash nano ENV STATIC_URL /static ENV STATIC_PATH /var/www/app/static COPY ./requirements.txt /var/www/requirements.txt RUN pip install -r /var/www/requirements.txt
في هذا المثال، سنبني صورة Docker (أي image) من صورة موجودة بالفعل وهي tiangolo/uwsgi-nginx-flask ويمكنك إيجادها على DockerHub وتعتبر هذه الصورة من أفضل الصور الموجودة لأنها تدعم العديد من نسخ بايثون بالإضافة إلى أنظمة التشغيل المختلفة.
أول سطرين سيحددان الصورة الرئيسيّة التي ستستخدمها لتشغيل التطبيق وتثبيت معالج أوامر Bash والمحرّر النصي nano، وستثبت أيضًا عميل git للسحب والدفع إلى خدمات استضافة التحكّم بالإصدارات مثل GitHub و GitLab و Bitbucket. أما بالنسبة إلى ENV STATIC_URL /static فهو متغيّر البيئة الخاص بصورة Docker الحالية ويحدد الملف الثابت (static) الذي سيحتوي على جميع الأصول مثل الصور وملفات CSS و ملفات جافا سكربت.
بالنسبة لآخر سطرين فستنسخ الملف requirements.txt إلى الحاوية ومن ثم ستثبّت التبعيات.
والآن، بعد أن أنهينا ملف Dockerfile، أصبحنا مستعدين لإنشاء ملف start.sh الذي سيبني حاوية Docker، وقبل كتابة سكربت start.sh، تأكد من وجود منفذ (port) مفتوح لاستخدامه في الإعدادات، ويمكنك التأكد من ذلك عن طريق تشغيل الأمر التالي:
sudo nc localhost 56733 < /dev/null; echo $?
إذا كانت مخرجات الأمر السابق هي 1 فهذا المنفذ مفتوح ويمكن استخدامه، وخلافا ذلك، ستحتاج إلى اختيار منفذ آخر لاستخدامه في ملف إعدادات start.sh.
بمجرّد أن تجد منفذ مفتوح للاستخدام، أنشئ سكربت start.sh:
sudo nano start.sh
سيبني سكربت start.sh ملف Dockerfile
وينشئ الحاوية من صورة Docker، ولهذا سنضيف إلى الملف /var/www/TestApp/start.sh
الإعدادات التالية:
#!/bin/bash app="docker.test" docker build -t ${app} . docker run -d -p 56733:80 \ --name=${app} \ -v $PWD:/app ${app}
يسمى السطر الأول بـ shebang، وهو يحدد أن هذا الملف هو ملف bash وستُنفّذ أوامره، وأما السطر الثاني فيحدّد اسم الصورة والحاوية وستُحفظ على شكل متغيّر يسمى app. أما السطر التالي فيخبر Docker ببناء الصور من ملف Dockerfile الموجود في المجلّد الحالي، وفي هذا المثال، سينشئ صورة تسمى docker.test
.
الأسطر الثلاثة الأخيرة تنشئ حاوية تسمى docker.test والتي تعمل على المنفذ 56733، وفي النهاية، تربط المجلد الحالي بمجلد /var/www
في الحاوية.
يمكنك استخدام الراية -d
لتشغيل الحاوية في وضع العفريت (daemon mode) أو كعملية خلفيّة (background process)، ويمكنك تضمين الراية -p
لربط منفذ الخادم إلى منفذ معيّن في حاوية Docker، وفي هذه الحالة ستربط منفذ 59733 بمنّفذ 80 في حاوية Docker. بالنسبة إلى الراية -v
(volume) فيحدد مكان Docker لوصله في الحاوية.
شغّل سكربت start.sh
لإنشاء صورة Docker وبناء حاوية من الصورة:
sudo bash start.sh
بمجرّد الانتهاء من الأمر السابق، استخدم الأمر التالي لعرض جميع الحاويات التي تعمل:
sudo docker ps
سيظهر لك شيء مشابه لهذا:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 58b05508f4dd docker.test "/entrypoint.sh /sta…" 12 seconds ago Up 3 seconds 443/tcp, 0.0.0.0:56733->80/tcp docker.test
سترى أن حاوية docker.test تعمل، والآن لنزور عنوان IP في المنفذ الذي اخترناه في متصفحك: http://ip-address:56733
ستشاهد صفحة مشابهة لهذه الصفحة:
في هذه الخطوة نجحنا في نشر تطبيق Flask على Docker، سنستخدم في الخطوة التالية القوالب لعرض المحتوى إلى المستخدمين.
الخطوة الثالثة - خدمة ملفات القوالب
القوالب هي ملفات لعرض محتوى ثابت وحيوي لزوار تطبيقك، في هذه الخطوة، سننشئ قالب HTML لإنشاء الصفحة الرئيسية لتطبيقك.
إبدأ بإنشاء ملف home.html
في مجلد app/templates
:
sudo nano app/templates/home.html
أضف الشيفرة البرمجية إلى قالبك لإنشاء صفحة HTML5 تحتوي على عنوان وبعض النصوص.
-
الملف
/var/www/TestApp/app/templates/home.html
:
<!doctype html> <html lang="en-us"> <head> <meta charset="utf-8"> <meta http-equiv="x-ua-compatible" content="ie=edge"> <title>Welcome home</title> </head> <body> <h1>Home Page</h1> <p>This is the home page of our application.</p> </body> </html>
بعد ذلك، عدّل على ملف app/views.py
لخدمة الملف المنشئ حديثًا:
sudo nano app/views.py
أضف أولا السطر التالي إلى بداية ملفك لإستدعاء أسلوب render_template من Flask والذي يرمّز صفحة HTML لتصيير (render) صفحة ويب للمستخدم.
from flask import render_template ...
أضف مسار (route) آخر في نهاية الملف لتصيير ملف القالب حيث ستحدّد هذه الشيفرة البرمجية أن المستخدمين سيخدمون بمحتوى ملف home.html
عند زيارة مسار /template
في تطبيقك.
... @app.route('/template') def template(): return render_template('home.html')
سيبدو ملف app/views.py
بعد تحديثه كالتالي:
from flask import render_template from app import app @app.route('/') def home(): return "Hello world!" @app.route('/template') def template(): return render_template('home.html')
من أجل تفعيل هذه التغييرات، ستحتاج إلى إيقاف وإعادة تشغيل حاويات Docker. شغّل الأمر التالي لإعادة بناء الحاوية:
sudo docker stop docker.test && sudo docker start docker.test
زر تطبيقك الآن على http://your-ip-address:56733/template
لمشاهدة خدمة القالب الجديد.
في هذه الخطوة أنشأت ملف قالب Docker لخدمة زوار تطبيقك وفي الخطوة القادمة سنرى كيف يمكنك تفعيل التغييرات دون الحاجة إلى إعادة تشغيل حاوية Docker.
الخطوة الرابعة - تحديث التطبيق
ستحتاج في بعض الأحيان إلى القيام ببعض التغييرات في تطبيقك مثل تثبيت متطلبات جديدة، تحديث حاوية Docker أو تغيير شيفرة HTML أو المنطق، لذلك، سنتحدّث الآن عن إعداد touch-reload للقيام بهذه التغييرات دون الحاجة إلى إعادة تشغيل حاوية Docker.
يراقب بايثون autoreloading نظام الملفات للتغييرات وتحديث التطبيق عند إيجاد تغيير، وهذه العملية غير منصوح بها عند مرحلة الإنتاج (production) لأنها ستستهلك الكثير من الموارد. سنستخدم touch-reload لمراقبة التغييرات لملف معيّن وإعادة التحميل عند تحديث أو استبدال هذا الملف.
لفعل ذلك، نبدأ بفتح ملف uwsgi.ini:
sudo nano uwsgi.ini
ونضيف هذا السطر الأخير إلى نهاية ملف uwsgi.ini
كما هو موضح في الشيفرة التالية:
module = main callable = app master = true touch-reload = /app/uwsgi.ini
يحدد هذا السطر الملف الذي يجب التعديل عليه لإعادة تحميل كامل التطبيق.
لمشاهدة هذا، غيّر قليلا في تطبيقك، فعلى سبيل المثال، افتح ملف app/views.py
:
sudo nano app/views.py
استبدل السلسلة النصيّة التي تعود من الدالة home:
from flask import render_template from app import app @app.route('/') def home(): return "<b>There has been a change</b>" @app.route('/template') def template(): return render_template('home.html')
والآن، إذا فتحت الصفحة الرئيسية لتطبيقك على http://ip-address:56733
ستلاحظة عدم ظهور التغييرات، وهذا بسبب أن شرط إعادة التحميل هو تغيير ملف uwsgi.ini
، لذا استخدم touch لتفعيل هذا الشرط:
sudo touch uwsgi.ini
أعد تحميل صفحة الرئيسية في تطبيقك على متصفحك مرّة أخرى، ستظهر لك التغييرات:
في هذه الخطوة، أعددت شرط touch-reload لتحديث تطبيقك بعد القيام بتغييرات.
الخلاصة
في هذا الدرس، أنشأت ونشرت تطبيق Flask على حاوية Docker، ولقد أعددّت touch-reload لإعادة تحميل التطبيق دون الحاجة إلى إعادة تشغيل الحاوية.
يمكنك الآن التوسع أكثر واكتشاف Docker بطريقة معمّقة، ويمكنك البدء بالتوثيق الرسمي
ترجمة -وبتصرف- للمقال How To Build and Deploy a Flask Application Using Docker on Ubuntu 18.04 لصاحبه Michael Okoh
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.