アルパカログ

📅  2021-12-13

DjangoをCloud Run+Cloud SQL構成で動かす


Cloud Run は Google Cloud で提供されているフルマネージドなサーバーレスプラットフォームです。

Django や Ruby on Rails といった Web アプリケーションを Cloud Run で実行すれば、従来に比べてインフラの管理コストを大きく削減することができます。

このエントリでは、Cloud Run+Cloud SQL 構成の Django アプリケーションを対象に Cloud Build を使って CI/CD 環境を構築する方法を説明します。

前提

下記の前提で説明していきます。

  • Python 3.9.7
  • Django 3.2.9

基本的には下記で説明されている内容になりますが、一部 CI/CD する上での注意点を挙げながら説明していきます。

説明に用いるサンプルアプリケーションのリポジトリは下記です。

構成

環境は production, staging, development, test の4つあるものとします。

production, staging 環境はそれぞれが Google Cloud プロジェクトで、development と test 環境はローカルです。

Django アプリケーションは Docker コンテナで実行します。

データベースには MySQL を使い、development, test 環境は Docker Compose で、production, staging 環境は Cloud SQL でデータベースを用意します。

CI/CD は master ブランチへの push をトリガーに Cloud Build を実行します。

Cloud Build では Docker イメージのビルドと Container Registry への push、そしてデータベースのマイグレーションと Cloud Run へのデプロイを行います。

今回は静的ファイルを配信するための collectstatic は行いません。

秘匿情報の管理にはシークレットマネージャーを利用します。

秘匿情報の取得はシークレットマネージャーの Python クライアント google-cloud-secret-manager を使ってDjango アプリケーション内で行います。

development, test 環境の構築

ここからはサンプルアプリケーションを使って説明していきます。実際に手を動かして試す場合は下記のリポジトリをフォークしてください。

フォークしたリポジトリをローカルにクローンしたら Docker Compose で development 環境を構築し Web サーバーを起動します。

$ git clone git@github.com:otoyo/django-cloudrun-sample.git
$ cd django-cloudrun-sample
$ docker compose build
$ docker compose run

MySQL コンテナが起動するまでしばらく待ちます。下記のようなログが現れたらブラウザで http://localhost:58000 を開きます。

app_1    | MySQL is up - executing command
app_1    | Watching for file changes with StatReloader

"The install worked successfully!" と表示されれば成功です。

ここで django_cloudrun_sample/settings.py を見てみましょう。L22 で必要な環境変数を定義しているのがわかります。

env = environ.Env(
        DEBUG=(bool, True),
        SECRET_KEY=(str, 'django-insecure-qnr$*ocy$diy6v#o&^k5x-9ofw@mn@4+bww*vyzwd4ydx%g@!d'),
        DB_NAME=(str, 'django_cloudrun_sample_dev'),
        DB_USER=(str, 'root'),
        DB_PASSWORD=(str, ''),
        DB_HOST=(str, 'mysql'),
        DB_PORT=(str, '3306'),
        )

環境変数の扱いには django-environ を使用しています。詳細はドキュメントを参照してください。

production, staging 環境ではこれらの環境変数をシークレットマネージャーから取得します。

L48 で環境の判別とシークレットマネージャーからの秘匿情報取得を行なっています。

try:
    _, os.environ["GOOGLE_CLOUD_PROJECT"] = google.auth.default()
except google.auth.exceptions.DefaultCredentialsError:
    pass

if os.environ.get("GOOGLE_CLOUD_PROJECT", None):
    # Pull secrets from Secret Manager and set env
    project_id = os.environ.get("GOOGLE_CLOUD_PROJECT")
    secret_name = 'django-cloudrun-sample-settings' # name of secret in Secret Manager

    client = secretmanager.SecretManagerServiceClient()
    name = f"projects/{project_id}/secrets/{secret_name}/versions/latest"
    payload = client.access_secret_version(name=name).payload.data.decode("UTF-8")

    env.read_env(io.StringIO(payload))

production, staging 環境は Google Cloud 上で実行されるため google.auth.default() でプロジェクトIDを取得することができます。プロジェクトIDが存在する場合は環境変数をシークレットマネージャーから取得した秘匿情報で上書きしています。

development, test 環境はローカルで実行されるため、環境変数はデフォルトが使用されます。

production, staging 環境の構築

production, staging 環境は Google Cloud プロジェクトが異なるだけという前提なので、ここでは staging 環境を例に説明していきます。

ここから各種インスタンスやサービスを作成するとき、リージョンは asia-northeast1 (東京) とします。

Google Cloud コンソールにログインし staging の Google Cloud プロジェクトを選択します(無ければ作成します)。

シークレットの作成

ℹ️

画像が読み込まれない場合はページの更新をお試しください。

シークレットマネージャーを開き新規にシークレットを作成します。

django-cloudrun-sample-settings の名前で下記の情報を登録します。

<secret> および <db_password> <PROJECT_ID> は自身で置き換えてください。

SECRET_KEY=<secret>
DB_NAME=django_cloudrun_sample
DB_USER=django
DB_PASSWORD=<db_password>
DB_HOST=/cloudsql/<PROJECT_ID>:asia-northeast1:django
DB_PORT=3306
画像が読み込まれない場合はページを更新してみてください。
django-cloudrun-sample-settings という名前でシークレットを作成する

シークレット名を変更する場合は settings.pysecret_name も変更します。

Cloud SQL インスタンスの作成

Cloud SQL を開き django という名前でインスタンスを作成します。インスタンスの接続設定でパブリック IP を割り当てていることを確認します。

画像が読み込まれない場合はページを更新してみてください。
パブリック IPを割り当てる

インスタンスを作成したら、左のメニューから django_cloudrun_sample データベースと django ユーザーを作成します。ユーザーのパスワードは先ほどシークレットに登録したパスワードを設定します。

画像が読み込まれない場合はページを更新してみてください。
django インスタンスのユーザー

画像が読み込まれない場合はページを更新してみてください。
django インスタンスのデータベース

Cloud Build トリガーの作成

Cloud Build を開き新規にトリガーを作成します。トリガー名は何でも構いません。ここでは deploy-django-cloudrun-sample という名前にします。

「構成」セクションで「自動検出」ではなく「Cloud Build 構成ファイル」を選択し、構成ファイルの場所として /cloudbuild.staging.yaml を指定します。

こうしておくことで production 環境と staging 環境で構成ファイルを分けておくことができます。

画像が読み込まれない場合はページを更新してみてください。
Cloud Build 構成ファイルは明示的に指定する

Cloud Run サービス作成

Cloud Run を開きサービスを作成します。

Cloud Run は Container Registry から Docker イメージを取得しますが、まだ Docker イメージをビルドおらず存在しないため、いったん手動で URL を gcr.io/django-cloudrun-sample/django-cloudrun-sample として登録しておきます。

画像が読み込まれない場合はページを更新してみてください。
Docker イメージをまだ登録していないため手動で入力しておく

"Container, Variables & Secrets, ..." セクションで、まず「変数とシークレット」タブを選び環境変数 DEBUG を値 False で追加します。

画像が読み込まれない場合はページを更新してみてください。
DEBUG: False で環境変数を追加する

次に「接続」タブを選択し Cloud SQL 接続を追加します。先ほど作成した django SQLインスタンスを選択します。

画像が読み込まれない場合はページを更新してみてください。
Cloud SQL 接続を追加する

ここまで設定できたらサービスを作成します。

画像が読み込まれない場合はページを更新してみてください。
サービスを作成する

サービスアカウントへのロール付与

IAM を開き PROJECTNUM@cloudbuild.gserviceaccount.comPROJECTNUM-compute@developer.gserviceaccount.com の2つのサービスアカウントに必要なロールを付与します。

下記の説明に従って Cloud Build サービスアカウントに権限を付与します。

上記に加えて、Cloud Build サービスアカウントに Cloud Build から Cloud SQL インスタンスの接続に cloud_sql_proxy を使うため 「Cloud SQL 管理者」を、Compute Engine のサービスアカウントにシークレットマネージャーからシークレットを取得するため「Secret Manager のシークレット アクセサー」を付与します。

最終的にサービスアカウントのロールは下記のようになりました。

画像が読み込まれない場合はページを更新してみてください。
サービスアカウントのロール

ビルドとデプロイの実行

これで CI/CD の準備が整いました。

フォークしたリポジトリに適当なコミットを push すると Cloud Build がトリガーされ、Docker イメージのビルドと push、データベースのマイグレーション、Cloud Run へのデプロイが順に実行されます。

Cloud Run へのデプロイが成功すると、Cloud Run のサービス画面に表示される URL に /admin パスを付けてブラウザで開きます。

https://django-cloudrun-sample-hogehoge.a.run.app/admin

Django Admin のログイン画面が表示されれば成功です。

以上です。

このエントリでは、Cloud Run+Cloud SQL 構成の Django アプリケーションを対象に Cloud Build を使って CI/CD 環境を構築する方法を説明しました。

同じカテゴリーの記事


おすすめ記事


最新記事


カテゴリー