Cloud Run + django + Cloud Sql のデプロイ
前提
とくにCloud Runを初めて使う人、使ってみてるけどうまくいかない人向けです。
ローカル環境について
- Pythonのバージョン: 3.10.0
- Dockerのバージョン: 20.10.8
- DB(postgres)のバージョン: 14.0
この記事で説明しないこと:
- Cloud Sql, Cloud Runの説明
準備するもの
- Cloud Sqlのインスタンスが作成されている
- Djangoのプロジェクト(ソース)が手元にある
- gcloudコマンドがインストールされている
- gcpのコンソールにログインできる
手順
手順としては、3ステップで説明する。
- デプロイのための準備
- dockerイメージをリポジトリに登録する
- Cloud Runにアプリ(django)をデプロイする
デプロイのための準備
環境変数を設定する
Cloud Runで実行するには都合を考えて、djangoにおけるDBの接続情報などを環境変数を.env
ファイルから読み込むようにしておきます。
今回はenviron
を利用して、.env
からsettings.py
に読み込むようにします。
pip install django-environ
import os
import environ
env = environ.Env()
env.read_env('.env')
SECRET_KEY = env('SECRET_KEY')
DEBUG = env.get_value('DEBUG',bool)
DATABASES = {
## DATABASE_URLとして読み込まれる
'default': env.db()
}
DATABASE_URL=postgres://postgres:postgres@db:5432/postgres
SECRET_KEY=<SECRET_KEY>
DEBUG=True
注意すること
- DEBUG=Falseにならない
- boolean型として判定させるためには、キャストするようにsettings.pyに記入する必要がある
環境変数にboolean
型を入れるときは、get_value
の第2引数にboolを指定する必要があります。
というのも、環境変数はenviron
を使って.env
の設定値を文字列(String)として読み込みます。
DEBUG = env.get_value('DEBUG',bool)
DEBUG=True
DBを作成、マイグレーションする
Cloud Run
にデプロイするアプリ(django)からCloud Sql
に接続するインスタンスは作成している前提として、そこに作ったDBを作ります。
Cloud SqlのDBの作り方はここでは割愛します。
次にローカルの開発環境からDBへマイグレーションを行います。
- ローカルでのアーキテクチャ
cloud proxyを利用してローカル環境からデータベースに接続するために、docker-compose.ymlにcloud proxyのサービスを設定します。今回はcloudsql-proxy
という名前でサービスを設定します。
version: '3'
services:
## cloudsql-proxyというサービスを追加する
cloudsql-proxy:
image: gcr.io/cloudsql-docker/gce-proxy:1.19.1
volumes:
- ./<service-account>.json:/config/key.json
ports:
- "5432:5432"
environment:
TZ: Asia/Tokyo
restart: always
command: /cloud_sql_proxy -instances="<cloud-sql-connection>"=tcp:0.0.0.0:5432 -credential_file=/config/key.json
cloudsql-proxy
のサービスをスタートします。
docker-compose up cloudsql-proxy
こうするとcloudsql-proxy
という名前でDockerのネットワークにおけるDNSの解決ができるようになります。
## cloudsql-proxyという名前で、5432番ポートを使って接続します
DATABASE_URL=postgres://<cloud-sql-db-user-name>:<cloud-sql-db-password>@cloudsql-proxy:5432/<db-name>
最後にdjangoのマイグレーションコマンドを実行します。
python manage.py migrate
うまくいくとCloud SqlのDBに接続しながら、ローカルのdjangoアプリをブラウザで動作を確認することができます。
注意すべきこと
サービスアカウントにCloud SqlのIAMを付与する
GCPにおけるリソースはIAMで管理されます。今回使うCloud Runでは実行するサービスアカウントを指定することができます。その指定するサービスアカウントにはCloud Runを実行するロールを持ったサービスアカウントを指定する必要があります。
IAMからサービスアカウントにロールが付与されているかを確認します。
データベースの接続名は108文字以内にする
Cloud Runで実行されるWEBアプリ(今回はdjango)は、Cloud Sql上のDBにUnixソケットを使って接続します。
ここで気をつけるのは接続名を108以内にすること
です。Unixのソケット通信が108文字までしか対応してないらしいです。gcpの公式にも注意があります。
Cloud Sqlの起動時間が長い
Cloud Sqlのインスタンスを起動しようとすると、ぼくの場合だけかもしれないですが5分-8分くらいかかります。
作業をスムーズに進めたいときには、先にCloud Sqlのインスタンスをスタートしておくとかの対応をすると良いと思います。
Cloud Sqlの費用に気をつける
パブリッククラウドにおけるDBのサービスは、どこでもだいたい高くなりがちです。gcpもその例に漏れません。何も考えずにデフォルトのプランでインスタンス立ち上げっぱなしにすると、請求日にびっくりするような料金が請求されることになります。
Cloud Sqlのインスタンスの設定にはくれぐれも気をつけるようにしましょう。
↑これが最安のインスタンスの設定になります(多分。)
dockerイメージをリポジトリに登録する
- Artifact RegistoryかContainer RegistoryにDockerイメージをpushする
Cloud Runでアプリを実行するときには、Cloud Runが実行するコンテナ上でwebアプリを実行します。そのコンテナ上で実行されるWEBアプリのコンテナイメージを予めgcpのイメージレジストリに登録しておく必要があります。
コンテナイメージを保存するのは、Artifact RegistoryでもContainer RegistoryでもOKです。
ステージングのとしてビルドしたい場合は、DockerfileをDockerfile.staging
のような名前でDockerfile作成し、docker-compose.staging.yml
でDockerfile.staging
を指定します。
FROM python:3
ENV PYTHONUNBUFFERED 1
RUN mkdir /code
WORKDIR /code
ADD requirements.txt /code/
RUN pip install --upgrade pip
RUN pip install -r requirements.txt
ADD . /code/
EXPOSE 8000
CMD python3 manage.py migrate
CMD python3 manage.py runserver 0.0.0.0:$PORT
$PORT
としておくと、Cloud Run
で実行するときにCloud Run
でポート番号をしていして、実行することができます。
そのためのDokcerfileに引数が取れるように指定しておきます。
docker-compose -f docker-compose.staging.yml build
docker push us-central1-docker.pkg.dev/<artifact-registory-path>:latest
Cloud RunのGUIからアプリ(django)をデプロイする
ここでやることは大きく3つあります。↓
- 環境変数をCloud Runから読み込むようにする
- Cloud SQLの接続情報を環境変数から読み込む
- コンテナポートは8000にする
キャプチャとともに説明していきます。
新しいリビジョンの編集とデプロイ
を押下する
1. 2. コンテナのイメージに予めpushしておいたコンテナのイメージを選択する
コンテナイメージのURL
に予めpushしておいたコンテナのイメージを指定します。今回の場合はdjangoアプリのイメージを選択します。
リッスンするコンテナのポートをコンテナポート
=8000にします。
デプロイがうまくいったときに生成されるURL、 https://<hogehoge>-uc.a.run.app
にポート番号指定無しでアクセスすると、内部的にコンテナの8000番ポートにリクエストが転送されます。
メモリ
、CPU
を設定する
3. コンテナに割り当てるメモリ
、CPU
を適当に設定します。
1コンテナに仮想的に割り当てられるリソースは少なめにしておいたほうがお安く済むと思います。(多分)
併せて、自動スケーリング
も設定します。
自動スケーリングのインスタンスの最小数
を1
に、インスタンスの最大数
については適当でいいです。自動スケーリングが必要になるタイミングが今回はあまりないと思うので。
割り当てるリソースが少ないほど、お安く済むと思います。(多分)
4. 環境変数をセットする
.env
で指定するパラメータをCloud Runにデプロイするときには、変数とシークレット
からセットします。
DATABASE_URL
にはCloud SQLの接続名
を指定します。(↓画像参照)
またSECRET_KEY
はdjangoのsettings.py
にあるSECRET_KEY
を指定しています。
5. Cloud SQLの接続する
Cloud SQL接続
に、予め作成しておいたインスタンスを指定します。
6. サービスアカウントを指定する
サービスアカウント
として、先程設定したサービスアカウントを指定します。
このときサービスアカウント
にCloud SQL
をコントロールするロールが付与されておく必要があります。
これでCloud Run
に設定することは以上です。後はページ下部のデプロイ
を押下すると、デプロイが開始されます。
Cloud Runを使うときに注意すべきこと
Cloud Run
を使うときに注意すべき点を説明しておきます。
Cloud SQLを実行するIAMが必要
Cloud Run
を実行するだけのIAMをサービスアカウントに付与しておく必要があります。今回は以下のロールが必要になります。
Cloud Run 起動元
Cloud SQL クライアント
メディア バケットの Storage 管理者
Django 設定シークレットの Secret Manager Accessor。(Django 管理シークレットへのアクセスは、サービス自体には必要ありません。)
まとめ
以上の手順でCloud Run + Cloud SQL + django
でのデプロイができるはずです。
もし指摘点あれば、コメントをください。
Discussion