← Back to blog

在 Ubuntu 20.04 上使用 Docker 建置與部署 Flask 應用程式

Category
在 Ubuntu 20.04 上使用 Docker 建置與部署 Flask 應用程式

簡介

Docker 是一個開源的容器平台。它是一個輕量級、虛擬化、可移植、軟體定義的標準化環境,允許軟體與運行在實體主機上的其他軟體隔離運行。Docker 提供了一個替代虛擬機的輕量級選擇。同時,它還提供了應用程式的可移植性、效能、敏捷性和可擴展性。如需完整的 Docker 生態系統指南,請參閱我們關於使用 Docker 進行容器化的詳細概述.

Flask 是一個開源的微型網頁框架,使用 Python 構建。Flask 的一些優秀特性包括輕量、靈活且高度結構化。此外,它不需要任何特定的工具或外掛程式即可運行。

將 Flask 和 Docker 結合使用,可以為您提供一個輕量、靈活且具可擴展性的應用程式。得益於 Docker 容器的可移植性,您可以將其部署到多個伺服器和基礎設施中。本教學的重點是向您展示如何使用 Docker 部署 Flask 應用程式。我們還將演示如何確保應用程式未來的更新能夠生效。

先決條件

這是一個動手實作的教學,您應該建立一個能夠跟著操作的環境:

現在,讓我們開始吧!

步驟 1:準備 Flask 應用程式

我們將首先建立一個用於存放 Flask 應用程式的目錄。您可以自行選擇目錄名稱。不過,在本教學中,我們將其命名為 flask_demo。我們將把專案檔案儲存在 /var/www 目錄中,這通常是 Ubuntu 預設允許公共網際網路存取的目錄。首先,執行以下命令來建立該目錄並進入其中:

在我們專案的根目錄中,我們將建立 Flask 應用程式的基本資料夾結構。接下來,執行以下命令來建立基本結構,並加上 -p 參數以同時建立所有父資料夾:

app 資料夾存放與 Flask 應用程式相關的所有檔案,包括 views 和 blueprints。Views 包含您編寫用於回應傳送到應用程式之請求的程式碼。Blueprints 有助於構建應用程式組件,並支援 Flask 應用程式中的常見模式。

顧名思義, static 資料夾存放靜態資產,例如圖片、CSS 和 JavaScript 檔案。 templates 目錄則存放專案的所有 HTML 範本。

現在我們可以開始編寫初始化 Flask 應用程式所需的檔案。首先在 app 目錄中建立一個名為 __init__.py 的檔案,以告知 Python 直譯器 應該將 app 目錄視為一個套件。在您的終端機上執行以下命令,以使用 nano 編輯器開啟該檔案:

我們在 Python 中使用套件將模組分組到邏輯命名空間或階層中。模組化允許將程式碼分解為執行特定功能的獨立且易於管理的區塊。

之後,在編輯器中開啟的 __init__.py 檔案中,新增以下程式碼片段以啟動 Flask 實例,並從您將在後續步驟中建立的 views.py 中匯入邏輯:

完成後,請按 Ctrl + O 和 ENTER 以儲存檔案,然後使用 Ctrl + X 關閉它。接下來,讓我們在 views.py 資料夾內建立 app 目錄。 views.py 檔案將包含大部分的應用程式邏輯:

在檔案中加入以下程式碼片段。這段程式碼將在使用者造訪您的網站時顯示一個簡單的字串,以表示您的應用程式正在執行:

在此檔案中,我們首先匯入 Flask 應用程式執行個體。然後,我們需要加入一行來定義路由: @app.route(/)。 @app.route(/) 行在 Flask 中被稱為 decorator。您可以使用裝飾器將額外的功能注入到一個或多個函式中。在此案例中,我們將對路由的呼叫傳遞給 / 到 home 函式。當使用者造訪此路由時,他們將會看到以下文字: "Our Flask application is running!".

接下來,您將建立 uwsgi.ini 檔案,以儲存應用程式的 uWSGI 設定。 uWSGI 是 Nginx 的一種部署選項,可用作協定和應用程式伺服器。執行以下命令,使用 nano 編輯器在專案的根目錄中建立該檔案:

在開啟的檔案中,加入以下程式碼片段:

此檔案包含一些指令。我們在下方定義它們的用途:

  • module – 定義提供 Flask 應用程式服務的模組。我們已將模組設定為 main,這會引用根目錄中的 main.py 檔案。我們將在下一步中建立此檔案。
  • callable – 指示 uWSGI 使用從應用程式匯出的 app 執行個體。
  • master – 確保應用程式持續執行,以在重新載入整個應用程式時將停機時間降至最低。

完成後,儲存並關閉檔案。

現在您可以建立 main.py 檔案,以確定應用程式的進入點。 uWSGI 將讀取此檔案以了解如何與應用程式互動。執行以下命令,以建立 main.py  檔案,使用 nano 於專案的 root directory 中:

在檔案中加入以下行,這將匯入在應用程式套件中建立的 Flask 執行個體:

在此步驟中,您要做的最後一件事是定義應用程式執行所需的相依性。我們將在名為 dependencies.txt 的檔案中定義這些相依性。當 Docker 建置您的應用程式映像檔時,它將執行 pip (package manager) 命令來安裝相依性。使用以下命令在根目錄中開啟該檔案:

到目前為止,在我們的專案中,我們只需要一個相依性: Flask。因此,我們可以加入以下行來引用我們專案所需的正確 Flask 版本:

我們決定使用 Flask version 2.0.1 作為相依性。這是撰寫本教學時的最新版本。您可以從 Flask Changes 頁面中了解更多關於各個版本的資訊。這樣就完成了 Flask 應用程式的設定。現在讓我們準備用於部署的 Docker 設定。

Step 2: Configure Docker

要設定 Docker 部署,我們將建立兩個檔案: Dockerfile 以及 start.sh。 Dockerfile 包含構成 Docker 映像檔的宣告行。而 start.sh 是一個基本的 Shell 指令碼,用於建置映像檔並從 Dockerfile 啟動容器。在專案的根目錄中,執行以下命令以建立 Dockerfile:

此檔案包含 Docker 映像檔所需的設定。接下來,加入以下程式碼片段以指定相依性以及如何建置映像檔:

中的第一行Dockerfile 定義了我們用來構建映像檔的基礎映像檔。在這種情況下,我們將基於 tiangolo/uwsgi-nginx-flask,可從 DockerHub 取得。我們選擇這個特定的映像檔是因為它支援許多 Python 版本。

我們還指定了要更新映像檔。然後,我們需要添加 bash 指令 processo、 nano 文字 編輯器,以及 git 用戶端,用於從版本控制存放庫(例如 )拉取和推送原始碼GitHub, Bitbucket, 或 Gitlab。帶有 ENV 指定要在容器中使用的環境變數。

The COPY 指令將依賴項複製到容器中。 RUN 指令會調用 pip 套件 管理員 來解析 dependencies.txt 檔案並 安裝 這些依賴項。編輯完成後,儲存並關閉檔案。

接下來,您將建立 start.sh 腳本。此腳本將包含 Docker 指令來 構建 和 運行 該映像檔。雖然您可以在終端機上逐步執行這些指令,但我們認為將它們添加到 Shell 腳本中,並只需在終端機中用一個指令調用它會更乾淨。

在定義此檔案的內容之前,我們必須先確定一個其他服務未使用的空閒連接埠。我們將使用連接埠 45644。不過,您可以選擇不同的連接埠。執行以下行以檢查該連接埠是否空閒:

根據您選擇的連接埠,如果上述指令的輸出為 1,那麼它就是空閒的。否則,您可能必須選擇另一個連接埠並再次嘗試該指令:

Flask application Port Check

既然我們已經確定了一個空閒連接埠,我們現在可以透過運行以下指令,在專案的根目錄中使用 nano 建立該檔案:

在此檔案中,添加以下程式碼片段:

第一行,被稱為 shebang,指定這是一個 bash 檔案,應作為指令執行。第二行宣告了一個名為 app_name 的變數。我們使用此變數來設定映像檔和容器名稱。第三行指示 Docker 構建 基於當前目錄中 Dockerfile 定義的映像檔。該映像檔將根據變數命名為 docker-flask-demo。

最後一行建立了一個名為 docker-flask-demo,如我們定義的變數所示。 -d 旗標使容器在指令執行完畢後,以分離狀態在背景繼續運行。 -p 旗標將伺服器上的連接埠綁定到容器上的特定連接埠。在這種情況下,我們將主機上的連接埠 45644 掛載到 Docker 將在容器中公開的連接埠 80。

我們使用 -v 旗標來指定要掛載到容器上的 Docker 磁碟區。 $PWD 變數是一個預設的 Linux 變數,保存您在特定時間所在的 目前目錄 的路徑:

Flask application pwd

在我們的案例中,我們將整個專案目錄掛載到容器的 /var/www 目錄。Docker 設定現在已準備就緒。您可以透過執行以下指令,基於構建的映像檔來構建映像檔並啟動容器:

等待腳本運行完畢,然後執行以下 Docker 命令以列出所有運行中的容器:

輸出將顯示運行中的容器:

Demo Docker

您應該會在運行中的容器列表中看到名稱為 docker-flask-demo 的容器。找到您伺服器的公用 IP 並在瀏覽器中透過指定的連接埠存取它: http://your-server-public-ip:45644.

您應該會看到類似的輸出:

Flask App Running

如果您在瀏覽器中看到上述內容,則表示您已成功部署 Flask 應用程式。接下來,我們將修改檔案並透過範本向使用者提供內容。

步驟 3:透過範本檔案提供內容

在 Flask 中,範本 用於向網站訪客顯示靜態和動態內容。我們將向您展示如何建立一個 HTML 範本,並在使用者造訪特定路由時將其提供給他們。例如,這可以是首頁或「關於」頁面。

在您的終端機上執行以下命令,以在 index.html 檔案建立於 app/templates 目錄中:

然後,將以下程式碼片段新增至該檔案:

完成後儲存並關閉檔案。此外,使用以下命令建立另一個頁面,我們稱之為「關於」頁面:

將以下程式碼片段新增至該檔案:

完成後儲存並關閉檔案。接下來,修改 app/views.py 檔案以引用範本以及實際頁面的路由:

修改檔案,使其看起來像這樣:

完成後儲存並關閉檔案。您所做的變更在停止並重新啟動容器之前不會生效。執行以下 Docker 指令來停止和啟動容器。請注意我們之前定義的容器名稱:

容器啟動並運行後,造訪首頁和關於頁面以查看一些新內容:

Flask application Index

 Flask application 1

到目前為止,您已經建立了一個可以向網站訪客提供內容的 Flask 應用程式。以下是該專案的檔案結構:

File Structure

您可能已經注意到,我們必須重新啟動 Docker 容器才能套用新的變更。在下一步中,我們將使其自動化,以確保減少停機時間。

步驟 4:設定應用程式檔案更新以自動重新載入

我們經常會對應用程式進行變更,以改進邏輯、使用者介面或新增一些依賴項。為了使這些變更生效,可能需要您重新啟動 Docker 容器。幸運的是, uWSGI 具有一個名為 touch-reload 的功能,用於在不重新啟動容器的情況下重新載入 Python 指令碼。

開箱即用,Python 具有一個 auto-reloading 功能,它會監視整個檔案系統的變更,並在發生變更時重新整理應用程式。雖然自動重新載入有利於減少停機時間,但它可能會消耗大量資源。因此,不建議在生產環境中使用。

讓我們看看如何使用 touch-reload 來監視特定檔案的變更,並在發生變更時重新載入應用程式。使用 nano 編輯器修改 uwsgi.ini 檔案:

新增醒目提示的行,使其看起來像這樣:

完成後儲存並關閉檔案。新增的行指定了一個檔案,修改該檔案將觸發應用程式的重新載入。但是,為了使此條件在未來的修改中生效,您必須先重新啟動容器:

您現在可以修改 app/views.py 檔案以示範自動重新載入的工作原理:

將 home 函數傳回的字串變更為醒目提示的內容:

完成後儲存並關閉檔案。

在瀏覽器中開啟應用程式的首頁: http://your-server-public-ip:45644.

您還不會看到任何變更。這是因為 touch-reload 條件偵測的是對 uwsgi.ini 檔案的變更。您可以使用 touch 來啟用該條件,從而使用以下指令重新載入整個應用程式:

現在,如果您重新載入首頁,您將會看到顯示的新變更:

Touch Reload

未來,如果您進行任何變更,只需執行以下指令 sudo touch uwsgi.ini ,整個應用程式將以更短的停機時間重新載入。本教學到此結束。

結論

在本教學中,您使用 Docker 映像檔和容器實作並部署了一個 Flask 應用程式。為了透過避免重新啟動容器來減少停機時間,您設定了 touch-reload 來監聽特定檔案的變更,並自動重新載入整個應用程式。最後,您在瀏覽器中測試了所有這些功能,以確保其正常運作。

Docker 可確保更快的部署,並允許輕鬆擴充應用程式。如果您想了解更多關於各種 Docker 指令的資訊,請參閱這篇關於 如何在 Ubuntu 上安裝和使用 Docker.

如需更多關於 Docker 的資源,請造訪 我們的部落格,您可以參考以下內容:

祝您運算愉快!

Pranay Kapgate

Author · CloudSigma

Comments

No comments yet. Be the first.