سننشئ في هذا المقال صورة دوكر مخصصة لتشغيل تطبيقات بايثون بداخلها، حيث يمكننا باستخدام ملف Dockerfile تخصيص وإنشاء صور دوكر جديدة، يمكن لمطوري التطبيقات أو المستخدمين أيضًا الاستفادة من ذلك، حيث سنستعين بصورة بايثون بسيطة وخفيفة، وبعد إجراء التعديلات على تلك الصورة ستصبح عملية تشغيل تطبيقات بايثون أسهل، ولن نقلق بشأن تشغيل تلك التطبيقات على أنظمة التشغيل المختلفة، حيث يمكن بتنفيذ أمر دوكر بسيط تشغيل تطبيق بايثون، ودون الحاجة للاستعانة ببرامج تثبيت التطبيقات التي توفرها الاستضافات عادةً. سنستخدم مينيكوندا Miniconda وهو مُثبّت كوندا مجاني يُنشئ gkh نسخة صغيرة ومجهزة من أناكوندا فيها الاحتياجات الأساسية لتطبيقات بايثون.
لماذا نستخدم مينيكوندا؟
لعدة أسباب حيث يستبدل مينيكوندا إصدار بايثون الذي يوفره مدير حزم نظام التشغيل، بإصدار بايثون يُثبته هو في مكان منفصل وله بيئته الخاصة، فنحصل على طبقة عزل إضافية عند استخدامه ضمن حاوية دوكر، ما يوفر لنا مزايا إضافية، فبما أننا نستخدم كوندا المُثبت من قبل مينيكوندا، يمكن استخدام تلك الأداة لتحديد إصدار بايثون الذي يحتاجه التطبيق، ما يفيد المطورين خصوصًا للعمل على عدة نسخ من بايثون معًا على نفس الجهاز، حيث يمكن مثلًا استخدام عدة إصدارات مختلفة من بايثون 3، مثل 3.6 أو 3.7 أو 3.8 أو 3.9 أو إصدارات أقدم منها، ومثلًا لو كان الإصدار الافتراضي الذي نستخدمه هو بايثون 3.9، ونعمل على تطبيق يحتاج لإصدار بايثون 3.7 واعتمادياته الخاصة، يمكن الاستفادة من كوندا لتغيير إصدار بايثون وتثبيت كافة اعتمادياته وذلك بتنفيذ الأمر conda install python=3.7
.
- يسمح مينيكوندا بتثبيت تطبيقات لكل من بايثون 2 و بايثون 3، ومع أن إصدار بايثون 2 قد توقف دعمه لكن لا زال بإمكاننا اختبار التطبيقات القديمة باستخدامه دون الحاجة للتعديل عليها لدعم إصدار بايثون 3 بأدوات مثل 2to3.
- أحيانًا تعتمد تطبيقات بايثون المُشغلة ضمن مينيكوندا على اعتماديات خارجية بغير لغة بايثون مثبتة على الجهاز المضيف، مثل الاعتماد على
g++
، وهنا تبرز قوة استخدام مينيكوندا ضمن دوكر كحل لتلك المشكلة. - يمكن أيضًا إنشاء وتفعيل بيئات تطبيق بايثون مخصصة باستخدام كوندا، وذلك بالاعتماد على العزل.
- يمكن التبديل بين إصدار بايثون الافتراضي ضمن حاوية دوكر، وبين الإصدار ضمن مينيكوندا في أي وقت، ما يوفر سهولة أكبر في إجراء التعديلات على التطبيق وإعادة بناء الصورة، والآن سنبدأ بإنشاء صورة دوكر جديدة لتطبيق بايثون مع مينيكوندا.
المستلزمات
أولًا يجب تثبيت دوكر بحسب توزيعة لينكس التي تعمل عليها، ولا ننسى إضافة المستخدم الخاص بنا إلى مجموعة دوكر حتى نتمكن من تنفيذ أوامر دوكر دون استخدام الأمر sudo
، ويجب توفر اتصال بالإنترنت لنتمكن من تنزيل صورة دوكر الأساسية التي سنستخدمها.
ولاختبار عملية تشغيل التطبيق باستخدام مينيكوندا داخل دوكر، سنستخدم تطبيق بسيط بالاسم python-app.py يطبع عبارة "Hello World!"، وبعدها يمكن تبديل ذلك التطبيق بتطبيق بايثون كامل يستخدم العديد من مكتبات بايثون، والاستفادة من بيئة مينيكوندا التي توفر عدة نسخ من الاعتماديات.
الخطوة الأولى: جلب صورة دوكر (اختياري)
سنستخدم صورة بايثون ذات الوسم slim بدلًا من وسم لينكس apline الخفيفة، لأنها تقدم أداء أفضل لتشغيل التطبيقات، وحجمها تقريبًا 40 ميجابايت مبنية على نسخة ديبيان Buster وإصدار بايثون 3.9.1، هذه الخطوة اختيارية والهدف منها توضيح الفرق بين استخدام نسخة جاهزة أو إنشاء نسخة مخصصة يدويًا باستخدام ملف دوكر Dockerfile، ويمكن تنزيل آخر إصدار من صورة بايثون slim باستخدام أمر docker pull
كالتالي:
docker pull python:slim
الخطوة الثانية: إنشاء ملف دوكر Dockerfile بالتخصيصات المطلوبة
ننشئ أولًا مجلد جديد لاحتواء تطبيق دوكر، ثم نُنشئ داخله ملف جديد فارغ ونسميه Dockerfile باستخدام الأمر touch
كالتالي:
mkdir python-docker cd python-docker touch Dockerfile
سنشرح خطوات عملية بناء صورة دوكر خطوة بخطوة، بعدها سنذكر المحتوى الكامل النهائي لملف Dockerfile.
تحضير الصورة الأساسية
التحديث إلى آخر إصدارات من الحزم الافتراضية باستخدام صورة بايثون slim:
FROM python:slim RUN apt-get update && apt-get -y upgrade \
تثبيت حزم الاعتماديات الخارجية
نثبت الاعتماديات الخارجية المكتوبة بغير لغة بايثون بحسب ما يحتاجه التطبيق، مثل g++
:
&& apt-get install -y --no-install-recommends \ git \ wget \ g++ \ gcc \ ca-certificates \ && rm -rf /var/lib/apt/lists/*
يمكن الاستفادة من Git و Wget لجلب تطبيقات بايثون من المستودعات والعناوين المختلفة، أخيرًا يمكننا تقليص حجم صورة دوكر الناتجة عبر مسح قوائم الحزم باستخدام الأمر rm -rf /var/lib/apt/lists/*
.
تثبيت مينيكوندا
يُعدل مينيكوندا بعد تثبيته الملف .bashrc ليبدل إصدار بايثون المستخدم إلى الإصدار الخاص به:
ENV PATH="/root/miniconda3/bin:${PATH}" ARG PATH="/root/miniconda3/bin:${PATH}" RUN wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh \ && mkdir /root/.conda \ && bash Miniconda3-latest-Linux-x86_64.sh -b \ && rm -f Miniconda3-latest-Linux-x86_64.sh \
يٌعيّن متغير البيئة ضمن مسار الحاوية داخل النظام، حيث أن التعليمة ENV
خاصة بالحاويات التي ستعمل وفقًا للصورة التي يتم بنائها، بينما ARG
للاستخدام بين الحاويات الوسيطة التي تُنشئ خلال عملية بناء الصورة لأول مرة، فالفرق بين تعليمتي ENV
و ARG
في الشيفرة السابقة هو أن التعليمة الأخيرة متاحة خلال عملية بناء الصورة فقط، ونٌنزل باستخدام الأمر wget
الإصدار الأخير من مينيكوندا من مستودع أناكوندا الرسمي، بعدها يتم إنشاء مجلد الضبط ثم تثبيته ثم حذف المُثبت.
إعداد مينيكوندا مع صدفة باش
بعد تثبيت مينيكوندا نعرض رقم الإصدار المثبت لتأكيد نجاح عملية التثبيت، ثم نُهيئه للعمل ضمن صدفة باش داخل الحاوية، السطر الثاني يُحدّث ملف .bashrc
الافتراضي:
&& echo "Running $(conda --version)" && \ conda init bash && \
إعادة تحميل باش لتطبيق التغييرات
نعيد تحميل باش داخل دوكر للتبديل من إصدار بايثون الافتراضي المثبت على نظام التشغيل الأساسي المٌستخدم في ديبيان، إلى إصدار بايثون الخاص بمينيكوندا:
. /root/.bashrc && \
ونحدث الحزم الافتراضية داخل حزمة مينيكوندا:
conda update conda && \
تحضير بيئة كوندا للتطبيق
نُنشئ ونُفعل بيئة كوندا منفصلة خاصة بتطبيق بايثون:
conda create -n python-app && \ conda activate python-app && \
نثبت إصدار بايثون المطلوب من قبل التطبيق، وذلك بفرض أن التطبيق مطور ليعمل على إصدار بايثون 3.6 نعيّن ذلك الإصدار ضمن البيئة الافتراضية الجديدة، إضافة إلى مدير الحزم Pip ليساعدنا في إدارة تطبيقات بايثون:
conda install python=3.6 pip && \
تثبيت تطبيق بايثون
بحسب طريقة استخدام التطبيق، يمكن تنفيذ أحد أمرين، الأول تثبيته باستخدام pip والذي بدوره يستدعي الملف setup.py
ضمن مستودع التطبيق:
git clone replace-me-with-repo-url cd repo-name pip install -e .
الثاني تنفيذه مباشرة باستخدام الأمر python
:
git clone replace-me-with-repo-url cd repo-name python python-app.py
لتجربة العملية بشكل كامل وفهم كيف يمكن تشغيل التطبيق مباشرةً عبر تشغيل حاوية أو داخل صدفة باش باستخدام دوكر، سنستخدم التطبيق المثال الذي ذكرناه سابقًا python-app.py، باتباع الطريقة الثانية ننشئ ملف التطبيق python-app.py:
echo 'print("Hello World!")' > python-app.py
الملف السابق سيطبع عبارة "Hello World!" عند تنفيذه باستخدام الأمرpython python-app.py
.
تحديث ملف .bashrc للتطبيق مثل مينيكوندا
كما ذكرنا سابقًا، يُحدث مثبت مينيكوندا ملف .bashrc تلقائيًا بعد تنفيذ الأمر conda init bash
، يمكننا تنفيذ أمر مشابه لتطبيقنا، بحيث كلما دخلنا إلى سطر أوامر باش داخل الحاوية سيتم تفعيل البيئة، ويمكن استخدام اسم التطبيق كأمر تشغيل له، سنستخدم الاسم python-app
للدلالة على التطبيق:
RUN echo 'conda activate python-app \n\ alias python-app="python python-app.py"' >> /root/.bashrc
تحضير التطبيق للتنفيذ النهائي
أخيرًا نٌنشئ المدخل للتطبيق ونعين له الأمر الذي سيسمح لنا بتشغيله في كل مرة نشغل حاوية مبنية من الصورة:
ENTRYPOINT [ "/bin/bash", "-l", "-c" ] CMD ["python python-app.py"]
ملف Dockerfile النهائي
باستخدام برنامج محرر نصوص مثل Vim أو Nano أو باستخدام الأمر cat
نضيف الأسطر التي شرحناها سابقًا إلى ملف Dockerfile:
FROM python:slim RUN apt-get update && apt-get -y upgrade \ && apt-get install -y --no-install-recommends \ git \ wget \ g++ \ ca-certificates \ && rm -rf /var/lib/apt/lists/* ENV PATH="/root/miniconda3/bin:${PATH}" ARG PATH="/root/miniconda3/bin:${PATH}" RUN wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh \ && mkdir /root/.conda \ && bash Miniconda3-latest-Linux-x86_64.sh -b \ && rm -f Miniconda3-latest-Linux-x86_64.sh \ && echo "Running $(conda --version)" && \ conda init bash && \ . /root/.bashrc && \ conda update conda && \ conda create -n python-app && \ conda activate python-app && \ conda install python=3.6 pip && \ echo 'print("Hello World!")' > python-app.py RUN echo 'conda activate python-app \n\ alias python-app="python python-app.py"' >> /root/.bashrc ENTRYPOINT [ "/bin/bash", "-l", "-c" ] CMD ["python python-app.py"]
لتشغيل تطبيق مختلف ضمن الحاوية، نبدل السطر التالي:
echo 'print("Hello World!")' > python-app.py
بإحدى الطريقتين المذكورتين سابقًا ضمن قسم "تثبيت تطبيق بايثون".
الخطوة الثالثة: بناء صورة تطبيق بايثون اعتمادا على ملف Dockerfile
أمر بناء صورة معدلة اعتمادًا على ملف Dockerfile هو كالتالي:
docker build -t python-app PATH_to_Dockerfile
الخيار -t
يُمكننا من وسم الصورة الناتجة باسم تطبيقنا، بحيث عينا له القيمة python-app
في الأمر السابق،
بفرض أن ملف Dockerfile موجود ضمن المجلد الحالي يمكننا إنشاء صورة دوكر جديدة لتطبيق بايثون كالتالي:
docker build -t python-app .
avimanyu@iborg-desktop:~/python-docker$ docker build -t python-app . Sending build context to Docker daemon 2.56kB Step 1/8 : FROM python:slim ---> 677f7ac99e48 Step 2/8 : RUN apt-get update && apt-get -y upgrade && apt-get install -y --no-install-recommends git wget g++ ca-certificates && rm -rf /var/lib/apt/lists/* ---> Using cache ---> 15ee9c47c83b Step 3/8 : ENV PATH="/root/miniconda3/bin:${PATH}" ---> Using cache ---> cfd5ed6b5ec9 Step 4/8 : ARG PATH="/root/miniconda3/bin:${PATH}" ---> Using cache ---> e70d06b5ff10 Step 5/8 : RUN wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh && mkdir /root/.conda && bash Miniconda3-latest-Linux-x86_64.sh -b && rm -f Miniconda3-latest-Linux-x86_64.sh && echo "Running $(conda --version)" && conda init bash && . /root/.bashrc && conda update conda && conda create -n python-app && conda activate python-app && conda install python=3.6 pip && echo 'print("Hello World!")' > python-app.py ---> Using cache ---> 8a7957a6abb2 Step 6/8 : RUN echo 'conda activate python-app \nalias python-app="python python-app.py"' >> /root/.bashrc ---> Running in e3193e93b631 Removing intermediate container e3193e93b631 ---> 948f45eb6024 Step 7/8 : ENTRYPOINT [ "/bin/bash", "-l", "-c" ] ---> Running in 621624951dcf Removing intermediate container 621624951dcf ---> 6e8824889502 Step 8/8 : CMD ["python python-app.py"] ---> Running in dc97f9d0d8fe Removing intermediate container dc97f9d0d8fe ---> 01bae0a9903c Successfully built 01bae0a9903c Successfully tagged python-app:latest
يعتمد خرج الأمر السابق على البيانات الموجودة ضمن التخزين المؤقت، بحيث سيأخذ مدة أطول عند تنفيذه لأول مرة وسينتج خرج أطول، يمكننا التحقق فيما إذا كانت صورة دوكر الناتجة تحوي التطبيق التجريبي الذي ثبتناه عبر تشغيل حاوية من تلك الصورة:
docker run python-app avimanyu@iborg-desktop:~/python-docker$ docker run python-app Hello World!
باستخدام دوكر ومينيكوندا يمكننا الآن تشغيل التطبيق مباشرة بدون أي عملية تثبيت أو تهيئة مسبقة للبيئة، حيث كل ما نريده هو تلك الصورة الناتجة، ويمكننا الآن تسجيل الدخول إلى صدفة باش داخل الحاوية كالتالي:
docker run -ti python-app bash avimanyu@iborg-desktop:~/python-docker$ docker run -ti python-app bash (python-app) root@2ceec4c9eaa4:/#
وكما نلاحظ دخلنا إلى بيئة كوندا المفعلة التي أنشأناها سابقًا عبر ملف Dockerfile، استخدمنا الخيار -ti
لإنشاء طرفية تفاعلية لاستخدامها، يمكننا أيضًا استخدام الاسم بديل الذي عيناه للتطبيق سابقًا لتشغيله كالتالي:
(python-app) root@2ceec4c9eaa4:/# python-app Hello World!
لنتحقق أيضًا من استخدامنا لإصدار بايثون الخاص بمينيكوندا وليس الإصدار الافتراضي الخاص بنظام التشغيل:
(python-app) root@2ceec4c9eaa4:/# python --version Python 3.6.12 :: Anaconda, Inc.
كما ذكرنا سابقًا مينيكوندا هو نسخة مصغرة من أناكوندا، وبعد الانتهاء من التحضير بشكل كامل يمكننا دفع الصورة النهائية للتطبيق إلى Docker Hub في حال كان التطبيق نسخة مفتوحة المصدر ومُستضافة على أحد استضافات المستودعات مثل GitHub أو GitLab أو Gitea أو Bitbucket أو أي مستودع آخر.
يمكن الخروج من الحاوية بتنفيذ الأمر exit
ضمن الطرفية، لتوفير المساحة المستخدمة يمكننا إيقاف الحاوية وحذفها وحذف صور دوكر التي تم بناؤها خلال العملية.
ختامًا
تعلمنا في هذا المقال كيف يمكن إنشاء صورة دوكر مخصصة لتشغيل تطبيق بايثون، يزيد مينيكوندا من مرونة تطبيقات بايثون ويُسهل عملية تحديثها مستقبلًا، كما يسهل عمل المطور كثيرًا، حيث يمكن بنفس الطريقة إعداده مع PyCharm.
قمنا بتثبيت مينيكوندا وتطبيق بايثون الذي نعمل عليه كما هي العادة، الفرق أن عملية بناء وحفظ الصورة يتم لمرة واحدة فقط، وبعدها يصبح الأمر عبارة عن عملية واحدة وهي تشغيل حاوية التطبيق فقط.
ترجمة -وبتصرف- للمقال How to Dockerize Python Applications With Miniconda [A Hybrid Approach] لصاحبه Avimanyu Bandyopadhyay.
تعليقات
إرسال تعليق