چگونه یک برنامهٔ Flask را با استفاده از Docker در Ubuntu 20.04 بسازیم و مستقر کنیم؟

Docker یک برنامهٔ متن‌باز است که به مدیران اجازه می‌دهد برنامه‌ها را با استفاده از کانتینرها ایجاد، مدیریت، مستقر و تکثیر کنند. کانتینرها را می‌توان به عنوان یک بسته در نظر گرفت که وابستگی‌هایی را که یک برنامه برای اجرا نیاز دارد در سطح سیستم‌عامل در خود جای داده‌اند. این یعنی هر برنامه‌ای که با Docker مستقر شود در یک محیط مجزا زندگی می‌کند و نیازمندی‌هایش به صورت جداگانه مدیریت می‌شوند.

Flask یک وب میکروفریم‌ورک است که بر پایهٔ Python ساخته شده. به آن میکروفریم‌ورک گفته می‌شود چون برای اجرا به ابزار یا پلاگین خاصی نیاز ندارد. فریم‌ورک Flask سبک و انعطاف‌پذیر است ولی در عین حال ساختاربندی‌شده است، که باعث می‌شود به خصوص برای برنامه‌های وب کوچک نوشته‌شده به زبان Python محبوب باشد.

استقرار یک برنامه Flask با Docker به شما امکان می‌دهد برنامه را در سرورهای مختلف با کمترین نیاز به پیکربندی مجدد تکرار کنید.

در این آموزش، شما یک برنامه Flask ایجاد کرده و با Docker آن را مستقر خواهید کرد. همچنین در مورد نحوه به‌روزرسانی برنامه پس از استقرار توضیح داده می‌شود.

برای دنبال کردن این آموزش به موارد زیر نیاز دارید:

ابتدا ساختار دایرکتوری‌ای که برنامه Flask شما را نگه می‌دارد ایجاد خواهید کرد. این آموزش یک دایرکتوری به نام TestApp در مسیر /var/www ایجاد می‌کند اما می‌توانید این نام را مطابق میل خود تغییر دهید.

وارد دایرکتوری جدید TestApp شوید:

سپس ساختار پایه‌ برای برنامه Flask را ایجاد کنید:

فلگ -p به mkdir می‌گوید دایرکتوری و کلیه دایرکتوری‌های والد که وجود ندارند را ایجاد کند. در این مورد mkdir دایرکتوری app را در فرآیند ساخت دایرکتوری‌های static و templates ایجاد می‌کند.

دایرکتوری app شامل تمام فایل‌های مربوط به برنامه Flask خواهد بود مثل blueprints. Views کدهایی هستند که برای پاسخ دادن به درخواست‌ها نوشته می‌شوند. Blueprints بخش‌هایی از برنامه ایجاد می‌کنند و از الگوهای متداول در برنامه یا برنامه‌های متعدد پشتیبانی می‌کنند.

دایرکتوری static جایی است که دارایی‌هایی مثل تصاویر، CSS و فایل‌های JavaScript قرار می‌گیرند. دایرکتوری templates جایی است که قالب‌های HTML پروژه را قرار می‌دهید.

حال که ساختار پایه تکمیل شده، باید فایل‌های لازم برای اجرای برنامه Flask را ایجاد کنید. ابتدا یک فایل __init__.py در دایرکتوری app بسازید با استفاده از nano یا ویرایشگر متنی دلخواه. این فایل به مفسر Python می‌گوید دایرکتوری app یک پکیج است و باید به این صورت رفتار شود.

برای ایجاد فایل، دستور زیر را اجرا کنید:

nano app/__init__.py

پکیج‌ها در Python به شما اجازه می‌دهند ماژول‌ها را در فضای نام یا سلسله‌مراتب منطقی گروه‌بندی کنید. این روش کد را به بلوک‌های مجزا و قابل مدیریت تقسیم می‌کند که هر کدام وظایف خاصی را انجام می‌دهند.

در ادامه کد زیر را به فایل __init__.py اضافه کنید که یک نمونه Flask ایجاد می‌کند و منطق فایل views.py را وارد می‌کند (views.py را پس از ذخیره این فایل ایجاد خواهید کرد):

from flask import Flask

app = Flask(__name__)

from app import views

پس از افزودن کد، فایل را ذخیره و ببندید. برای ذخیره و بستن در nano، Ctrl+X را بزنید، سپس Y و Enter.

حالا وقت آن است که فایل views.py را در دایرکتوری app ایجاد کنید. این فایل بیشتر منطق برنامه را در بر می‌گیرد.

کد زیر را برای views.py بنویسید که رشته hello world! را به کاربرانی که صفحه وب را باز می‌کنند بازمی‌گرداند:

from app import app

@app.route('/')
def home():
    return "hello world!"

خط @app.route که بالای تابع قرار گرفته یک decorator است. Decoratorها یک قرارداد در زبان Python هستند که معمولاً توسط Flask به کار گرفته می‌شوند؛ وظیفه‌شان تغییر رفتار تابعی است که بلافاصله پس از آن قرار دارد. در اینجا decorator آدرس URL که تابع home() به آن پاسخ می‌دهد مشخص می‌کند. متن hello world که تابع home بازمی‌گرداند در مرورگر به کاربر نمایش داده می‌شود.

حالا فایل uwsgi.ini را ایجاد کنید که تنظیمات uWSGI را برای برنامه ما دارد. uWSGI هم یک پروتکل هم یک Application Server است که می‌تواند پروتکل‌های uWSGI، FastCGI و HTTP را سرو کند و معمولاً با Nginx به کار می‌رود.

فایل uwsgi.ini را بسازید:

nano uwsgi.ini

محتوای زیر را در uwsgi.ini قرار دهید:

[uwsgi]
module = main:app
master = true
processes = 5
socket = 0.0.0.0:5000
vacuum = true
die-on-term = true

این کد ماژولی که برنامه Flask از آن سرو می‌شود را مشخص می‌کند، که در این مثال main.py است و به صورت main آورده شده. گزینه callable به uWSGI می‌گوید که نمونه app که توسط برنامه اصلی صادر شده را استفاده کند. master اجازه می‌دهد برنامه به طور مداوم اجرا شود تا زمان خرابی یا بارگذاری مجدد به حداقل برسد.

فایل main.py را ایجاد کنید، این نقطه ورود برنامه است و به uWSGI نحوه تعامل با برنامه را می‌گوید:

from app import app

if __name__ == "__main__":
    app.run()

فایل requirements.txt را بسازید تا وابستگی‌هایی که pip هنگام ساخت Docker نصب می‌کند را مشخص کنید:

Flask>=2.0.2

این خط، فریم‌ورک Flask را به عنوان وابستگی مشخص می‌کند. نسخه 2.0.2 یا بالاتر نصب خواهد شد. شما می‌توانید این نسخه را با مراجعه به سایت رسمی Flask یا صفحه Python Package Index چک کنید.

حالا Dockerfile را ایجاد کنید. این فایل دستورات لازم برای ساخت ایمیج Docker را در خود دارد.

nano Dockerfile

محتوای زیر را به Dockerfile اضافه کنید:

FROM tiangolo/uwsgi-nginx-flask:python3.8-alpine

RUN apk add --no-cache bash nano git

ENV STATIC_URL /static

COPY requirements.txt /app/

RUN pip install --no-cache-dir -r /app/requirements.txt

در این مثال، ایمیج داکری بر اساس tiangolo/uwsgi-nginx-flask ساخته می‌شود که از منابع متنوعی پشتیبانی می‌کند. خطوط اول parent image را مشخص می‌کند و دستور نصب bash، nano و git را اجرا می‌کند. سپس متغیر محیطی STATIC_URL تنظیم شده که جای قرارگیری فایل‌های استاتیک را تعیین می‌کند. در نهایت فایل requirements.txt به کانتینر کپی شده و بسته‌ها نصب می‌شوند.

اسکریپت start.sh را بسازید که ایمیج را می‌سازد و کانتینر را اجرا می‌کند. ابتدا مطمئن شوید پورتی برای استفاده باز دارید. برای چک کردن این موضوع دستور زیر را بزنید:

sudo nc -z localhost 56733; echo $?

اگر خروجی 1 بود یعنی پورت باز و قابل استفاده است، اگر نه باید پورت دیگری انتخاب کنید.

حالا فایل start.sh را بسازید:

nano start.sh

محتوای زیر را به start.sh اضافه کنید:

#!/bin/bash

app=docker.test

docker build -t $app .

docker run -d -p 56733:80 --name $app -v $(pwd):/var/www $app

خط اول بیان می‌کند که این یک فایل bash است. سپس نام ایمیج و کانتینر در متغیر app ذخیره می‌شود. دستور docker build ایمیجی به نام docker.test از Dockerfile می‌سازد. سپس docker run کانتینری با همین نام می‌سازد، پورت 56733 را به پورت 80 داخل کانتینر متصل می‌کند و دایرکتوری فعلی روی مسیر /var/www کانتینر نصب می‌شود.

حالا می‌توانید اسکریپت start.sh را اجرا کنید:

bash start.sh

کانتینرهای در حال اجرا را با دستور زیر مشاهده کنید:

docker ps

وقتی کانتینر اجرا شد، در مرورگر به آدرس http://ip-address:56733 بروید و صفحه Hello World را مشاهده کنید.

برای نمایش قالب‌ها، فایل home.html در مسیر app/templates بسازید:

nano app/templates/home.html

محتوای زیر را قرار دهید:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Home Page</title>
</head>
<body>
  <h1>Welcome to the Home Page</h1>
  <p>This is a simple Flask template.</p>
</body>
</html>

سپس در app/views.py این تغییرات را اعمال کنید:

from app import app
from flask import render_template

@app.route("/")
def home():
    return "hello world!"

@app.route("/template")
def template():
    return render_template("home.html")

برای اعمال این تغییرات، کانتینر Docker را مجدداً بسازید و اجرا کنید:

bash start.sh

این بار در مرورگر به http://ip-address:56733/template بروید و قالب HTML را ببینید.

برای به‌روزرسانی برنامه بدون ریستارت کانتینر می‌توانید از ویژگی touch-reload در فایل uwsgi.ini استفاده کنید:

nano uwsgi.ini

خط زیر را به انتهای آن اضافه کنید:

touch-reload = /var/www/TestApp/uwsgi.ini

بعد از ذخیره فایل، وقتی تغییری در این فایل ایجاد شود، uWSGI کانتینر را ریلود می‌کند.

اگر مثلاً در app/views.py تغییر دادید، مثلاً متن تابع home را:

def home():
    return "hello world updated"

و حالا می‌بینید تغییرات در صفحه اصلی دیده نمی‌شود، دستور زیر را اجرا کنید تا uwsgi.ini تغییر بخورد و برنامه ریفرش شود:

touch /var/www/TestApp/uwsgi.ini

اکنون صفحه مرورگرتان را refresh کنید و تغییر را مشاهده خواهید کرد.

نحوه نصب بسته جدید Python و افزودن آن به برنامه Flask در این کانتینر Docker

برای افزودن بسته جدید Python مانند flask_mail به برنامه Flask مستقر شده در Docker به این صورت عمل کنید:

  1. ابتدا در فایل requirements.txt بسته مورد نظر خود را اضافه کنید. مثلاً برای flask_mail یک خط مثل زیر اضافه کنید:
    Flask-Mail
    
  2. در فایل app/views.py خطوط import مربوط به flask_mail را بنویسید:
    from flask_mail import Mail, Message
    
  3. سپس فایل start.sh یا به صورت دستی دستور ساخت دوباره Docker را اجرا کنید:
    docker build -t docker.test .
    docker stop docker.test
    docker rm docker.test
    docker run -d -p 56733:80 --name docker.test -v $(pwd):/var/www docker.test
    

    این کار باعث می‌شود که ایمیج جدید به همراه بسته flask_mail ساخته و کانتینر جدید اجرا شود.

توجه مهم: فقط نصب flask_mail در سیستم خارج از داکر کافی نیست، چون داخل کانتینر جداگانه اجرا می‌شود. باید در requirements.txt ذکر و مجدداً ایمیج ساخته شود.

 

از همراهی شما با پارمین کلود متشکریم.

Click to rate this post!
[Total: 0 Average: 0]

نظرات کاربران

دیدگاهی بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *