返回部落格

在 Ubuntu 上使用 Docker 建立 Django 與 Gunicorn 應用程式

在 Ubuntu 上使用 Docker 建立 Django 與 Gunicorn 應用程式

Django 是一個高階的開源 Python 網頁框架,可以幫助您快速構建 Python 應用程式。它遵循模型-模板-視圖(model–template–views)架構模式,鼓勵快速開發和乾淨、務實的設計。該框架開箱即用,配備了必要的現代應用程式組件,例如使用者驗證、快取框架, 物件關係對映器, URL 分發器, 模板系統,以及可自訂的管理介面。

Gunicorn ‘Green Unicorn’ 是一款適用於 UNIX 系統的 Python WSGI HTTP 伺服器。Gunicorn 伺服器與各種網頁框架相容,提供卓越的效能,且佔用極少的伺服器資源。 Docker 是一個開源容器平台,已經推出了一段時間,它使應用程式開發變得快速、高效且可預測。

在本教學中,您將獲得開發和部署可擴充容器化 Django 網頁應用程式的技能。我們將使用一個 Django Polls 應用程式,該程式是按照 Django 入門指南建立的。在撰寫本教學時,我們將其基於 Django 3.2 ,並由 Python 3.6 或更高版本支援。我們將使用 Docker 將該應用程式部署為容器,並使用 Gunicorn 伺服器進行服務。當然,在容器中部署 Django 應用程式之前,您必須對專案程式碼進行一些修改,以處理諸如記錄到標準輸出流以及使用環境變數等工作。CSS 和 JavaScript 圖片等靜態檔案可以卸載到物件儲存服務中,以便在多容器環境中從單一位置輕鬆管理這些檔案。

我們將向您展示如何根據設計良好的 twelve-factor 方法論來建置可擴充的網頁應用程式。完成修改後,您將建置該應用程式的 Docker 映像檔,並使用 Docker 部署容器化應用程式。我們建議您按照教學中概述的步驟進行操作,以充分理解本教學。

先決條件

由於這是一個動手實作的教學,我們建議您進行以下設定以協助您跟隨步驟:

  • 一台 Ubuntu 20.04 伺服器。您可以按照此 逐步教學來協助您設定您的 Ubuntu 伺服器 於 CloudSigma 上。

  • 請確保您新增一個 具有 sudo 權限的使用者 於我們將用來執行上述教學中概述指令的兩個節點上。

  • 在伺服器上安裝 Docker。您可以按照我們關於 安裝和操作 Docker 的教學 的步驟 1、2 和 3。請記住將上面建立的 sudo 使用者新增至 Docker 群組中。

  • 相容的物件儲存空間。Django 支援多種儲存服務,如 django-storages 文件 中所述。您可以選擇您偏好的一種,並按照文件進行設定。在本教學中,我們將使用 MinIO ,這是一個與 S3 相容的雲端儲存服務。

  • 一個 SQL 資料庫執行個體。 Django 支援多種 SQL 資料庫 ,您可以自由選擇。在本教學中,我們將使用 PostgreSQL。PostgreSQL 資料庫將不會部署在容器內。我們將設定一台獨立的 Ubuntu 伺服器來託管 PostgreSQL 執行個體,以確保實現我們的多容器設定以及資料持久化。您可以 建立另一個 Ubuntu 20.04 執行個體,並按照本教學來 在 Ubuntu 上設定 PostgreSQL 資料庫執行個體。請記住按照步驟 23 中的說明,在 PostgreSQL 資料庫中為您的 sudo 使用者新增一個角色。此角色將允許您從託管容器的其他伺服器連線到資料庫。

根據這些先決條件,您應該擁有兩個 Ubuntu 伺服器執行個體。一個執行個體將執行您的 Docker 容器,另一個執行個體將執行 PostgreSQL 執行個體。讓我們開始吧!

步驟 1:設定 PostgreSQL 資料庫執行個體

在本節中,我們將修改執行 Postgres 執行個體的 Ubuntu 伺服器上的 Postgres 設定。這將允許來自外部 IP 位址的連線。連線後,我們可以建立一個專門用於我們正在部署的 Django Polls 應用程式的資料庫和使用者角色。

首先,如果您已按照先決條件進行了環境設定,您的 PostgreSQL 資料庫中應該已經有一個適用於您的 sudo 使用者的角色。接下來,我們需要為此角色設定密碼。在執行 PostgreSQL 的伺服器上,使用以下指令登入 Postgres 終端機:

進入 Postgres 終端機後,發送 \password 指令以修改使用者的密碼。該 \password 指令的語法為 \password <username>。在我們的情況下,指令為:

輸入密碼並確認。將此密碼儲存在安全的地方,因為您稍後將使用它從另一個 Ubuntu 伺服器進行驗證。之後,輸入 exit 並按下 Enter 鍵以退出 Postgres 終端機。

如果您已在 PostgreSQL 伺服器執行個體上啟用防火牆 (ufw),您將需要允許流量通過 Postgres 預設連接埠 5432。您可以將流量限制為僅源自將執行 Docker 容器的另一個 Ubuntu 伺服器的特定 IP 位址。執行以下指令以新增 ufw 規則,並在醒目提示處替換為您的 IP 位址:

這將確保只有您的伺服器可以連線到 PostgreSQL 執行個體。雖然這允許流量通過防火牆,但您還需要修改 PostgreSQL 設定檔以允許來自遠端 IP 位址的連線。預設情況下,該設定僅允許來自 localhost 的連線。PostgreSQL 的設定檔位於 /etc/postgresql/12/main 目錄。 12,在此情況下,是我們為本教學安裝的 PostgreSQL 版本。您可能安裝了不同的版本。因此,您可以切換到目錄 /etc/postgresql/ 並列出內容以尋找您安裝的 PostgreSQL 版本號。

使用 nano 修改設定檔:

找到下面這行,並取消註解,將其設定為允許來自所有 IP 的連線:

儲存並關閉檔案。然後,您也必須編輯 pg_hba.conf 檔案,它與 postgresql.conf 位於同一個目錄。 pg_hba.conf 允許您定義可以從哪些電腦連線到 PostgreSQL 執行個體,以及驗證方法。使用 nano 開啟檔案:

請閱讀此檔案中的註解以了解關鍵字。我們正在尋找的區段是這個:

Building a Django and Gunicorn Application with Docker on Ubuntu 1

我們的重點將放在第二行,您會希望它在取消註解後看起來像下面這行:

請將醒目提示的部分替換為您的 Ubuntu 伺服器 IP 位址,以允許其連線到 PostgreSQL 執行個體。準備好後儲存檔案。重新啟動 PostgreSQL 資料庫以使變更生效:

我們具有指定 IP 位址的另一個 Ubuntu 伺服器應該就能夠連線到 Postgres 執行個體。

步驟 2:連線到 PostgreSQL 伺服器執行個體並建立資料庫和使用者

在此步驟中,我們將嘗試確保服務於我們 Docker 容器的 Ubuntu 執行個體 可以連線到執行 PostgreSQL 執行個體 的另一台伺服器。登入具有 Docker 的 Ubuntu 執行個體,並安裝 postgresql-client 套件到 Ubuntu 主機中(尚未在容器內)。

按照慣例,先更新 apt 套件,然後使用以下指令安裝套件:

上面安裝的套件將協助您為應用程式建立資料庫和使用者。接下來,我們需要透過向 PostgreSQL 用戶端發送連線參數來連線到 PostgreSQL 執行個體。

連線參數遵循以下語法:

在此命令中, username 是您新增到 PostgreSQL 資料庫的使用者/角色。 host 是執行 PostgreSQL 資料庫的 Ubuntu 執行個體的 IP 位址。 port 是 Postgres 監聽傳入連線的預設連接埠,即 5432。在 database 的位置,我們將使用名為 postgres 的預設資料庫,它是隨 PostgreSQL 安裝一起提供的。請在醒目提示的部分中適當地替換您的值,然後按 Enter。出現提示時,輸入您設定的密碼。這會將您登入到 Postgres 提示字元,您可以在其中管理資料庫。

您已成功連線到 PostgreSQL 執行個體。您現在可以為 Django polls 應用程式建立資料庫。我們將其命名為 django_polls:

請確保您的陳述式以分號結尾,以避免出錯。然後,切換到 django_polls 資料庫,使用以下命令:

接下來,建立一個專屬於此專案的資料庫使用者。我們將使用者命名為 django_user:

為您的使用者選擇一個安全的密碼。完成後,我們需要修改剛剛建立的使用者的連線參數。這有助於確保每次建立連線時不會查詢和設定正確的值,從而加快資料庫操作的速度。

將 Django 預期之預設編碼設定為 UTF-8:

接下來,將預設交易隔離配置設定為「 read committed」,這會封鎖來自未提交交易的讀取:

設定您的時區。為了保持教學的通用性,我們將使用 UTC:

最後,將資料庫的管理權限授予新使用者:

準備就緒後,結束 PostgreSQL 提示字元:

此步驟到此為止。一旦您正確設定了 Django 應用程式,它應該就能夠管理您的資料庫。

步驟 3:從 Git 存放庫提取應用程式並定義相依性

在此步驟中,我們將複製 Django-polls 應用程式存放庫。此存放庫包含 Django’s 撰寫您的第一個 Django 應用程式教學課程.

登入執行 Docker 的 Ubuntu 伺服器,建立一個名為 django_project 的目錄並進入其中:

然後,使用以下命令將存放庫複製到該目錄中:

進入該目錄並列出內容:

列出目錄的內容:

Building a Django and Gunicorn Application with Docker on Ubuntu 2

請注意以下項目:

  • manage.py:此檔案是 Django 提供用來管理應用程式的命令列公用程式的入口。

  • mysite:包含 Django 專案範圍和程式碼設定的目錄。

  • polls:包含 polls 應用程式程式碼的目錄。

  • templates:包含管理頁面的自訂範本檔案。

若要深入了解我們實際建立專案的方式,請參閱官方文件中的 Writing your first Django app。在 django-polls 目錄中,我們希望在一個文字檔案中定義我們的 Python 依賴項。我們將其命名為 requirements.txt。使用您偏好的編輯器打開該檔案:

將以下幾行貼入檔案中以宣告依賴項:

在此檔案中,我們定義了 Python 依賴項及其在建置應用程式時應安裝的確切版本。其中一些包括 Django, django-storages 用於與物件儲存貯體進行互動, psycopg2 配接器用於 PostgreSQL, gunicorn WSGI 伺服器,以及其他額外的依賴項。完成後儲存並關閉檔案。

步驟 4:為 Django 應用程式設定環境變數

twelve-factor app」方法論建議您應該從應用程式的程式碼庫中提取硬編碼的設定。這樣一來,您就可以在執行時透過修改環境變數來自由地更改應用程式的行為,而無需觸動程式碼庫。Docker 支援這種設定,因此我們將修改設定檔案以配合環境變數運作。Kubernetes 也支援這種設定。我們將在 CloudSigma blog.

The settings.py 是 Django 專案的主要設定檔案。它是一個使用原生資料結構來設定應用程式的 Python 模組。對於我們的應用程式,該檔案位於 django-polls/mysite/settings.py。它的大多數值都是硬編碼的。如果您更改應用程式的行為,這將需要您修改程式碼庫中的設定檔案。我們想要改變這一點。幸運的是,Python 提供了 getenv 函式,位於 os 模組中。我們可以使用它來設定 Django,使其改為從本機環境變數中讀取設定參數。

讓我們繼續修改 django-polls/mysite/settings.py 檔案,以取代變數的硬編碼值。我們可能希望在執行時透過呼叫 os.getenv 來進行更新。此函式會讀取在提供的環境變數名稱中設定的值。或者,您可以提供第二個參數,即在未設定環境變數時將使用的預設值。

以下是一個範例:

在上面這行程式碼中,我們告訴 Django 從環境變數中檢索金鑰。我們沒有提供備用值,因為我們將從外部提供該金鑰。如果它不存在,應用程式應該會啟動失敗。在外部提供金鑰的同時,我們還希望確保我們所有容器化的應用程式複本在各個伺服器上都使用相同的金鑰。這可以避免因應用程式的各個複本使用不同金鑰而產生的潛在問題。

以下是另一個帶有預設選項的範例:

在這一行中,我們定義了一個環境變數 DEBUG ,該變數應該被讀取。然而,如果未設定它,我們提供了第二個參數,該參數將傳遞給 DEBUG 設定變數。 DEBUG 被設定為 False ,以確保在應用程式出現問題時,敏感資訊不會被傳遞到前端。然而,如果我們處於開發模式,我們希望將其設定為 True ,以便我們能夠查看錯誤資訊,從而更容易地修復錯誤。

現在您已經知道環境變數的重要性,請在編輯器中打開 django_project/django-polls/settings.py。首先,匯入 os 模組,方法是在 settings.py 檔案頂部新增此行:

然後,找到這些變數並按如下方式更新:

ALLOWED_HOSTS 設定中,我們指定它應該從 DJANGO_ALLOWED_HOSTS 環境變數中獲取值,並將其拆分為 Python 列表,使用逗號( ,)作為分隔符。如果該變數缺失, ALLOWED_HOSTS 會被設置為 127.0.0.1.

接下來,滾動瀏覽文件並找到 DATABASES 部分,將其配置為也從環境變數中讀取:

請注意,我們添加了 json.loads 模組。您還應該在 settings.py 文件的頂部添加該模組的導入:

json.loads 函數會將傳入 DATABASES['default']['OPTIONS'] 的 JSON 物件從 DB_OPTIONS 環境變數中進行反序列化。指定此選項允許我們傳入任意數據結構來定義資料庫配置。資料庫引擎包含一組適用於它的有效選項。JSON 選項使我們能夠靈活地為當時使用的資料庫引擎編碼具有適當參數的 JSON 物件。

DATABASES['default']['NAME'] 指定了我們設置的關聯式資料庫管理系統中的資料庫名稱。如果使用 SQLite 資料庫,您應該指定資料庫檔案的路徑。

請注意,Python 提供了幾種方法來讀取外部環境變數。我們只使用了其中一種。您可以自由研究並使用其他方法。在此步驟中,您已學習如何使用外部環境變數。這使您能夠靈活地更改變數並改變在容器中運行的應用程式的行為。在下一步中,您將學習如何使用物件儲存服務。

步驟 5:使用外部物件儲存服務

將應用程式容器化的主要優勢在於使其具有可移植性,以便在流量增加時輕鬆部署應用程式的多個副本。因此,這為擴展提供了空間。然而,這也帶來了在各個容器之間維護靜態檔案和資產版本的問題。得益於雲端技術的進步,您可以將這些共享的靜態元素卸載到外部儲存中。然後,您可以使這些檔案通過網路可供所有運行的容器存取。與其嘗試在各個運行的容器之間同步檔案,您不如擁有一個集中管理它們的地方。

我們上面試圖解釋的概念是使用雲端物件儲存服務,或簡單儲存服務 (S3)。Django 有一個名為 django-storages,它允許您使用遠端儲存後端。 Django-storages 適用於大多數與 S3 相容的物件儲存服務,例如 FTP、SFTP、Amazon 的 AWS S3、Google Cloud Storage、Dropbox 和 Azure Storage 等。在本教學中,我們將使用 MinIO。您可以隨意使用任何其他 與 S3 相容的物件儲存服務. MinIO MinIO 提供高效能、與 S3 相容的物件儲存。透過 MinIO,您可以在任何雲端上建置與 S3 相容的數據基礎架構。

我們將向您展示如何在 CloudSigma 平台上設定 MinIO 儲存服務。請按照以下步驟操作:

  • 首先 在 CloudSigma 上建立帳戶。 如果您在建立 MinIO 儲存時遇到任何問題,請聯絡 CloudSigma’s 免費 24/7 即時線上客服支援,他們將為您提供協助。

  • 新增您的帳單資訊。

  • 接下來,從這裡申請您的公開存取儲存貯體: https://blog.cloudsigma.com/xxxx。您需要聯絡即時聊天支援以獲取您的帳戶存取憑證。

  • 建立 MinIO 物件儲存環境後,系統將為您提供存取憑證以及其他存取說明。憑證應包含您的 MINI_ACCESS_KEY, MINIO_SECRET_KEY,以及 MINIO_URL。您將在下面的說明中使用這些金鑰。

讓我們對 mysite/settings.py 檔案進行更多修改(我們在前面的步驟中一直在修改該檔案)。在檔案中,將 storages 應用程式新增到 Django 的 INSTALLED_APPS:

INSTALLED_APPS

storages 應用程式是透過 django-storages 安裝的,如 requirements.txt 中所定義。捲動到檔案底部,並將 STATIC_URL 變數替換為以下程式碼片段:

請注意,某些設定變數是硬編碼的:

  • STATICFILES_STORAGE:定義 Django 用來處理靜態檔案的儲存後端。在我們的指南中,我們使用的是 MinIO 儲存,但您可以使用任何 與 S3 相容的後端,如 Django Storages 文件中所述.

  • AWS_S3_OBJECT_PARAMETERS:定義快取控制(cache-control)標頭。

  • AWS_LOCATION:我們使用它在儲存貯體中設定一個目錄,所有靜態檔案都將儲存在該目錄中。您可以自由選擇不同的名稱。

  • AWS_DEFAULT_ACL:設定靜態檔案的存取控制清單 (ACL)。將值設定為 ‘ public-Read’ 將使所有公開使用者都能存取這些檔案。

  • STATIC_URL:Django 使用此變數中設定的基礎 URL 來產生靜態檔案的 URL。在此情況下,基礎 URL 是由端點 URL 和靜態檔案子目錄組合而成。

  • STATIC_ROOT:定義在將靜態檔案複製到遠端物件儲存之前,要在本機收集這些檔案的位置。

我們還擁有一些外部定義的環境變數,以保持靈活性和可移植性:

  • AWS_STORAGE_BUCKET_NAME:定義 Django 將上傳靜態資源的儲存貯體名稱。

  • AWS_S3_ENDPOINT_URL:定義用於存取物件儲存服務的端點 URL。這將是映射到託管您 MinIO 服務之伺服器的 URL。

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

設定妥當並安裝好宣告的 Python 依賴項後,您隨時可以執行 Django 指令 manage.py collectstatic 來收集您專案的靜態檔案,並將它們上傳到遠端物件儲存後端:

然而,我們還沒有設定 env 檔案的配置,因此它很可能會失敗。

當您執行該指令時,根據檔案大小和您的網路速度,將靜態資源複製到 MinIO 雲端儲存需要花費一點時間。

此步驟到此為止。接下來讓我們看看如何將 Django 日誌推送到 Docker Engine,以便您可以在下一步中使用 docker logs 指令來檢視它們。

步驟 6:在 Django 應用程式中設定日誌記錄

在偵錯模式下,當 DEBUG 選項設定為 True 時,Django 會將資訊記錄到標準輸出和標準錯誤。日誌資訊通常會顯示在您啟動開發 HTTP 伺服器的終端機上。

在生產環境中,您可能會使用不同的 HTTP 伺服器,且 DEBUG 選項設定為 False 。在這種情況下,Django 將使用不同的日誌記錄方法。Django 會將優先級為 ERRORCRITICAL 的日誌發送到您定義的管理員電子郵件帳戶。這在許多情況下都非常有效。

在容器化和 Kubernetes 設定中,強烈建議將日誌記錄到標準輸出和標準錯誤。日誌訊息會收集在節點的檔案系統上的單一目錄中,並且可以使用 kubectldocker 指令輕鬆存取。透過節點檔案系統上的集中式日誌記錄點,維運團隊可以輕鬆地在每個節點上執行程序來監控和轉發日誌。因此,我們必須配置我們的應用程式以將日誌寫入此標準設定。

您會很高興地了解到,Django 利用了 Python 標準函式庫中高度可自訂的 logging 模組。這允許您定義一個傳遞給 logging.config.dictConfig 的字典,以定義所需的輸出和格式。這裡有一篇關於 Django Logging, The Right Way 的好文章,可以幫助您掌握 Django 日誌記錄的技術。

在編輯器中打開 django-polls/mysite/settings.py  檔案。在檔案頂部新增 Python logging.config 函式庫的匯入:

到目前為止,加上我們新增的所有匯入,您在 settings.py 中的匯入區段應該看起來像這樣:

Building a Django and Gunicorn Application with Docker on Ubuntu 3

The logging.config 函式庫透過 dictConfig 函式接收新日誌配置的字典,以覆寫 Django 的預設日誌記錄行為。

捲動到檔案底部並新增以下日誌配置程式碼片段:

LOGGING_CONFIG 被設定為 None 以停用/清除 Django 定義的預設日誌設定。 LOGLEVEL 是由 DJANGO_LOGLEVEL 環境變數設定。然而,如果它不存在,我們希望將其設定為 ‘ info’.

我們在頂部導入的 logging.config 模組提供了一個函數 dictConfig,用於設定新的設定字典。該字典使用 formatters 鍵來定義文字格式。輸出則是透過 handlers 鍵來設定,最後, loggers 鍵定義了哪些訊息應該傳送到哪個處理器。

一旦您定義了這些設定,Docker 將透過 docker logs 指令。同樣地,在我們即將針對 Kubernetes 進行的另一個教學中,您可以使用 kubectl logs 指令。現在讓我們在下一步中開始容器化流程。

步驟 7:定義應用程式 Dockerfile

在此步驟中,我們將定義用來啟動容器映像檔的設定,該映像檔將執行由 Gunicorn WSGI 伺服器提供服務的 Django 應用程式。我們將定義用於建置容器映像檔的執行階段環境、安裝應用程式及其依賴項,並進行一些最終設定。

  • Django 應用程式的父映像檔

在處理容器化部署時,決定作為容器基礎的基礎映像檔是您要做的第一個決定。當然,您可以選擇從 SCRATCH(即空檔案系統)建置容器映像檔,或者基於現有的容器映像檔。由於我們不想重新發明輪子,我們將從基礎映像檔建置我們的映像檔。有許多開源容器映像檔可從 Docker 的官方容器映像檔存放庫 取得。除非您是從頭開始建置映像檔,否則強烈建議您使用 Docker 官方 Hub 的映像檔。這是因為 Docker 會驗證映像檔是否遵循最佳實踐,並確保定期更新和安全性修補程式到位。

由於 Django 是一個 Python 框架,我們將利用具有標準 Python 環境的映像檔,該環境已安裝了我們所需的工具和函式庫。從官方的 Docker Hub 上的 Python 映像檔 頁面中,您可以找到適用於各種 Python 版本的 Python 基礎映像檔。

從我們各種 基於 Docker 的教學 中,您會注意到我們使用基於 Alpine Linux 的映像檔。Alpine Linux 為執行容器化應用程式提供了一個強大但精簡的作業系統環境。雖然它的檔案系統很小,但它是可擴充的,並配備了完整的套件管理系統,且有可能新增功能。

在 Docker Hub 上選擇基礎映像檔時,您可能會注意到每個映像檔有多個可用的標籤。為了 Python,我們有 3-alpine,它指向最新 Alpine 版本的最新 Python 3 版本映像檔。這意味著,如果您的專案適用於較舊的映像檔版本,當 Docker 映像檔的維護者進行更新時,它可能會損壞。為了避免未來出現此類情況,始終建議為您要使用的映像檔選擇最特定的標籤。

在本教學中,我們將使用 3.8.12-alpine3.15 映像檔作為我們 Django 應用程式的基礎映像檔。此特定標籤將在 Dockerfile 中使用 FROM 指令指定。Dockerfile 將位於主專案目錄中: django_project.

首先,導航出 Django-polls 目錄,回到 django_project 目錄:

進入該目錄後,使用您最喜愛的編輯器開啟一個名為 Dockerfile :

接下來,貼上以下行以設定映像檔的基礎:

這個 FROM  關鍵字定義了自訂 Docker 映像檔的起點。定義好之後,我們可以繼續新增指令來設定應用程式。這些指令將安裝必要的依賴項目、複製應用程式檔案並設定執行階段環境。

在 Dockerfile 中新增以下程式碼片段:

在此程式碼片段中,我們指示 Docker 複製 requirements.txt  檔案至 /app/requirements.txt,以確保應用程式的依賴項目在映像檔的檔案系統中可用。這些需求包括執行應用程式所需的所有 Python 套件。先複製依賴項目是為了讓 Docker 能夠快取映像檔層。這是因為 Docker 會快取 Dockerfile 中的每個步驟。映像檔的首次建置通常需要較長時間。Docker 會下載依賴項目,然後將其快取。如果 requirements.txt 檔案沒有變更,Docker 將從快取中建置,從而使後續的建置速度更快。

下一步包含 RUN 指令,該指令執行一系列 Linux 指令,並使用 Linux 的 && 運算子連結。這些指令執行以下操作:

  • 使用 Alpine 的 apk 套件管理工具來安裝 PostgreSQL 開發檔案和基本的建置依賴項目。

  • 建立 Python 虛擬環境。

  • 安裝定義在 requirements.txt 檔案中的 Python 依賴項目,使用 pip.

  • 透過分析已安裝 Python 套件的需求來編譯必要的執行階段套件。

  • 移除任何不再需要的建置依賴項目。

RUN 步驟中連結指令的原因是為了減少映像檔層。每當 Docker 遇到 ADD, COPYRUN Dockerfile 中的指令。在適用時壓縮命令將能最大限度地減少建立的映像檔層數。

新增到映像檔層中的項目無法在後續層中刪除。您必須在進入下一個指令之前宣告刪除不需要項目的指令。這對於減小映像檔大小是必要的。您應該會注意到我們添加了 apk del 命令在 的末尾RUN 命令。這樣做是為了在我們使用建置依賴項建置應用程式的套件後將其刪除。

接下來,我們有另一個 ADD 指令,我們用它來將應用程式程式碼複製到 /app 目錄。然後,我們將使用 WORKDIR 指令將映像檔的工作目錄設置為 /app 目錄,該目錄現在包含應用程式的程式碼。

接下來,我們有 ENV 指令,我們用它來設置兩個環境變數,映像檔將使執行中的容器可以使用這些變數。首先,我們將 VIRTUAL_ENV 變數設置為 /env。其次,我們設置 PATH 變數以包含 /env/bin 目錄。在這兩行中,我們正在載入 /env/bin/activate 腳本,這是在 Linux 環境中啟用虛擬環境的方式。您可以閱讀更多關於在其他作業系統上使用 其他作業系統上的 Python 虛擬環境 的資訊。最後一個指令是 EXPOSE 命令,它設置了連接埠 8000,容器將在執行時監聽該連接埠。

到目前為止,除了啟動容器時將執行的預設命令之外,您的 Dockerfile 幾乎已經完成了。讓我們在下一節中定義它。

  • 理解預設的 Docker 映像檔命令

啟動 Docker 容器時,您可以提供要執行的命令。但是,如果您不提供命令,Docker 映像檔的預設命令將決定容器啟動時會發生什麼。我們單獨或結合使用 ENTRYPOINTCMD 指令,在 Dockerfile 中定義預設命令。

如果您選擇同時定義 ENTRYPOINTCMD,在 ENTRYPOINT 指令中,您定義了將由容器執行的可執行檔。在 CMD 指令中,定義可執行命令的預設參數列表。您可以在啟動容器時,在命令列上附加替代參數來覆寫預設參數列表,格式如下:

這種格式可以防止開發人員輕易覆寫 ENTRYPOINT 命令。定義 ENTRYPOINT 命令是為了呼叫一個腳本,該腳本將根據提供的參數列表設定環境並執行不同的操作。

您可以單獨使用 ENTRYPOINT 指令來設定容器的可執行檔。但是,此格式不允許定義預設參數列表。當您使用 執行容器時,可以提供參數。docker run 命令。

如果您選擇僅使用 CMD  ,Docker 會將其解釋為預設命令和參數列表,您可以在執行時覆寫它。您可以在 官方 Dockerfile 參考文件.

讓我們看看如何將您學到的關於預設命令的資訊應用到我們的容器範例中。我們希望預設使用 gunicorn 伺服器。雖然傳遞給 gunicorn 伺服器的參數列表不需要在執行時進行設定,但我們希望能夠靈活地執行其他命令,以用於偵錯或管理設定(初始化資料庫、收集靜態資源等)等目的。如您所見,使用 最符合我們的利益CMD 來定義預設命令,這將允許我們在必要時覆寫它。

以下是您可以用來定義 CMD 命令的一些語法:

  • CMD ["command", "argument 1", "argument 2", . . . ,"argument n"]exec 格式(推薦格式)接受一個命令和一個參數列表。它直接執行命令,不進行 shell 處理。
  • CMD command "argument 1" "argument 2" . . . "argument n": shell 格式定義了一個命令和參數列表。它將命令列表傳遞給 shell 進行處理。如果您想在命令中替換環境變數,這可能會很有用,但這並非完全可預測。
  • CMD ["argument 1", "argument 2", . . . ,"argument n"]: 參數列表格式,它僅定義預設參數列表,並與 ENTRYPOINT 指令。

我們將使用 exec 格式來定義我們在 Dockerfile 中的最終指令。在您的 Dockerfile:

您現在可以儲存並關閉 Dockerfile.

當您使用此映像檔啟動容器時,它們將執行 gunicorn 並綁定到 localhost 連接埠 8000,其中包含 3 個 worker,並呼叫位於 application 函式,該函式位於 wsgi.py 檔案中,該檔案位於 mysite 目錄。您可以選擇提供不同的命令,以在執行階段覆寫預設命令,並執行其他程序來代替 gunicorn。您可能想了解更多關於 Gunicorn worker.

您的 Dockerfile 現在已準備就緒,您可以使用 docker build 來建置應用程式映像檔。您可以使用 docker run 在您的本機開發機器上啟動容器。

  • 建置 Docker 映像檔

這個 docker build 命令預設會在目前目錄中尋找 Dockerfile 以尋找其建置指令。它還會將建置「內容」(context)傳送到 Docker 精靈程序(daemon)。一個 建置內容 是一組在建置過程中應該可用的檔案。預設情況下,您執行 docker build 命令的目前目錄會被設定為建置內容。

在包含 Dockerfile 的相同目錄中,執行命令 docker build。使用 -t 旗標提供映像檔和標籤,並使用命令末尾的 ( .) 點號將目前目錄設定為建置內容:

在此命令中,我們將映像檔命名為 django-polls,標籤命名為 v1。請注意命令末尾的點號,我們用它來表示將目前目錄作為建置內容。

docker build 完成時,您應該會看到類似於以下輸出的內容:

Building a Django and Gunicorn Application with Docker on Ubuntu 4

您的 Docker 映像檔現在已準備就緒。如果我們沒有將某些設定移至外部環境變數中,您就可以輕鬆地使用 docker run 命令來執行您的容器。然而,由於我們尚未設定在 settings.py 檔案中設定的外部環境變數,因此執行將會失敗。讓我們在下一步中完成此設定。

步驟 8:設定執行階段環境並測試應用程式

我們即將結束本教學。在此步驟中,我們將在 中設定環境變數env 檔案。有了 env 檔案中的變數後,我們就可以建立資料庫綱要、產生靜態檔案並將其上傳到外部物件儲存服務,最後測試應用程式。

Docker 提供了幾種方法,您可以用來 提供環境變數 給容器。在我們的案例中,我們希望透過檔案提供環境變數列表。因此,我們將使用 --env-file 方法。

使用您偏好的編輯器,在 中建立一個名為 env 的檔案,該檔案位於 django_project 目錄中:

貼上以下變數列表:

清單中的變數是您在先前步驟中定義的變數:

  • DJANGO_SECRET_KEY:產生一個獨特且不可預測的值,如這篇中所述 Django 文件。您可以使用此指令來產生隨機字串並將其設定給該變數:

  • DEBUG:我們已將此值設定為 True,但對於生產環境部署,請記得將其設定為 False(將其留空)。

  • DJANGO_LOGLEVEL:我們已將此設定為 info,您可以隨意將其調整為您所需的級別。

  • DJANGO_ALLOWED_HOSTS:將此值設定為執行 Docker 容器的 Ubuntu 伺服器的 IP 位址。或者,將其設定為 *,如果在開發模式下,萬用字元將比對所有主機。

  • DB_DATABASE:如果您使用了不同的資料庫名稱,請在此處進行相應的設定。

  • DB_USERNAME:將此設定為您為資料庫選擇的使用者名稱。

  • DB_PASSWORD:將此設定為您為資料庫選擇的密碼。

  • DB_HOST:將此設定為執行您資料庫執行個體的主機,如您在步驟一.

  • DB_PORT:將此設定為您資料庫的連接埠。

  • STATIC_MINIO_BUCKET_NAME:將此設定為您在 MinIO 雲端儲存帳戶中建立的儲存貯體名稱。

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

環境設定現已就緒。我們需要執行容器並傳入引數以覆寫預設的 CMD 指令,並使用 manage.py makemigrationsmanage.py migrate 指令來建立資料庫綱要。

以下是指令:

在此指令中,我們正在執行 django-polls:v1 容器映像檔,並使用 env-file 旗標來傳入環境變數檔案。我們也使用 sh -c "python manage.py makemigrations && python manage.py migrate" 來覆寫預設的 CMD 指令。當執行此指令啟動容器時,它將建立應用程式程式碼中定義的資料庫綱要。

如果成功,您應該會看到類似於下方的輸出:

Building a Django and Gunicorn Application with Docker on Ubuntu 4

輸出結果表示資料庫綱要已成功建立。

下一步是為 Django 應用程式建立管理員使用者。我們將啟動容器並使用以下指令在其中啟動互動式 shell:

該指令會啟動容器並顯示 shell 提示字元,您可以使用它與 Python shell 進行互動。讓我們建立一個使用者:

按照提示提供使用者名稱、電子郵件地址、密碼、重新輸入密碼,然後按下 Enter 鍵以建立使用者。按下 CTRL+D.

鍵來終止容器。接下來,我們需要再次執行容器,使用 collectstatic Django 指令覆寫預設指令,以產生應用程式的靜態檔案並將其上傳到您的 MinIO 雲端儲存服務:

完成後,您應該會看到類似下方的輸出,表示您的容器已成功連線到 MinIO 儲存服務並上傳了靜態檔案:

static files

我們的儲存貯體現在看起來像這樣,其中包含 Django 建立的目錄:

Building a Django and Gunicorn Application with Docker on Ubuntu 5

最後,我們現在可以使用以下命令執行應用程式:

以下是輸出結果:

output

當您執行上述命令時,它會執行映像檔中的預設 CMD 命令並公開連接埠 8000 (如定義所示)。現在,Ubuntu 上的連接埠 80 被對應到 8000 連接埠,位於 django-polls:v1 容器。

我們現在可以在瀏覽器中測試應用程式。在瀏覽器中前往您伺服器的公用 IP 位址: http://your_server_public_ip.

預期會看到 404 Page Not Found(找不到網頁)錯誤,因為根據 Django Tutorial,我們沒有為 / 路徑定義路由:

page not found

我們已將 DEBUG 變數設定為 True,這就是為什麼我們會看到這個包含許多關鍵資訊的錯誤頁面。讓我們取消設定 DEBUG 變數。首先,您需要使用 CTRL+C 停止執行中的容器。然後,開啟 env 檔案:

接下來,找到 DEBUG 變數並取消設定,或將其留空。我們將其留空,因為 getenv 函式會將 False 解釋為字串,從而返回 true:

儲存檔案並使用以下命令再次執行容器:

如果您在瀏覽器中造訪 http://your_server_public_ip,您應該會看到預設的 404 頁面:

not found

您已經了解如何使用環境變數來操作 Django 應用程式的執行階段行為,而無需修改原始碼。

導覽至 http://your_server_public_ip/polls 以查看 Polls(投票)首頁:

Building a Django and Gunicorn Application with Docker on Ubuntu 6

由於我們剛剛部署了應用程式,因此目前沒有任何投票。

導覽至管理介面: http://your_server_public_ip/admin 以查看管理員驗證視窗:

polls administration

提供您之前使用 createsuperuser 命令設定的憑證以進行登入。您現在應該會進入管理頁面介面:

site administration

請注意,所有靜態檔案都是由我們設定的外部儲存服務所提供。您可以 按一下滑鼠右鍵 並選擇 View Page Source:

external storage

您可以新增一些問題和選項,並測試應用程式的整體效能:

questions and choices

返回 Polls 首頁 http://your_server_public_ip/polls 並嘗試對問題進行投票:

django framework

在您測試並確認一切運作正常後,即可停止該容器。

結論

您已成功設定 Django 網頁應用程式,使其在容器化環境中良好運作。這包括調整應用程式以配合外部環境變數、設定應用程式使用雲端儲存服務來處理靜態檔案,以及為容器映像檔建立 Dockerfile。您可以在 django-polls-docker 分支上查看我們為了將應用程式 Docker 化所做的變更,該分支位於 django-polls GitHub 存放庫。

從這裡開始,未來的可能性僅受限於您的想像力。您可以設定 Nginx 反向代理,使其介於用戶端與 Gunicorn 伺服器之間。您也可以加入 Certbot 以取得 TLS 憑證來保護您的 Nginx 伺服器。我們建議加入 HTTP 代理以緩衝慢速用戶端,並保護您的 Gunicorn 伺服器免受阻斷服務攻擊。

雖然我們在 Dockerfile 的啟動命令中定義了 3 個 worker,但您可以根據伺服器上的可用資源設定您偏好的數量。您可以在 official Gunicorn design docs 中找到更多資訊。如果您 wish,可以將您建置的 Docker 映像檔推送到 Docker Hub,並嘗試將其部署到多個已安裝 Docker 的環境中。如果您想了解更多資訊,請持續關注我們的 Тutorials blog ,因為我們將會推出後續教學,介紹如何使用 Nginx 和 Let's Encrypt 來保護 Django 應用程式的安全。

最後,這裡有更多能協助您使用 Docker 的資源:

祝您運算愉快!

author

Shreyas Patil

作者 · CloudSigma

Preslav Dobrev 是 CloudSigma 的創意設計師,專注於透過傳統與創新行銷渠道建立一致的企業形象。他擅長將藝術願景與策略行銷相融合,創造具有影響力的品牌敘事。

留言

目前尚無留言。成為第一個留言的人吧。