Python: 高度な使用法

Pythonデプロイメントをさらに進める

👋 Stackheroのドキュメントへようこそ!

Stackheroは、数多くの利点を提供するPythonクラウドソリューションを提供しています。主な利点は以下の通りです:

  • シンプルなgit pushでアプリケーションを数秒でデプロイ
  • 独自のドメイン名を使用し、HTTPS証明書の自動設定による強化されたセキュリティを享受。
  • 自動バックアップワンクリックアップデート、そしてシンプルで透明性のある予測可能な価格設定で安心を提供。
  • プライベートで専用のVMによる最適なパフォーマンスと強固なセキュリティを実現。

時間を節約し、生活を簡素化: StackheroのPythonクラウドホスティングソリューションを試すのに5分しかかかりません

これまで、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

壊れたコードのデプロイを防ぎ、本番環境の安定性を高めるために、「ステージング」環境を持つことを強くお勧めします。

開発と本番の間に位置するステージング環境は、本番設定のほぼ複製を提供します。これにより、ライブデプロイメントの前にコードを徹底的にテストできます。

ステージングを利用することで、コードの機能性とパフォーマンスに対する信頼が高まり、より堅牢な本番デプロイメントが実現します。

このタイプの環境については、後のドキュメントで説明します。

ステージング環境は、開発および本番環境と共に使用する場合のベストプラクティスです。本番環境を複製することで、ライブにする前に更新や変更をテストし、本番での問題のリスクを減らします。

ステージング環境は、本番環境を密接に反映する必要があります。

ただし、ライブの本番データベースではなく、プロダクションデータベースまたは接続されたサービスのクローンバージョンを使用する必要があります。

Pythonサービスがデータベースや他のサービスに依存している場合、新しい<Project> - Stagingスタックでそれらを再作成します。

Stackheroでステージング環境を設定する手順は次のとおりです。

  1. Stackheroダッシュボードで、既存のスタックを<Project>から<Project> - Productionに名前を変更します。例えば、プロジェクトがChat Botの場合、スタックはChat Bot - Productionになります。
  2. <Project> - Stagingという名前の新しいスタックを作成します。Chat Botプロジェクトの場合、スタックはChat Bot - Stagingになります。
  3. ステージングスタック内でPythonサービスを開始します。
  4. git remoteコマンドを取得し、ステージング環境へのデプロイドキュメントの指示に従います。

この構成により、本番デプロイメント前に更新をテストするための完全に機能するステージング環境が確保されます。

ステージングと本番環境を分けて維持することを強くお勧めします。複数の環境を管理するには、まず現在のリモートリポジトリの名前を変更します。例えば、リモートstackherostackhero-productionに名前を変更します。

git remote rename stackhero stackhero-production

次に、ステージング環境用の新しい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
    

次に、以下のコマンドを使用してどちらの環境にもデプロイできます。

  • ステージングにデプロイ:

    git push stackhero-staging main
    
  • 本番にデプロイ:

    git push stackhero-production main
    

デプロイメントプロセスを改善するために、改良されたMakefileバージョンを利用することをお勧めします。

この改良されたMakefileを使用すると、本番またはステージングへのデプロイがmake deploy-productionまたはmake deploy-stagingを実行するだけで簡単になります。

以下は、複数のルールをサポートする改良されたMakefileです。

  • make dev(または単にmake):開発モードでアプリケーションを開始します。
  • make deploy:リモート名stackheroにアプリケーションをデプロイします。これは、Stackheroインスタンスが1つだけの場合に適しています。
  • make deploy-production:リモート名stackhero-productionにアプリケーションをデプロイします。
  • make deploy-staging:リモート名stackhero-stagingにアプリケーションをデプロイします。

このMakefileは、コードが変更されていない場合に「Everything up-to-date」エラーを回避するように設計されています。

以下の内容を新しいMakefileとしてコピーして貼り付けてください。

# 引数なしで"make"を呼び出すときにデフォルトで実行されるルール
.DEFAULT_GOAL := dev


# Stackhero for Pythonは、インスタンスで"run"ルールを実行します。
# これは、本番およびステージング環境で実行するコマンドです。
run:
  ENV=production gunicorn app:app \
    --error-logfile - \
    -b 0.0.0.0:8080


# 開発環境で使用するコマンド
dev:
  python app.py


# インスタンス"stackhero"にデプロイするためのルール"deploy"。
# インスタンスが1つだけの場合に適しています。
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 \"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}

データベースやサードパーティサービスのトークンやパスワードなどのシークレットを保存する必要がある時が来ます。これらを安全に保存することが重要です。リポジトリやコードに直接埋め込むことは、重大なセキュリティリスクを生むため避けてください。

環境変数を使用することには2つの重要な利点があります。

  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ファイルはステージングおよび本番環境には十分に安全ではありません。代わりに、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"

本番およびステージングでは、StackheroダッシュボードのPythonサービス設定でREDIS_URLを定義します。

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

Pythonパッケージをrequirements.txtファイルで管理することをお勧めします。このファイルには、コードを確実に実行するために必要なすべてのパッケージとそのバージョンが一覧表示されます。

このファイルを最新の状態に保つことで、次のことが保証されます。

  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_ed25519id_rsaに置き換えます。

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