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 "正在将分支 \"${DEPLOY_BRANCH}\" 部署到 \"${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 \"您的消息\""; \
    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 添加到 .gitignore 中,确保它被 Git 排除:

echo ".env" >> .gitignore

.env 文件对于 staging 和生产环境来说不够安全。相反,Stackhero 允许您将环境变量直接安全地存储在您的 Python 服务配置中。

您可以通过选择您的 Python 服务,然后点击“配置”按钮,在 Stackhero 仪表板中设置这些变量。

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 服务中调整“端口重定向”设置。

对于每个额外的端口,指定入口端口(面向公众)、目标端口(由您的 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