Cloud Run 環境で Django を実行する

Django のようにステートフル アプリケーションを Cloud Run にデプロイすると、サービスが連携して統合プロジェクトを形成します。

このチュートリアルは、Django ウェブ開発の知識があることを前提としています。Django 開発を初めて使用する場合は、続行する前に最初の Django アプリを作成するを実施することをおすすめします。

このチュートリアルでは Django について具体的に説明しますが、このデプロイ プロセスは WagtailDjango CMS などの他の Django ベースのフレームワークでも使用できます。

このチュートリアルでは Django 3 を使用します。Django 3 には Python 3.7 以降が必要です。

目標

このチュートリアルの内容は次のとおりです。

  • Cloud SQL データベースを作成して接続する。
  • Secret Manager のシークレット値を作成して使用する。
  • Cloud Run に Django アプリをデプロイする。

  • Cloud Storage で静的ファイルをホストする。

  • Cloud Build を使用してデプロイを自動化する。

料金

このチュートリアルでは、課金対象である次の Google Cloud コンポーネントを使用します。

料金計算ツールを使用すると、予想使用量に基づいて費用の見積もりを算出できます。新しい Google Cloud ユーザーは無料トライアルをご利用いただけます。

始める前に

  1. Google Cloud アカウントにログインします。Google Cloud を初めて使用する場合は、アカウントを作成して、実際のシナリオでの Google プロダクトのパフォーマンスを評価してください。新規のお客様には、ワークロードの実行、テスト、デプロイができる無料クレジット $300 分を差し上げます。
  2. Google Cloud Console の [プロジェクト セレクタ] ページで、Google Cloud プロジェクトを選択または作成します。

    プロジェクト セレクタに移動

  3. Cloud プロジェクトに対して課金が有効になっていることを確認します。プロジェクトに対して課金が有効になっていることを確認する方法を学習する

  4. Cloud Run, Cloud SQL, Cloud Build, Secret Manager, and Compute Engine API を有効にします。

    API を有効にする

  5. Cloud SDK をインストールして初期化します。
  6. このチュートリアルで使用するアカウントに十分な権限が付与されていることを確認してください。

環境を準備する

サンプルアプリのクローンを作成する

Django サンプルアプリのコードは、GitHub の GoogleCloudPlatform/python-docs-samples リポジトリにあります。

  1. ZIP ファイルとしてサンプルをダウンロードして展開するか、ローカルマシンにリポジトリのクローンを作成します。

    git clone https://github.com/GoogleCloudPlatform/python-docs-samples.git
    
  2. サンプルコードのあるディレクトリに移動します。

    Linux / macOS

    cd python-docs-samples/run/django
    

    Windows

    cd python-docs-samples\run\django
    

Python の設定を確認する

このチュートリアルでは、マシン上でサンプル アプリケーションを実行するために Python を使用します。サンプルコードは依存関係もインストールする必要があります。

詳細については、Python 開発環境ガイドをご覧ください。

  1. Python のバージョンが 3.7 以降であることを確認します。

     python -V
    

    Python 3.7.3 以上が表示される必要があります。

  2. Python 仮想環境を作成し、依存関係をインストールします。

    Linux / macOS

    python -m venv venv
    source venv/bin/activate
    pip install --upgrade pip
    pip install -r requirements.txt
    

    Windows

    python -m venv env
    venv\scripts\activate
    pip install --upgrade pip
    pip install -r requirements.txt
    

ローカルマシンから Cloud SQL Auth プロキシをダウンロードして Cloud SQL に接続する

デプロイされると、アプリは Cloud Run 環境に組み込まれている Cloud SQL Auth プロキシを使用して Cloud SQL インスタンスと通信します。ただし、アプリをローカルでテストするには、プロキシのローカルコピーを開発環境にインストールして使用する必要があります。詳細については、Cloud SQL Auth プロキシガイドをご覧ください。

Cloud SQL Auth プロキシは、Cloud SQL API を使用して SQL インスタンスを操作します。そのためには、gcloud でアプリケーションの認証を行う必要があります。

  1. API の認証情報を取得して認証します。

    gcloud auth application-default login
    
  2. Cloud SQL Auth プロキシをローカルマシンにダウンロードしてインストールします。

    Linux 64 ビット

    1. Cloud SQL Auth Proxy をダウンロードします。
      wget https://dl.google.com/cloudsql/cloud_sql_proxy.linux.amd64 -O cloud_sql_proxy
      
    2. Cloud SQL Auth Proxy を動作可能にします。
      chmod +x cloud_sql_proxy
      

    Linux 32 ビット

    1. Cloud SQL Auth Proxy をダウンロードします。
      wget https://dl.google.com/cloudsql/cloud_sql_proxy.linux.386 -O cloud_sql_proxy
      
    2. Cloud SQL Auth Proxy を動作可能にします。
      chmod +x cloud_sql_proxy
      

    macOS 64 ビット

    1. Cloud SQL Auth Proxy をダウンロードします。
      curl -o cloud_sql_proxy https://dl.google.com/cloudsql/cloud_sql_proxy.darwin.amd64
      
    2. Cloud SQL Auth Proxy を動作可能にします。
      chmod +x cloud_sql_proxy
      

    macOS 32 ビット

    1. Cloud SQL Auth Proxy をダウンロードします。
      curl -o cloud_sql_proxy https://dl.google.com/cloudsql/cloud_sql_proxy.darwin.386
      
    2. Cloud SQL Auth Proxy を動作可能にします。
      chmod +x cloud_sql_proxy
      

    Windows 64 ビット

    https://dl.google.com/cloudsql/cloud_sql_proxy_x64.exe を右クリックして [名前を付けてリンク先を保存] を選択し、Cloud SQL Auth Proxy をダウンロードします。ファイル名を cloud_sql_proxy.exe に変更します。

    Windows 32 ビット

    https://dl.google.com/cloudsql/cloud_sql_proxy_x86.exe を右クリックして [名前を付けてリンク先を保存] を選択し、Cloud SQL Auth Proxy をダウンロードします。ファイル名を cloud_sql_proxy.exe に変更します。

    Cloud SQL Auth Proxy Docker イメージ

    便宜上、Cloud SQL Auth プロキシを含むいくつかのコンテナ イメージは、GitHub で Cloud SQL Auth プロキシ リポジトリから入手できます。次のコマンドを使用して、最新のイメージをローカルマシンに Docker で pull できます。
    docker pull gcr.io/cloudsql-docker/gce-proxy:1.19.1
    

    その他の OS

    ここに記載されていないその他のオペレーティング システムの場合は、ソースから Cloud SQL Auth Proxy をコンパイルできます。

    ダウンロード先は、PATH の場所やホーム ディレクトリなど、任意の場所に移動できます。これを選択した場合、チュートリアルの後半で Cloud SQL Auth プロキシを起動する際に、cloud_sql_proxy コマンドを使用するときに選択したロケーションを必ず参照してください。

バッキング サービスの準備

このチュートリアルでは、さまざまな Google Cloud サービスを使用して、デプロイ済みの Django プロジェクトをサポートするデータベース、メディア ストレージ、シークレット ストレージを準備します。これらのサービスは、特定のリージョンにデプロイされます。サービス間の効率を高めるために、すべてのサービスを同じリージョンにデプロイすることをおすすめします。最も近いリージョンの詳細については、リージョン別に提供されるプロダクトをご覧ください。

Cloud SQL for PostgreSQL インスタンスを設定する

Django は複数のリレーショナル データベースをサポートしていますが、Cloud SQL で提供されるデータベース タイプの 1 つである PostgreSQL を最もサポートしています。

以降のセクションでは、polls アプリ用の PostgreSQL インスタンス、データベース、データベース ユーザーの作成について説明します。

PostgreSQL インスタンスを作成する

Console

  1. Cloud Console で、[Cloud SQL インスタンス] ページに移動します。

    Cloud SQL インスタンス ページに移動

  2. [インスタンスを作成] をクリックします。

  3. [PostgreSQL] をクリックします。

  4. [インスタンス ID] フィールドに、インスタンスの名前(INSTANCE_NAME)を入力します。

  5. postgres ユーザーのパスワードを入力します。

  6. 他のフィールドはデフォルト値を使用します。

  7. [作成] をクリックします。

gcloud

  1. PostgreSQL インスタンスを作成します。

    gcloud sql instances create INSTANCE_NAME \
        --project PROJECT_ID \
        --database-version POSTGRES_12 \
        --tier db-f1-micro \
        --region REGION
    

    以下を置き換えます。

    インスタンスの作成と使用準備が完了するまでに数分かかります。

  2. postgres ユーザーのパスワードを設定します。

    gcloud sql users set-password postgres \
        --instance INSTANCE_NAME --prompt-for-password
    

データベースの作成

Console

  1. Cloud Console で、[Cloud SQL インスタンス] ページに移動します。

    Cloud SQL インスタンス ページに移動

  2. INSTANCE_NAME インスタンスを選択します。

  3. [データベース] タブに移動します。

  4. [データベースを作成] をクリックします。

  5. [データベース名] ダイアログで「DATABASE_NAME」と入力します。

  6. [作成] をクリックします。

gcloud

  • 最近作成したインスタンス内にデータベースを作成します。

    gcloud sql databases create DATABASE_NAME \
        --instance INSTANCE_NAME
    

    DATABASE_NAME を、このインスタンス内のデータベースの名前に置き換えます。

ユーザーを作成する

Console

  1. Cloud Console で、Cloud Shell をアクティブにします。

    Cloud Shell をアクティブにする

  2. Cloud Shell で、組み込みの gcloud クライアントを使用して INSTANCE_NAME インスタンスに接続します。

    gcloud sql connect INSTANCE_NAME --user postgres
    
  3. postgres ユーザー パスワードを入力します。

    現在、psql を使用しています。postgres=> プロンプトが表示されます。

  4. ユーザーを作成します。

    CREATE USER 'django' WITH PASSWORD 'PASSWORD';
    

    PASSWORD を、十分に秘密性の高いパスワードに置き換えます。

  5. 新しいデータベースに対する完全な権限を新しいユーザーに付与します。

    GRANT ALL PRIVILEGES ON DATABASE 'DATABASE_NAME' TO 'django';
    
  6. psql を終了します。

    \q
    

gcloud

  1. SQL インスタンスへの接続を開始します。

    gcloud sql connect INSTANCE_NAME --user postgres
    

    INSTANCE_NAME は、作成した Cloud SQL インスタンスに置き換えます。

  2. postgres ユーザー パスワードを入力します。

    現在、psql を使用しています。postgres=> プロンプトが表示されます。

  3. ユーザーを作成します。

    CREATE USER 'django' WITH PASSWORD 'PASSWORD';
    
  4. 新しいデータベースに対する完全な権限を新しいユーザーに付与します。

    GRANT ALL PRIVILEGES ON DATABASE 'DATABASE_NAME' TO 'django';
    
  5. psql を終了します。

    \q
    

Cloud Storage バケットを設定する

Django に含まれている静的アセットやユーザーがアップロードしたメディアを、Cloud Storage を使用する可用性の高いオブジェクト ストレージに保存できます。django-storages[google] パッケージは、Django とこのストレージ バックエンドとのインタラクションを処理します。

Console

  1. Cloud Console で、Cloud Storage ブラウザページに移動します。

    [ブラウザ] に移動

  2. [バケットを作成] をクリックします。
  3. [バケットの作成] ページでユーザーのバケット情報を入力します。次のステップに進むには、[続行] をクリックします。
    • [バケットに名前を付ける] で、バケット名の要件を満たす名前を入力します。
    • [ロケーション] で、次のように選択します。 PROJECT_ID-media
    • [データのデフォルトのストレージ クラスを選択する] で、次を選択します。 Standard
    • [オブジェクトへのアクセスを制御する方法を選択する] で [アクセス制御] オプションを選択します。
    • [詳細設定(省略可)] には、暗号化メソッド保持ポリシー、またはバケットラベルを指定します。
  4. [作成] をクリックします。

gcloud

gsutil コマンドライン ツールは、Cloud SDK の一部としてインストールされます。

  • Cloud Storage バケットを作成します。

    gsutil mb -l REGION gs://PROJECT_ID-media
    

Secret Manager にシークレット値を保存する

バッキング サービスが構成されたので、Django はこれらのサービスに関する情報を必要とします。このチュートリアルでは、これらの値を Django のソースコードに直接入力せず、Secret Manager を使用してこの情報を安全に保存します。

Cloud Run と Cloud Build は、プロジェクト番号を含むメールアドレスで識別される、それぞれのサービス アカウントを使用してシークレットとやり取りします。

Secret Manager シークレットとして Django 環境ファイルを作成する

Django の起動に必要な設定を、保護された .env ファイルに保存します。サンプルコードは、Secret Manager API を使用してシークレット値を取得し、django-environ パッケージを使用して Django 環境に値を読み込みます。シークレットは、Cloud Build と Cloud Run の両方でアクセスできるように構成されます。これは、これらのサービスが両方とも Django を実行するためです。

  1. .env という名前のファイルを作成し、データベースの接続文字列、メディア バケット名、新しい SECRET_KEY 値を定義します。

    DATABASE_URL=postgres://django:PASSWORD@//cloudsql/PROJECT_ID:REGION:INSTANCE_NAME/DATABASE_NAME
    GS_BUCKET_NAME=PROJECT_ID-media
    SECRET_KEY=(a random string, length 50)
    
  2. シークレットを Secret Manager に保存します。

Console

  1. Cloud Console で、[シークレット マネージャー] ページに移動します。

    シークレット マネージャー ページに移動

  2. [シークレットの作成] をクリックします。

  3. [名前] フィールドに「django_settings」と入力します。

  4. [ファイルをアップロード] ダイアログで、ローカルに保存されている .env ファイルを選択します。

  5. [シークレットの作成] をクリックします。

  6. [django_settings の詳細] で、プロジェクト番号をメモします。

    projects/PROJECTNUM/secrets/django_settings
    
  7. [メンバーを追加] をクリックします。

  8. [新しいメンバー] フィールドに「PROJECTNUM-compute@developer.gserviceaccount.com」と入力し、Enter を押します。

  9. [新しいメンバー] フィールドに「PROJECTNUM@cloudbuild.gserviceaccount.com」と入力し、Enter を押します。

  10. [ロール] プルダウン メニューで [Secret Manager のシークレット アクセサー] を選択します。

  11. [保存] をクリックします。

gcloud

  1. 新しいシークレット(django_settings)を作成します。

    gcloud secrets create django_settings --replication-policy automatic
    
  2. .env ファイルをシークレットのバージョンとして追加します。

    gcloud secrets versions add django_settings --data-file .env
    
  3. シークレットの作成を確認するには、次のことを確認します。

    gcloud secrets describe django_settings
    

    プロジェクト番号をメモします。

    projects/PROJECTNUM/secrets/django_settings
    
  4. Cloud Run サービス アカウントにシークレットへのアクセス権を付与します。

    gcloud secrets add-iam-policy-binding django_settings \
        --member serviceAccount:PROJECTNUM-compute@developer.gserviceaccount.com \
        --role roles/secretmanager.secretAccessor
    
  5. Cloud Build サービス アカウントにシークレットへのアクセス権を付与します。

    gcloud secrets add-iam-policy-binding django_settings \
        --member serviceAccount:PROJECTNUM@cloudbuild.gserviceaccount.com \
        --role roles/secretmanager.secretAccessor
    

    出力で、bindings が 2 つのサービス アカウントをメンバーとしてリストしていることを確認します。

Django の管理者パスワード用のシークレットを作成する

Django 管理ユーザーは通常、インタラクティブ管理コマンド createsuperuser を実行して作成されます。

このチュートリアルでは、データ移行を使用して管理ユーザーを作成し、Secret Manager からパスワードを取得します。

Console

  1. Cloud Console で、[シークレット マネージャー] ページに移動します。
  2. [シークレットの作成] をクリックします。

  3. [名前] フィールドに「superuser_password」と入力します。

  4. [シークレット値] フィールドにランダムなパスワードを入力します。

  5. [シークレットの作成] をクリックします。

  6. [superuser_password の詳細] で、プロジェクト番号をメモします(projects/PROJECTNUM/secrets/superuser_password)。

  7. [メンバーを追加] をクリックします。

  8. [新しいメンバー] フィールドに「PROJECTNUM@cloudbuild.gserviceaccount.com」と入力し、Enter を押します。

  9. [ロール] プルダウン メニューで [Secret Manager のシークレット アクセサー] を選択します。

  10. [保存] をクリックします。

gcloud

  1. 新しいシークレット(superuser_password)を作成します。

    gcloud secrets create superuser_password --replication-policy automatic
    
  2. このシークレットのバージョンとして、ランダムに生成されたパスワードを追加します。

    cat /dev/urandom | tr -dc 'a-zA-Z0-9' | head -c30 > superuser_password
    
    gcloud secrets versions add superuser_password --data-file superuser_password
    
  3. Cloud Build にシークレットへのアクセス権を付与します。

    gcloud secrets add-iam-policy-binding superuser_password \
        --member serviceAccount:PROJECTNUM@cloudbuild.gserviceaccount.com \
        --role roles/secretmanager.secretAccessor
    

    出力で、bindings が Cloud Build のみをメンバーとしてリストしていることを確認します。

Cloud Build に Cloud SQL へのアクセス権を付与する

Cloud Build でデータベースの移行を適用するには、Cloud Build に Cloud SQL へのアクセス権を付与する必要があります。

Console

  1. Cloud Console で、[Identity and Access Management] ページに移動します。

    [Identity and Access Management] ページに移動

  2. PROJECTNUM@cloudbuild.gserviceaccount.com のエントリを編集するには、 [編集] をクリックします。

  3. [別のロールを追加] をクリックします。

  4. [ロールを選択] ダイアログで、[Cloud SQL クライアント] を選択します。

  5. [保存] をクリックします。

gcloud

  1. Cloud Build に Cloud SQL へのアクセス権を付与します。

    gcloud projects add-iam-policy-binding PROJECT_ID \
        --member serviceAccount:PROJECTNUM@cloudbuild.gserviceaccount.com \
        --role roles/cloudsql.client
    

ローカル コンピュータでアプリを実行する

バッキング サービスが構成されたら、パソコン上でアプリを実行できます。この設定により、ローカルでの開発やデータベースの移行が可能になります。データベースの移行は Cloud Build にも適用されますが、makemigrations を使用するには、このローカル設定が必要です。

  1. 別のターミナルで Cloud SQL Auth プロキシを開始します。

    Linux / macOS

    ./cloud_sql_proxy -instances="PROJECT_ID:REGION:INSTANCE_NAME"=tcp:5432
    

    Windows

    cloud_sql_proxy.exe -instances="PROJECT_ID:REGION:INSTANCE_NAME"=tcp:5432
    

    このステップで、ローカルのパソコンから Cloud SQL インスタンスへのローカルテスト用接続が確立されます。ローカルでのアプリのテストが終了するまで、Cloud SQL Auth プロキシを実行したままにしてください。このプロセスを別のターミナルで実行すると、このプロセスの実行中に作業を続行できます。次のステップが別のターミナルで完了していることを確認します。

  2. 新しいターミナルで、プロジェクト ID をローカルで設定します。

    Linux / macOS

      export GOOGLE_CLOUD_PROJECT=PROJECT_ID
    

    Windows

      set GOOGLE_CLOUD_PROJECT=PROJECT_ID
    
  3. Cloud SQL Auth プロキシを使用していることを示す環境変数を設定します(この値はコードで認識できます)。

    Linux / macOS

      export USE_CLOUD_SQL_AUTH_PROXY=true
    

    Windows

      set USE_CLOUD_SQL_AUTH_PROXY=true
    
  4. モデルとアセットを設定するために、Django の移行を実行します。

    python manage.py makemigrations
    python manage.py makemigrations polls
    python manage.py migrate
    python manage.py collectstatic
    
  5. Django ウェブサーバーを起動します。

    python manage.py runserver
    
  6. ブラウザで、http://localhost:8000 にアクセスします。

    「Hello, world. You're at the polls index.」というテキストを含む簡単なウェブページが表示されます。コンピュータで実行されている Django ウェブサーバーは、サンプルアプリのページを配信します。

  7. Control+C キーを押して、ローカル ウェブサーバーを停止します。

Cloud Run にアプリをデプロイする

バッキング サービスを設定できたので、Cloud Run サービスをデプロイできるようになりました。

  1. 提供された cloudmigrate.yaml を使用して、Cloud Build を使用してイメージをビルドし、データベースの移行を実行して、静的アセットにデータを入力します。

    gcloud builds submit --config cloudmigrate.yaml \
        --substitutions _INSTANCE_NAME=INSTANCE_NAME,_REGION=REGION
    

    最初のビルドが完了するまで数分かかります。

  2. ビルドが成功したら、Cloud Run サービスを初めてデプロイし、サービス リージョン、ベースイメージ、接続された Cloud SQL インスタンスを設定します。

    gcloud run deploy polls-service \
        --platform managed \
        --region REGION \
        --image gcr.io/PROJECT_ID/polls-service \
        --add-cloudsql-instances PROJECT_ID:REGION:INSTANCE_NAME \
        --allow-unauthenticated
    

    サービスの URL とともに、デプロイが成功したことを示す出力が表示されます。

    Service [polls-service] revision [polls-service-00001-tug] has been deployed
    and is serving 100 percent of traffic at https://polls-service-<hash>-uc.a.run.app
    
  3. デプロイされたサービスを確認するには、サービスの URL に移動します。

  4. Django 管理にログインするには、URL に /admin を加え、ユーザー名 admin と前に設定したパスワードでログインします。

アプリケーションを更新する

最初のプロビジョニングとデプロイの手順は複雑でしたが、更新はより単純なプロセスです。

  1. Cloud Build のビルドと移行スクリプトを実行します。

    gcloud builds submit --config cloudmigrate.yaml \
        --substitutions _INSTANCE_NAME=INSTANCE_NAME,_REGION=REGION
    
  2. リージョンとイメージのみを指定して、サービスをデプロイします。

    gcloud run deploy polls-service \
        --platform managed \
        --region REGION \
        --image gcr.io/PROJECT_ID/polls-service
    

本番環境用の構成

これで Django のデプロイが機能するようになりました。しかし、アプリケーションが本番環境に対応できるよう、さらに対策を講じる必要があります。

デバッグが無効になっていることを確認する

mysite/settings.pyDEBUG 変数が False に設定されていることを確認します。これにより、構成に関する情報が漏洩する可能性がある、詳細なエラーページがユーザーに表示されなくなります。

データベース ユーザーの権限を制限する

Cloud SQLを使用して作成されたすべてのユーザーには、cloudsqlsuperuser ロールに関連付けられた特権(CREATEROLECREATEDB、および LOGIN)があります。

Django データベース ユーザーにこれらの権限が付与されないようにするには、PostgreSQL でユーザーを手動で作成します。psql インタラクティブ ターミナルをインストールするか、このツールがプリインストールされている Cloud Shell を使用する必要があります。

Console

  1. Cloud Console で、Cloud Shell をアクティブにします。

    Cloud Shell をアクティブにする

  2. Cloud Shell で、組み込みターミナルを使用して INSTANCE_NAME インスタンスに接続します。

    gcloud sql connect INSTANCE_NAME --user postgres
    
  3. postgres ユーザー パスワードを入力します。

    現在、psql を使用しています。postgres=> プロンプトが表示されます。

  4. ユーザーを作成します。

    CREATE USER django WITH PASSWORD 'PASSWORD';
    

    PASSWORD は、ランダムな一意のパスワードに置き換えます。

  5. 新しいデータベースに対する完全な権限を新しいユーザーに付与します。

    GRANT ALL PRIVILEGES ON DATABASE DATABASE_NAME TO django;
    
  6. psql を終了します。

    \q
    

gcloud

  1. SQL インスタンスへの接続を開始します。

    gcloud sql connect INSTANCE_NAME --user postgres
    

    INSTANCE_NAME は、作成した Cloud SQL インスタンスに置き換えます。

  2. postgres ユーザー パスワードを入力します。

    現在、psql を使用しています。postgres=> プロンプトが表示されます。

  3. ユーザーを作成します。

    CREATE USER django WITH PASSWORD 'PASSWORD';
    
  4. 新しいデータベースに対する完全な権限を新しいユーザーに付与します。

    GRANT ALL PRIVILEGES ON DATABASE DATABASE_NAME TO django;
    
  5. psql を終了します。

    \q
    

最小権限の設定

デフォルトでは、このサービスは、デフォルトのコンピューティング サービス アカウントでデプロイされます。ただし、デフォルトのサービス アカウントを使用すると、付与される権限が多くなりすぎることがあります。制限を強める必要がある場合は、独自のサービス アカウントを作成して、サービスに必要な権限のみを割り当てる必要があります。必要な権限は、特定のサービスにより使用されるリソースに応じて、サービスごとに異なります。

このサービスに必要な最小限のプロジェクト ロールは次のとおりです。

  • Cloud Run 起動元
  • Cloud SQL クライアント
  • メディア バケットの Storage 管理者
  • Django 設定シークレットの Secret Manager Accessor。(Django 管理シークレットへのアクセスは、サービス自体には必要ありません。)

必要な権限を持つサービス アカウントを作成し、サービスに割り当てるには、次のコマンドを実行します。

  1. gcloud ツールで、必要なロールを持つサービス アカウントを作成します。

    gcloud iam service-accounts create polls-service-account
    SERVICE_ACCOUNT=polls-service-account@PROJECT_ID.iam.gserviceaccount.com
    
    # Cloud Run Invoker
    gcloud projects add-iam-policy-binding PROJECT_ID \
        --member serviceAccount:${SERVICE_ACCOUNT} \
        --role roles/run.invoker
    
    # Cloud SQL Client
    gcloud projects add-iam-policy-binding PROJECT_ID \
        --member serviceAccount:${SERVICE_ACCOUNT} \
        --role roles/cloudsql.client
    
    # Storage Admin, on the media bucket
    gsutil iam ch \
        serviceAccount:${SERVICE_ACCOUNT}:roles/storage.objectAdmin \
        gs://PROJECT_ID-media
    
    # Secret Accessor, on the Django settings secret.
    gcloud secrets add-iam-policy-binding django_settings \
        --member serviceAccount:${SERVICE_ACCOUNT} \
        --role roles/secretmanager.secretAccessor
    
  2. サービスを新しいサービス アカウントに関連付けてデプロイします。

    gcloud run services update polls-service \
        --platform managed \
        --region REGION \
        --service-account ${SERVICE_ACCOUNT}
    

コードを理解する

サンプル アプリケーション

Django サンプルアプリは、Django の標準ツールを使用して作成されています。以下のコマンドは、プロジェクトと polls アプリを作成します。

django-admin startproject mysite
python manage.py startapp polls

ベースビュー、モデル、ルート構成は、最初の Django アプリを作成するパート 1およびパート 2)からコピーされました。

Secret Manager のシークレット

settings.py ファイルには、Secret Manager Python API を使用して指定されたシークレットの最新バージョンを取得し、(django-environ を使用して)その環境に pull するコードが含まれています。

env = environ.Env(DEBUG=(bool, False))
env_file = os.path.join(BASE_DIR, ".env")

# Attempt to load the Project ID into the environment, safely failing on error.
try:
    _, os.environ["GOOGLE_CLOUD_PROJECT"] = google.auth.default()
except google.auth.exceptions.DefaultCredentialsError:
    pass

if os.path.isfile(env_file):
    # Use a local secret file, if provided

    env.read_env(env_file)
# ...
elif os.environ.get("GOOGLE_CLOUD_PROJECT", None):
    # Pull secrets from Secret Manager
    project_id = os.environ.get("GOOGLE_CLOUD_PROJECT")

    client = secretmanager.SecretManagerServiceClient()
    settings_name = os.environ.get("SETTINGS_NAME", "django_settings")
    name = f"projects/{project_id}/secrets/{settings_name}/versions/latest"
    payload = client.access_secret_version(name=name).payload.data.decode("UTF-8")

    env.read_env(io.StringIO(payload))
else:
    raise Exception("No local .env or GOOGLE_CLOUD_PROJECT detected. No secrets found.")

シークレットは、構成する必要のあるさまざまなシークレットの数を減らすために、複数のシークレット値を格納するために使用されます。 superuser_passwordコマンドラインから直接作成することもできますが、この方法ではなくファイルベースの方法が使用されました。コマンドラインから生成したとしたら、head -c を使用してランダムに生成された文字列の長さを慎重に決定し、ファイルの最後に改行文字がないことを確認する必要がありました(これは、パスワードを Django 管理に入力する際の問題の原因になります)。

ローカル シークレットのオーバーライド

ローカルのファイル システムで .env ファイルが見つかった場合は、Secret Manager の値の代わりに使用されます。ローカルで .env ファイルを作成すると、ローカルでのテストに役立ちます(例: SQLite データベースに対してローカルで開発する場合など)。

データベースへの接続

settings.pyファイルには、SQL データベースの構成が含まれています。USE_CLOUD_SQL_AUTH_PROXY を設定すると、DATABASES 設定が Cloud SQL Auth プロキシの使用を推測するように変更されます。

# Use django-environ to parse the connection string
DATABASES = {"default": env.db()}

# If the flag as been set, configure to use proxy
if os.getenv("USE_CLOUD_SQL_AUTH_PROXY", None):
    DATABASES["default"]["HOST"] = "127.0.0.1"
    DATABASES["default"]["PORT"] = 5432

クラウドに保存された静的

また、settings.py ファイルは、django-storages を使用して Cloud Storage メディア バケットをプロジェクトに直接統合します。

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

Cloud Build による自動化

cloudmigrate.yaml ファイルは、一般的なイメージのビルドステップ(コンテナ イメージを作成してコンテナ レジストリに push する)だけでなく、Django の migrate コマンドと collectstatic コマンドも実行します。これにはデータベースへのアクセスが必要です。これは、app-engine-exec-wrapperCloud SQL Auth プロキシのヘルパー)を使用して実行されます。

steps:
  - id: "build image"
    name: "gcr.io/cloud-builders/docker"
    args: ["build", "-t", "gcr.io/${PROJECT_ID}/${_SERVICE_NAME}", "."]

  - id: "push image"
    name: "gcr.io/cloud-builders/docker"
    args: ["push", "gcr.io/${PROJECT_ID}/${_SERVICE_NAME}"]

  - id: "apply migrations"
    name: "gcr.io/google-appengine/exec-wrapper"
    args:
      [
        "-i",
        "gcr.io/$PROJECT_ID/${_SERVICE_NAME}",
        "-s",
        "${PROJECT_ID}:${_REGION}:${_INSTANCE_NAME}",
        "-e",
        "SETTINGS_NAME=${_SECRET_SETTINGS_NAME}",
        "--",
        "python",
        "manage.py",
        "migrate",
      ]

  - id: "collect static"
    name: "gcr.io/google-appengine/exec-wrapper"
    args:
      [
        "-i",
        "gcr.io/$PROJECT_ID/${_SERVICE_NAME}",
        "-s",
        "${PROJECT_ID}:${_REGION}:${_INSTANCE_NAME}",
        "-e",
        "SETTINGS_NAME=${_SECRET_SETTINGS_NAME}",
        "--",
        "python",
        "manage.py",
        "collectstatic",
        "--verbosity",
        "2",
        "--no-input",
      ]

substitutions:
  _INSTANCE_NAME: django-instance
  _REGION: us-central1
  _SERVICE_NAME: polls-service
  _SECRET_SETTINGS_NAME: django_settings

images:
  - "gcr.io/${PROJECT_ID}/${_SERVICE_NAME}"

この構成では代入変数が使用されます。ファイルの値を直接変更すると、移行時に --substitutions フラグを省略できます。

K_SERVICE は、Cloud Run のコンテナ契約で宣言されているデフォルトの環境変数の 1 つです。この値は、移行ステップで設定します。この変数は、アプリケーションがローカルで実行されており、Cloud SQL Auth プロキシが使用されているかどうかを検出するために settings.py で使用される変数です。

この構成では、既存の移行のみが適用されます。「アプリをローカルで実行する」で定義されている Cloud SQL Auth プロキシ メソッドを使用して、移行をローカルで作成する必要があります。

2 つのコマンドを実行せずに 1 つの構成にデプロイを含めるように Cloud Build の構成を拡張するには、Cloud Build を使用した git による継続的デプロイをご覧ください。説明されているように、これには IAM の変更が必要です。

データ移行によるスーパーユーザーの作成

Django 管理コマンド createsuperuser はインタラクティブにのみ実行できます。つまり、ユーザーがプロンプトに従い情報を入力する場合です。このコマンドを Cloud SQL Proxy で使用し、ローカルの Docker セットアップ内でコマンドを実行できますが、別の方法は、データ移行としてスーパーユーザーを作成することです。

import os

from django.contrib.auth.models import User
from django.db import migrations
from django.db.backends.postgresql.schema import DatabaseSchemaEditor
from django.db.migrations.state import StateApps

import google.auth
from google.cloud import secretmanager

def createsuperuser(apps: StateApps, schema_editor: DatabaseSchemaEditor) -> None:
    """
    Dynamically create an admin user as part of a migration
    Password is pulled from Secret Manger (previously created as part of tutorial)
    """
    if os.getenv("TRAMPOLINE_CI", None):
        # We are in CI, so just create a placeholder user for unit testing.
        admin_password = "test"
    else:
        client = secretmanager.SecretManagerServiceClient()

        # Get project value for identifying current context
        _, project = google.auth.default()

        # Retrieve the previously stored admin password
        PASSWORD_NAME = os.environ.get("PASSWORD_NAME", "superuser_password")
        name = f"projects/{project}/secrets/{PASSWORD_NAME}/versions/latest"
        admin_password = client.access_secret_version(name=name).payload.data.decode(
            "UTF-8"
        )

    # Create a new user using acquired password, stripping any accidentally stored newline characters
    User.objects.create_superuser("admin", password=admin_password.strip())

class Migration(migrations.Migration):

    initial = True
    dependencies = []
    operations = [migrations.RunPython(createsuperuser)]

クリーンアップ

このチュートリアルで使用したリソースについて、Google Cloud アカウントに課金されないようにするには、リソースを含むプロジェクトを削除するか、プロジェクトを維持して個々のリソースを削除します。

プロジェクトの削除

  1. Cloud Console で [リソースの管理] ページに移動します。

    [リソースの管理] に移動

  2. プロジェクト リストで、削除するプロジェクトを選択し、[削除] をクリックします。
  3. ダイアログでプロジェクト ID を入力し、[シャットダウン] をクリックしてプロジェクトを削除します。

次のステップ