在 Cloud Run 中執行 Django

1. 簡介

894762ebb681671c.png

Cloud Run 是代管運算平台,能夠讓您執行可透過 HTTP 要求叫用的無狀態容器。Cloud Run 採用無伺服器技術,可為您省去所有基礎架構管理工作,讓您專心處理最重要的事物,也就是建構出色的應用程式。

另外,這項服務也會與 Google Cloud 生態系統的許多其他部分原生通訊,包括適用於代管資料庫的 Cloud SQL、適用於統一物件儲存空間的 Cloud Storage,以及用於管理密鑰的 Secret Manager

Django 是高階的 Python 網路架構。

在這個教學課程中,您將使用這些元件來部署小型的 Django 專案。

注意:本程式碼研究室上次透過 Django 5.0 驗證。除非日後更新有任何破壞性變更,否則本程式碼研究室應可持續運作。查看未來的 Django 版本資訊。

課程內容

  • 如何使用 Cloud Shell
  • 如何建立 Cloud SQL 資料庫
  • 如何建立 Cloud Storage 值區
  • 如何建立 Secret Manager 密鑰
  • 如何使用不同 Google Cloud 服務的 Secret
  • 如何將 Google Cloud 元件連結至 Cloud Run 服務
  • 如何使用 Container Registry 儲存建構的容器
  • 如何部署至 Cloud Run
  • 如何在 Cloud Build 中執行資料庫結構定義遷移作業

2. 設定和需求

自修環境設定

  1. 登入 Google Cloud 控制台,建立新專案或重複使用現有專案。如果您還沒有 Gmail 或 Google Workspace 帳戶,請先建立帳戶

fbef9caa1602edd0.png

a99b7ace416376c4.png

5e3ff691252acf41.png

  • 「專案名稱」是這項專案參與者的顯示名稱。這是 Google API 未使用的字元字串。你隨時可以更新。
  • 所有 Google Cloud 專案的專案 ID 均不得重複,而且設定後即無法變更。Cloud 控制台會自動產生一個不重複的字串。但通常是在乎它何在在大部分的程式碼研究室中,您必須參照專案 ID (通常為 PROJECT_ID)。如果您對產生的 ID 不滿意,可以隨機產生一個 ID。或者,您也可以自行嘗試,看看是否支援。在這個步驟後,這個名稱即無法變更,而且在專案期間內仍會保持有效。
  • 資訊中的第三個值是專案編號,部分 API 會使用這個編號。如要進一步瞭解這三個值,請參閱說明文件
  1. 接下來,您需要在 Cloud 控制台中啟用計費功能,才能使用 Cloud 資源/API。執行本程式碼研究室不會產生任何費用 (如果有的話)。如要關閉資源,以免產生本教學課程結束後產生的費用,您可以刪除自己建立的資源或刪除專案。新使用者符合 $300 美元免費試用計畫的資格。

Google Cloud Shell

雖然 Google Cloud 可以在筆電上遠端操作,但在本程式碼研究室中,我們會使用 Google Cloud Shell,這是 Cloud 中運作的指令列環境。

啟用 Cloud Shell

  1. 在 Cloud 控制台中,按一下「啟用 Cloud Shell」圖示 853e55310c205094.png

3c1dabeca90e44e5.png

如果您是第一次啟動 Cloud Shell,系統會顯示中繼畫面,說明這項服務的內容。如果系統顯示中繼畫面,請按一下「繼續」

9c92662c6a846a5c.png

佈建並連線至 Cloud Shell 只需幾分鐘的時間。

9f0e51b578fecce5.png

這個虛擬機器已載入所有必要的開發工具。提供永久的 5 GB 主目錄,而且在 Google Cloud 中運作,大幅提高網路效能和驗證能力。在本程式碼研究室中,您的大部分作業都可透過瀏覽器完成。

連線至 Cloud Shell 後,您應會發現自己通過驗證,且專案已設為您的專案 ID。

  1. 在 Cloud Shell 中執行下列指令,確認您已通過驗證:
gcloud auth list

指令輸出

 Credentialed Accounts
ACTIVE  ACCOUNT
*       <my_account>@<my_domain.com>

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. 在 Cloud Shell 中執行下列指令,確認 gcloud 指令知道您的專案:
gcloud config list project

指令輸出

[core]
project = <PROJECT_ID>

如果尚未設定,請使用下列指令進行設定:

gcloud config set project <PROJECT_ID>

指令輸出

Updated property [core/project].

3. 啟用 Cloud API

在 Cloud Shell 中,為要使用的元件啟用 Cloud API:

gcloud services enable \
  run.googleapis.com \
  sql-component.googleapis.com \
  sqladmin.googleapis.com \
  compute.googleapis.com \
  cloudbuild.googleapis.com \
  secretmanager.googleapis.com \
  artifactregistry.googleapis.com

由於這是您第一次透過 gcloud 呼叫 API,系統會要求您使用憑證來發出這項要求。每個 Cloud Shell 工作階段都需要執行一次。

這項作業可能需要幾分鐘才能完成。

完成後,畫面上應該會顯示類似以下的成功訊息:

Operation "operations/acf.cc11852d-40af-47ad-9d59-477a12847c9e" finished successfully.

4. 建立範本專案

您將使用預設的 Django 專案範本做為您的 Django 專案範例。

如要建立這個範本專案,請使用 Cloud Shell 建立名為 django-cloudrun 的新目錄,然後前往該目錄:

mkdir ~/django-cloudrun
cd ~/django-cloudrun

然後,將 Django 安裝到臨時虛擬環境中:

virtualenv venv
source venv/bin/activate
pip install Django

儲存安裝至「requirements.txt」的套件清單

pip freeze > requirements.txt

這份清單應包含 Django 及其依附元件:sqlparseasgiref

接著,建立新的範本專案:

django-admin startproject myproject .

您將取得名為 manage.py 的新檔案,以及名為 myproject 的新資料夾,其中包含許多檔案,包括 settings.py

確認頂層資料夾的內容符合預期:

ls -F
manage.py myproject/ requirements.txt venv/

確認 myproject 資料夾的內容是否符合預期:

ls -F myproject/
__init__.py asgi.py settings.py  urls.py  wsgi.py

您現在可以離開並移除臨時的虛擬環境:

deactivate
rm -rf venv

從這裡開始,在容器中呼叫 Django。

5. 建立後端服務

您現在要建立備份服務,包括專屬服務帳戶、Artifact Registry、Cloud SQL 資料庫、Cloud Storage 值區,以及一些 Secret Manager 值。

保護部署中所用密碼的值對任何專案的安全性至關重要,並確保沒有人不小心將不合適的密碼放入密碼 (例如,直接在設定檔中或終端機輸入,以便從歷史記錄擷取密碼)。

首先,請為專案 ID 設定兩個基本環境變數:

PROJECT_ID=$(gcloud config get-value core/project)

一個用於區域:

REGION=us-central1

建立服務帳戶

如要限制服務只能存取 Google Cloud 的其他部分,請建立專屬的服務帳戶:

gcloud iam service-accounts create cloudrun-serviceaccount

在本程式碼研究室的後續章節中,我們會以電子郵件地址參照這個帳戶。在環境變數中設定該值:

SERVICE_ACCOUNT=$(gcloud iam service-accounts list \
    --filter cloudrun-serviceaccount --format "value(email)")

建立 Artifact Registry

如要儲存建構的容器映像檔,請在所選區域中建立 Container Registry:

gcloud artifacts repositories create containers --repository-format docker --location $REGION

在本程式碼研究室的後續章節中,我們會依名稱參照這個登錄檔:

ARTIFACT_REGISTRY=${REGION}-docker.pkg.dev/${PROJECT_ID}/containers

建立資料庫

建立 Cloud SQL 執行個體:

gcloud sql instances create myinstance --project $PROJECT_ID \
  --database-version POSTGRES_14 --tier db-f1-micro --region $REGION

這項作業會在幾分鐘內完成。

在該執行個體中建立資料庫:

gcloud sql databases create mydatabase --instance myinstance

在該例項中,建立使用者:

DJPASS="$(cat /dev/urandom | LC_ALL=C tr -dc 'a-zA-Z0-9' | fold -w 30 | head -n 1)"
gcloud sql users create djuser --instance myinstance --password $DJPASS

授予服務帳戶連線至執行個體的權限:

gcloud projects add-iam-policy-binding $PROJECT_ID \
    --member serviceAccount:${SERVICE_ACCOUNT} \
    --role roles/cloudsql.client

建立儲存空間值區

建立 Cloud Storage 值區 (註記名稱在全域範圍內不得重複):

GS_BUCKET_NAME=${PROJECT_ID}-media
gcloud storage buckets create gs://${GS_BUCKET_NAME} --location ${REGION} 

授予服務帳戶管理值區的權限:

gcloud storage buckets add-iam-policy-binding gs://${GS_BUCKET_NAME} \
    --member serviceAccount:${SERVICE_ACCOUNT} \
    --role roles/storage.admin

將設定儲存為 Secret

設定備份服務後,您現在會將這些值儲存在使用 Secret Manager 保護的檔案中。

Secret Manager 能以二進位 blob 或文字字串的形式,儲存、管理及存取密鑰。很適合用來在執行階段儲存應用程式所需的設定資訊,例如資料庫密碼、API 金鑰或 TLS 憑證。

首先,建立具有資料庫連線字串值、媒體值區、Django 密鑰 (用於加密工作階段和權杖的加密) 值的檔案,並啟用偵錯功能:

echo DATABASE_URL=\"postgres://djuser:${DJPASS}@//cloudsql/${PROJECT_ID}:${REGION}:myinstance/mydatabase\" > .env

echo GS_BUCKET_NAME=\"${GS_BUCKET_NAME}\" >> .env

echo SECRET_KEY=\"$(cat /dev/urandom | LC_ALL=C tr -dc 'a-zA-Z0-9' | fold -w 50 | head -n 1)\" >> .env

echo DEBUG=True >> .env

接著,建立名為 application_settings 的密鑰,並使用該檔案做為密鑰:

gcloud secrets create application_settings --data-file .env

允許服務帳戶存取這組密鑰:

gcloud secrets add-iam-policy-binding application_settings \
  --member serviceAccount:${SERVICE_ACCOUNT} --role roles/secretmanager.secretAccessor

列出密鑰,確認已建立密鑰:

gcloud secrets versions list application_settings

確認 Secret 已建立後,移除本機檔案:

rm .env

6. 設定應用程式

有鑑於您剛建立的後端服務,您必須依據自己的需求變更範本專案。

包括導入 django-environ,以使用環境變數做為配置設定,您會在設定中看到您定義為密鑰的值。如要實作這個效果,您需要擴充範本設定。此外,您也需要新增其他 Python 依附元件。

調整設定

移動 settings.py 檔案,重新命名為 basesettings.py:

mv myproject/settings.py myproject/basesettings.py

使用 Cloud Shell 網頁編輯器,使用下列程式碼建立新的 settings.py 檔案:

touch myproject/settings.py
cloudshell edit myproject/settings.py

myproject/settings.py

import io
import os
from urllib.parse import urlparse

import environ

# Import the original settings from each template
from .basesettings import *

# Load the settings from the environment variable
env = environ.Env()
env.read_env(io.StringIO(os.environ.get("APPLICATION_SETTINGS", None)))

# Setting this value from django-environ
SECRET_KEY = env("SECRET_KEY")

# Ensure myproject is added to the installed applications
if "myproject" not in INSTALLED_APPS:
    INSTALLED_APPS.append("myproject")

# If defined, add service URL to Django security settings
CLOUDRUN_SERVICE_URL = env("CLOUDRUN_SERVICE_URL", default=None)
if CLOUDRUN_SERVICE_URL:
    ALLOWED_HOSTS = [urlparse(CLOUDRUN_SERVICE_URL).netloc]
    CSRF_TRUSTED_ORIGINS = [CLOUDRUN_SERVICE_URL]
else:
    ALLOWED_HOSTS = ["*"]

# Default false. True allows default landing pages to be visible
DEBUG = env("DEBUG", default=False)

# Set this value from django-environ
DATABASES = {"default": env.db()}

# Change database settings if using the Cloud SQL Auth Proxy
if os.getenv("USE_CLOUD_SQL_AUTH_PROXY", None):
    DATABASES["default"]["HOST"] = "127.0.0.1"
    DATABASES["default"]["PORT"] = 5432

# Define static storage via django-storages[google]
GS_BUCKET_NAME = env("GS_BUCKET_NAME")
STATICFILES_DIRS = []
DEFAULT_FILE_STORAGE = "storages.backends.gcloud.GoogleCloudStorage"
STATICFILES_STORAGE = "storages.backends.gcloud.GoogleCloudStorage"
GS_DEFAULT_ACL = "publicRead"

請花點時間閱讀關於每項設定新增的解說。

請注意,這個檔案可能會顯示程式碼檢查錯誤。這個狀況有可能發生:Cloud Shell 沒有這項專案的規定背景資訊,因此可能會回報無效的匯入項目和未使用的匯入作業。

Python 依附元件

找出 requirements.txt 檔案並附加下列套件:

cloudshell edit requirements.txt

requirements.txt (附加)

gunicorn
psycopg2-binary
django-storages[google]
django-environ

定義應用程式映像檔

只要容器符合 Cloud Run 容器合約,Cloud Run 就會執行。本教學課程選擇省略 Dockerfile,但改用 Cloud Native Buildpacks。Buildpacks 能協助您建構常見語言 (包括 Python) 的容器。

本教學課程選擇自訂 Procfile,用於啟動網頁應用程式。

如要將範本專案容器化,請先在專案頂層 (與 manage.py 相同的目錄中) 建立名為 Procfile 的新檔案,然後複製下列內容:

touch Procfile
cloudshell edit Procfile

Procfile

web: gunicorn --bind 0.0.0.0:$PORT --workers 1 --threads 8 --timeout 0 myproject.wsgi:application

7. 設定、建構及執行遷移步驟

如要在 Cloud SQL 資料庫中建立資料庫結構定義,並使用靜態資產填入 Cloud Storage 值區,您必須執行 migratecollectstatic

這些基本 Django 遷移命令必須在具備資料庫存取權的建構容器映像檔環境中執行。

您還需要執行 createsuperuser,以建立管理員帳戶,登入 Django 管理員。

如要這麼做,請使用 Cloud Run 工作來執行這些工作。Cloud Run 工作可讓您執行已定義結尾的處理程序,相當適合用於管理工作。

定義 Django 超級使用者密碼

如要建立超級使用者,請使用非互動式版本的 createsuperuser 指令。這個指令需要您特別命名的環境變數,以取代提示輸入密碼的提示。

使用隨機產生的密碼建立新密鑰:

echo -n $(cat /dev/urandom | LC_ALL=C tr -dc 'a-zA-Z0-9' | fold -w 30 | head -n 1) | gcloud secrets create django_superuser_password --data-file=-

允許您的服務帳戶存取此密鑰:

gcloud secrets add-iam-policy-binding django_superuser_password \
  --member serviceAccount:${SERVICE_ACCOUNT} \
  --role roles/secretmanager.secretAccessor

更新 Procfile

為了清楚瞭解 Cloud Run 工作,請在 Procfile 中建立捷徑,並將下列進入點附加至 Procfile

migrate: python manage.py migrate && python manage.py collectstatic --noinput --clear
createuser: python manage.py createsuperuser --username admin --email noop@example.com --noinput

您現在應有三個項目:預設網路進入點、用來套用資料庫遷移作業的 migrate 進入點,以及執行 createsuperuser 指令的 createuser 進入點。

建構應用程式映像檔

更新 Procfile 後,建構映像檔:

gcloud builds submit --pack image=${ARTIFACT_REGISTRY}/myimage

建立 Cloud Run 工作

映像檔已存在,您就能使用該映像檔建立 Cloud Run 工作。

這些工作使用先前建構的映像檔,但使用不同的 command 值。這些物件會對應到 Procfile 中的值。

建立遷移工作:

gcloud run jobs create migrate \
  --region $REGION \
  --image ${ARTIFACT_REGISTRY}/myimage \
  --set-cloudsql-instances ${PROJECT_ID}:${REGION}:myinstance \
  --set-secrets APPLICATION_SETTINGS=application_settings:latest \
  --service-account $SERVICE_ACCOUNT \
  --command migrate

為使用者建立作業建立工作:

gcloud run jobs create createuser \
  --region $REGION \
  --image ${ARTIFACT_REGISTRY}/myimage \
  --set-cloudsql-instances ${PROJECT_ID}:${REGION}:myinstance \
  --set-secrets APPLICATION_SETTINGS=application_settings:latest \
  --set-secrets DJANGO_SUPERUSER_PASSWORD=django_superuser_password:latest \
  --service-account $SERVICE_ACCOUNT \
  --command createuser

執行 Cloud Run 工作

設定好工作設定後,請執行遷移作業:

gcloud run jobs execute migrate --region $REGION --wait

確認指令輸出內容顯示執行作業「成功完成」。

稍後更新應用程式時您將執行這個指令。

設定資料庫後,使用工作建立使用者:

gcloud run jobs execute createuser --region $REGION --wait

確認指令輸出內容顯示執行作業「成功完成」。

您不必再次執行這個指令。

8. 部署至 Cloud Run

建立並填入備份服務後,您現在可以建立 Cloud Run 服務來存取這些服務。

使用下列指令,使用先前建構的映像檔將服務部署至 Cloud Run:

gcloud run deploy django-cloudrun \
  --region $REGION \
  --image ${ARTIFACT_REGISTRY}/myimage \
  --set-cloudsql-instances ${PROJECT_ID}:${REGION}:myinstance \
  --set-secrets APPLICATION_SETTINGS=application_settings:latest \
  --service-account $SERVICE_ACCOUNT \
  --allow-unauthenticated

部署成功之後,指令列會顯示服務網址:

Service [django-cloudrun] revision [django-cloudrun-00001-...] has been deployed and is serving 100 percent of traffic.
Service URL: https://django-cloudrun-...-uc.a.run.app

您現在可以在網路瀏覽器中開啟這個網址,造訪您部署的容器:

61586f9354194019.png

9. 存取 Django 管理員

Django 的其中一項主要功能是互動式管理員。

更新 CSRF 設定

Django 包含針對跨網站要求偽造 (CSRF) 的保護措施。每當有表單提交至 Django 網站時 (包括登入 Django 管理員),系統都會檢查「信任來源」設定。如果與要求的來源不相符,Django 會傳回錯誤。

mysite/settings.py 檔案中,如果 CLOUDRUN_SERVICE_URL 環境變數已定義,則 CSRF_TRUSTED_ORIGINSALLOWED_HOSTS 設定會使用該變數。雖然定義 ALLOWED_HOSTS 並非必要,但建議您新增此元素,因為 CSRF_TRUSTED_ORIGINS 原本就會使用這個屬性。

因為您需要服務網址,所以您必須等到首次部署之後,才能新增這項設定。

您必須更新服務,才能新增此環境變數。這可以新增至 application_settings 密鑰,或是直接新增為環境變數。

擷取服務網址:

CLOUDRUN_SERVICE_URL=$(gcloud run services describe django-cloudrun \
  --platform managed \
  --region $REGION  \
  --format "value(status.url)")
echo $CLOUDRUN_SERVICE_URL

在您的 Cloud Run 服務上,將這個值設為環境變數:

gcloud run services update django-cloudrun \
  --region $REGION \
  --update-env-vars CLOUDRUN_SERVICE_URL=$CLOUDRUN_SERVICE_URL

登入 Django 管理員

如要存取 Django 管理員介面,請將 /admin 附加至服務網址。

現在以「admin」這個使用者名稱登入並使用以下指令擷取密碼:

gcloud secrets versions access latest --secret django_superuser_password && echo ""

28d6107689b0d9e.png

402392fbdac25dae.png

10. 開發應用程式

開發應用程式時,您可能會想在本機上進行測試。為此,您必須連線至 Cloud SQL (「正式環境」) 資料庫或本機 (「測試」) 資料庫。

連線至實際工作環境的資料庫

您可以使用 Cloud SQL 驗證 Proxy 連線至 Cloud SQL 執行個體。這個應用程式會從本機電腦連線至資料庫。

安裝 Cloud SQL 驗證 Proxy 後,請按照下列步驟操作:

# Create a virtualenv
virtualenv venv
source venv/bin/activate
pip install -r requirements.txt

# Copy the application settings to your local machine
gcloud secrets versions access latest --secret application_settings > temp_settings

# Run the Cloud SQL Auth Proxy
./cloud-sql-proxy --instances=${PROJECT_ID}:${REGION}:myinstance=tcp:5432

# In a new tab, start the local web server using these new settings
USE_CLOUD_SQL_AUTH_PROXY=true APPLICATION_SETTINGS=$(cat temp_settings) python manage.py runserver

完成作業後,請務必移除 temp_settings 檔案。

連線至本機 SQLite 資料庫

您也可以在開發應用程式時使用本機資料庫。Django 支援 PostgreSQL 和 SQLite 資料庫,而有些 PostgreSQL 沒有 SQLite 所具備的功能,不過在許多情況下,功能都相同。

如要設定 SQLite,您必須更新應用程式設定,指向本機資料庫,然後套用結構定義遷移作業。

如要設定這個方法:

# Create a virtualenv
virtualenv venv
source venv/bin/activate
pip install -r requirements.txt

# Copy the application settings to your local machine
gcloud secrets versions access latest --secret application_settings > temp_settings

# Edit the DATABASE_URL setting to use a local sqlite file. For example:
DATABASE_URL=sqlite:////tmp/my-tmp-sqlite.db

# Set the updated settings as an environment variable
APPLICATION_SETTINGS=$(cat temp_settings) 

# Apply migrations to the local database
python manage.py migrate

# Start the local web server
python manage.py runserver

完成作業後,請務必移除 temp_settings 檔案。

建立遷移作業

變更資料庫模型時,您可能需要執行 python manage.py makemigrations 來產生 Django 的遷移檔案。

設定實際工作環境或測試資料庫連線之後,您可以執行這個指令。或者,您也可以指定空白設定,在沒有資料庫的情況下產生遷移檔案:

SECRET_KEY="" DATABASE_URL="" GS_BUCKET_NAME="" python manage.py makemigrations

正在套用應用程式更新

如要將變更套用至應用程式,您需要:

  • 就能將變更建構到新的映像檔
  • 套用任何資料庫或靜態遷移作業
  • 請更新 Cloud Run 服務,以使用新的映像檔。

如何建構映像檔:

gcloud builds submit --pack image=${ARTIFACT_REGISTRY}/myimage

如有要套用的遷移作業,請執行 Cloud Run 工作:

gcloud run jobs execute migrate --region $REGION --wait

如何使用新映像檔更新服務:

gcloud run services update django-cloudrun \
  --platform managed \
  --region $REGION \
  --image ${ARTIFACT_REGISTRY}/myimage

11. 恭喜!

您已成功將複雜的專案部署至 Cloud Run!

  • Cloud Run 會自動及水平擴充您的容器映像檔,以處理收到的要求,然後在需求減少時縮減規模。您只需要支付處理要求期間使用的 CPU、記憶體和網路費用。
  • Cloud SQL 可讓您佈建自動維護的代管 PostgreSQL 執行個體,並原生整合至許多 Google Cloud 系統中。
  • Cloud Storage 可讓您以順暢的方式在 Django 中存取雲端儲存空間。
  • Secret Manager 可讓您儲存密鑰,並允許 Google Cloud 的特定部分存取密鑰。

清理

如要避免系統向您的 Google Cloud Platform 帳戶收取您在本教學課程中所用資源的相關費用:

  • 在 Cloud 控制台中,前往「管理資源」頁面。
  • 在專案清單中,選取您的專案,然後按一下「Delete」(刪除)
  • 在對話方塊中輸入專案 ID,然後按一下「Shut down」(關閉) 即可刪除專案。

瞭解詳情