🤖

Cloud Run + django + Cloud Sql のデプロイ

2021/11/16に公開

前提

とくに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

https://pypi.org/project/django-environ/

settings.py
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()
}
.env
DATABASE_URL=postgres://postgres:postgres@db:5432/postgres
SECRET_KEY=<SECRET_KEY>
DEBUG=True

https://cloud.google.com/python/django/run

注意すること

  • DEBUG=Falseにならない
    • boolean型として判定させるためには、キャストするようにsettings.pyに記入する必要がある

環境変数にboolean型を入れるときは、get_valueの第2引数にboolを指定する必要があります。
というのも、環境変数はenvironを使って.envの設定値を文字列(String)として読み込みます。

settings.py(一部)
DEBUG = env.get_value('DEBUG',bool)
.env(一部)
DEBUG=True

DBを作成、マイグレーションする

Cloud Runにデプロイするアプリ(django)からCloud Sqlに接続するインスタンスは作成している前提として、そこに作ったDBを作ります。

Cloud SqlのDBの作り方はここでは割愛します。

次にローカルの開発環境からDBへマイグレーションを行います。

  • ローカルでのアーキテクチャ

cloud proxyを利用してローカル環境からデータベースに接続するために、docker-compose.ymlにcloud proxyのサービスを設定します。今回はcloudsql-proxyという名前でサービスを設定します。

docker-compose.yml(一部抜粋)
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のサービスをスタートします。

bash
docker-compose up cloudsql-proxy

こうするとcloudsql-proxyという名前でDockerのネットワークにおけるDNSの解決ができるようになります。

.env(一部抜粋)
## cloudsql-proxyという名前で、5432番ポートを使って接続します
DATABASE_URL=postgres://<cloud-sql-db-user-name>:<cloud-sql-db-password>@cloudsql-proxy:5432/<db-name>

最後にdjangoのマイグレーションコマンドを実行します。

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の公式にも注意があります。

https://cloud.google.com/sql/docs/mysql/connect-run?hl=ja

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.ymlDockerfile.stagingを指定します。

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コマンドでbuildする
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番ポートにリクエストが転送されます。


3. メモリCPUを設定する

コンテナに割り当てるメモリ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 管理シークレットへのアクセスは、サービス自体には必要ありません。)

https://cloud.google.com/python/django/run#setting_minimum_permissions

まとめ

以上の手順でCloud Run + Cloud SQL + djangoでのデプロイができるはずです。
もし指摘点あれば、コメントをください。

Oriental Coffee Ventures

Discussion