Python: 進階用法

深入了解 Python 部署

👋 歡迎來到 Stackhero 文件!

Stackhero 提供現成的 Python 雲端 解決方案,帶來多種好處,包括:

  • 只需一個簡單的 git push,即可在幾秒鐘內 部署您的應用程式。
  • 使用您自己的域名,並享受 HTTPS 證書的自動配置以增強安全性。
  • 享受自動備份一鍵更新,以及簡單、透明且可預測的定價,讓您高枕無憂。
  • 得益於專用的私人 VM,獲得最佳的性能和強大的安全性

節省時間簡化您的生活:只需 5 分鐘 即可嘗試 Stackhero 的 Python 雲端託管 解決方案!

到目前為止,我們使用 git push stackhero main 命令將 main 分支部署到生產環境。

如果您需要部署其他分支,可以使用以下命令,其中 <BRANCH> 是您想部署的分支名稱:

git push stackhero <BRANCH>:main

例如,如果您想部署 production 分支,只需執行:

git push stackhero production:main

您可以選擇部署標籤而不是分支。要部署特定標籤,請在以下命令中將 <TAG> 替換為您想要的標籤:

git push stackhero '<TAG>^{}:main'

例如,要部署標籤 v1.0.0,您將執行:

git push stackhero 'v1.0.0^{}:main'

^{} 語法確保您推送的是標籤的提交而不是標籤引用本身。

除了部署分支或標籤,您還可以使用其哈希值部署特定提交。將 <COMMIT_HASH> 替換為您想部署的提交哈希:

git push -f stackhero <COMMIT_HASH>:main

例如,要部署哈希為 abcde 的提交,請執行:

git push -f stackhero abcde:main

如果最近的部署引入了問題,您可以通過部署早期的提交來回滾。首先,通過執行以下命令識別提交哈希:

git log

此命令顯示每個提交的日期、哈希和描述。

例如,輸出可能如下所示:

git log

commit cccc8b3ebdccb9abc1926ef49ee589dae5c5fe06 (HEAD -> main, stackhero/main)
Author: Developer
Date:   Fri Apr 28 09:36:18 +0000

    Break the code

commit bbbb622301772072c3d82f3cc0d91e29e6e84901
Author: Developer
Date:   Wed Apr 26 12:49:28 +0000

    Update the code

commit aaaa1d8b06535b413e0df8298ccf52339dfef3ff
Author: Developer
Date:   Wed Apr 26 12:44:50 +0000

    Improve the code

如果當前生產部署是提交 "Break the code"(哈希以 cccc 開頭),而您希望回滾到先前的提交 "Update the code"(哈希以 bbbb 開頭),請執行:

git push -f stackhero bbbb622301772072c3d82f3cc0d91e29e6e84901:main

為了避免部署有缺陷的代碼並提高生產穩定性,強烈建議設置一個 "staging" 環境。

位於開發和生產之間,staging 環境提供了接近生產設置的複製品。它幫助您在實時部署前徹底測試代碼。

使用 staging 增加了您對代碼功能和性能的信心,從而實現更穩定的生產部署。

這種類型的環境將在文檔中稍後討論。

當與開發和生產環境一起使用時,staging 環境是一種最佳實踐。它複製生產環境,以便您可以在上線前測試更新和更改,從而降低生產中的問題風險。

staging 環境必須緊密反映生產環境。

然而,它應使用生產數據庫或連接服務的克隆版本,而不是實時生產數據庫。

如果您的 Python 服務依賴於數據庫或其他服務,請在新的 <Project> - Staging 堆疊中重新創建它們。

按照以下步驟使用 Stackhero 設置 staging 環境:

  1. 在 Stackhero 儀表板上,將現有堆疊從 <Project> 重命名為 <Project> - Production。例如,如果您的項目名為 Chat Bot,則堆疊變為 Chat Bot - Production
  2. 創建一個名為 <Project> - Staging 的新堆疊。對於 Chat Bot 項目,堆疊變為 Chat Bot - Staging
  3. 在 staging 堆疊中啟動 Python 服務。
  4. 獲取 git remote 命令並按照 部署到 staging 環境 文檔中的說明進行操作。

此配置確保您擁有一個功能齊全的 staging 環境,以便在生產部署前測試更新。

強烈建議維護獨立的 staging 和生產環境。要管理多個環境,首先重命名當前的遠程存儲庫。例如,將遠程 stackhero 重命名為 stackhero-production

git remote rename stackhero stackhero-production

接下來,為您的 staging 環境創建一個新的 Python 服務。獲取 git remote add 命令並將 <XXXXXX> 替換為您的服務域名:

  • 原始命令:

    git remote add stackhero ssh://stackhero@<XXXXXX>.stackhero-network.com:222/project.git
    
  • 修改後的命令:

    git remote add stackhero-staging ssh://stackhero@<XXXXXX>.stackhero-network.com:222/project.git
    

然後,您可以使用以下命令部署到任一環境:

  • 部署到 staging:

    git push stackhero-staging main
    
  • 部署到生產:

    git push stackhero-production main
    

為了改善部署過程,我們建議使用 改進版 Makefile

使用這個改進的 Makefile,部署到生產或 staging 變得像運行 make deploy-productionmake deploy-staging 一樣簡單。

以下是一個支持多個規則的改進版 Makefile

  • make dev(或簡單地 make):以開發模式啟動應用程序。
  • make deploy:將應用程序部署到名為 stackhero 的遠程。這在您只有一個 Stackhero 實例時效果很好。
  • make deploy-production:將應用程序部署到名為 stackhero-production 的遠程。
  • make deploy-staging:將應用程序部署到名為 stackhero-staging 的遠程。

Makefile 設計用於處理代碼未更改的情況,避免 "Everything up-to-date" 錯誤。

將以下內容複製並粘貼為您的新 Makefile

# 默認執行的規則,當不帶參數調用 "make" 時執行
.DEFAULT_GOAL := dev


# Stackhero for Python 將在您的實例上執行 "run" 規則。
# 這是在您的生產和 staging 環境中運行的命令。
run:
  ENV=production gunicorn app:app \
    --error-logfile - \
    -b 0.0.0.0:8080


# 在開發環境中使用的命令
dev:
  python app.py


# "deploy" 規則用於部署到 "stackhero" 實例。
# 適合您只有一個實例的情況。
deploy:
  @$(MAKE) -s deploy-script DEPLOY_REMOTE=stackhero DEPLOY_BRANCH=main


# "deploy-*" 規則部署到名為 "stackhero-*" 的實例。
# 例如,運行 "make deploy-production" 部署到 "stackhero-production",
# 或 "make deploy-staging" 部署到 "stackhero-staging"。
deploy-%:
  @$(MAKE) -s deploy-script DEPLOY_REMOTE=stackhero-$* DEPLOY_BRANCH=main


# 內部部署規則。請勿修改。
deploy-script:
  @echo "Deploying branch \"${DEPLOY_BRANCH}\" to \"${DEPLOY_REMOTE}\"..."
  @echo

  @if [ -n "$$(git status --porcelain)" ]; then \
    echo "無法部署,因為有未提交的更改:"; \
    echo "\e[0m"; \
    git status -s; \
    echo ""; \
    echo "\e[0;31m"; \
    echo "您可以使用此命令提交更改:"; \
    echo "git add -A . && git commit -m \"Your message\""; \
    echo "\e[0m"; \
    exit 1; \
  fi

  @git push --dry-run ${DEPLOY_REMOTE} ${DEPLOY_BRANCH} 2>&1 | grep -q -F "Everything up-to-date"; \
  EXIT_CODE=$$?; \
  if [ $$EXIT_CODE -eq 0 ]; then \
    echo -n "沒有新內容可部署... 強制部署(這將創建一個新提交)? (y/N) "; \
    read answer && \
    case $$answer in \
      y|Y|yes|YES) \
      git commit --allow-empty -m "Force update for deploy purpose to \"${DEPLOY_REMOTE}\"" ; \
      ;; \
    *) \
      echo "沒有可部署的內容!"; \
      exit 1; \
      ;; \
    esac \
  fi

  git push ${DEPLOY_REMOTE} ${DEPLOY_BRANCH}

在某些時候,您需要存儲機密信息,如數據庫或第三方服務的令牌和密碼。重要的是要安全地存儲這些信息。避免將它們直接嵌入到您的存儲庫或代碼中,因為這會造成重大安全風險。

使用環境變量有兩個主要好處:

  1. 您的機密信息從未存儲在您的 Git 存儲庫中,從而降低未經授權訪問的風險。
  2. 您可以為不同的環境使用不同的憑證,例如在生產中使用生產數據庫,在開發中使用開發數據庫。

在開發環境中,在項目根目錄創建 .env 文件。此文件應從 Git 中排除,以確保它從未被提交。

要自動讀取 .env 文件,您可以使用 python-dotenv 模塊:

pip install python-dotenv
pip freeze > requirements.txt

然後,在項目根目錄創建 .env 文件並添加您的變量:

ENV="development"
DATABASE_PASSWORD="secretPassword"
THIRD_API_PRIVATE_KEY="secretKey"
# ...

最後,確保 .env 文件被排除在 Git 之外,將其添加到 .gitignore

echo ".env" >> .gitignore

.env 文件對於 staging 和生產環境來說不夠安全。相反,Stackhero 允許您將環境變量安全地存儲在您的 Python 服務配置中。

您可以在 Stackhero 儀表板中選擇您的 Python 服務,然後點擊 "Configure" 按鈕來設置這些變量。

Stackhero 上的 Python 環境變量Stackhero 上的 Python 環境變量

在 Python 中訪問環境變量很簡單。只需使用 os.environ.get(),如下所示:

import os

print(os.environ.get('ENV'))

例如,使用環境變量連接到 Redis 服務器可以這樣做:

import os
import redis

r = redis.from_url(os.environ.get("REDIS_URL"))

在開發環境中,在 .env 文件中設置 REDIS_URL 如下:

REDIS_URL="redis://localhost:6379"

對於生產和 staging,請在 Stackhero 儀表板的 Python 服務配置中定義 REDIS_URL

REDIS_URL="rediss://default:<yourPassword>@<XXXXXX>.stackhero-network.com:6380"

使用 requirements.txt 文件管理 Python 套件是一種最佳實踐。此文件列出了運行您的代碼所需的所有套件及其版本,以確保可靠運行。

保持此文件更新可確保:

  1. 安裝所有必需的套件。
  2. 僅使用兼容的套件版本。

在部署到您的 Stackhero 實例時,requirements.txt 中指定的套件會自動安裝。

在安裝新套件後,運行以下命令生成或更新 requirements.txt

pip freeze > requirements.txt

大多數 Python 應用程序使用 HTTP 端口 80(HTTP)和 443(HTTPS)。

如果您的應用程序需要開啟其他端口或使用其他協議(TCP 或 UDP),您可以在 Stackhero 儀表板上的 Python 服務中調整 "Ports Redirections" 設置。

對於每個額外的端口,指定入口端口(公共面向)、目標端口(由您的 Python 應用程序使用)和協議(TCP 或 UDP)。

Stackhero 儀表板上的端口重定向Stackhero 儀表板上的端口重定向

對於存儲用戶照片或文檔等文件,通常最好使用對象存儲解決方案。

對象存儲允許您在多個服務或實例之間共享文件,並將存儲與代碼分開,遵循最佳實踐。

我們推薦 MinIO,這是一個快速且強大的解決方案,兼容 Amazon S3 協議。

如果您更喜歡本地文件存儲,可以使用位於 /persistent/storage/ 的 Python 實例提供的持久存儲。然而,在大多數情況下不建議這種方法。

警告:切勿將數據存儲在 /persistent/storage/ 文件夾之外!

將數據存儲在此文件夾之外可能會導致數據丟失,當您的實例重新啟動、更新或推送新代碼時。

在 macOS 上,每次推送代碼時輸入 SSH 私鑰密碼可能會很麻煩。雖然安全性至關重要,但您可以使用 Apple 的鑰匙串安全地保存密碼,而不是從密鑰中刪除它。

要存儲名為 id_ed25519 的密鑰的密碼,請執行:

ssh-add --apple-use-keychain ~/.ssh/id_ed25519

之後,您將不會被提示輸入密鑰密碼,節省時間和精力。

如果您使用的是 RSA 密鑰,請在命令中將 id_ed25519 替換為 id_rsa

ssh-add --apple-use-keychain ~/.ssh/id_rsa