2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Django(Django Ninja)をCloud Runにデプロイしてみた vol.1

Last updated at Posted at 2023-05-17

環境

MacOS Ventura
Python 3.10.7
Poetry 1.3.2

はじめに

この記事はこちらの続きです
https://qiita.com/ps0317ix/items/ff10e0eddfc24e5db96c

早速始めよう

正直Googleの公式がかなり充実してるのでこれで問題ないですが、あえて噛み砕いて手順を説明します
https://cloud.google.com/python/django/run?hl=ja

必要なライブラリを追加

terminal
poetry add psycopg2-binary gunicorn django-environ django-storages google-cloud-secret-manager

あとは公式ドキュメントに沿っていきます。

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

terminal
gcloud auth application-default login

2. Cloud SQL Auth プロキシをダウンロードしてローカルマシンにインストール

terminal
curl -o cloud_sql_proxy https://dl.google.com/cloudsql/cloud_sql_proxy.darwin.arm64
chmod +x cloud_sql_proxy

3. PostgreSQL インスタンスを作成

以下に置き換えてください
INSTANCE_NAME: Cloud SQL インスタンス名
PROJECT_ID: Google Cloud プロジェクト ID
REGION: Google Cloud リージョン

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

作成したインスタンス内に、データベースを作成

terminal
gcloud sql databases create DATABASE_NAME \
    --instance INSTANCE_NAME

データベース ユーザーを作成

terminal
gcloud sql users create DATABASE_USERNAME \
    --instance INSTANCE_NAME \
    --password DATABASE_PASSWORD

4. Cloud Storage バケットを設定

terminal
gsutil mb -l REGION gs://PROJECT_ID_MEDIA_BUCKET

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

terminal
echo DATABASE_URL=postgres://DATABASE_USERNAME:DATABASE_PASSWORD@//cloudsql/PROJECT_ID:REGION:INSTANCE_NAME/DATABASE_NAME > .env
echo GS_BUCKET_NAME=PROJECT_ID_MEDIA_BUCKET >> .env
echo SECRET_KEY=$(cat /dev/urandom | LC_ALL=C tr -dc '[:alpha:]'| fold -w 50 | head -n1) >> .env
echo PROJECTNUM=$(gcloud projects describe PROJECT_ID --format='value(projectNumber)') >> .env

6. シークレットをSecret Managerに保存

terminal
gcloud secrets create django_settings --data-file .env

7. 動作確認

settings.pyに以下を追加していきます

DJANGO_NINJA_TEMPLETE/settings.py
import io
import os
import environ
from pathlib import Path
from datetime import timedelta

import google.auth
from google.cloud import secretmanager
from google.oauth2 import service_account
from datetime import timedelta
from pathlib import Path
from storages.backends.gcloud import GoogleCloudStorage
DJANGO_NINJA_TEMPLETE/settings.py
env = environ.Env(DEBUG=(bool, True))
env_file = os.path.join(BASE_DIR, ".env")

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

if os.path.isfile(env_file):
    print('Use a local secret file, if provided')
    env.read_env(env_file)
    service_account_json = get_or_create_service_account_json(BASE_DIR)
    credentials = service_account.Credentials.from_service_account_info(service_account_json)
elif os.environ.get("GOOGLE_CLOUD_PROJECT", None):
    print('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))
elif os.getenv("TRAMPOLINE_CI", False):
    print('Create local settings if running with CI, for unit testing')
    placeholder = (
        f"SECRET_KEY=a\n"
        "GS_BUCKET_NAME=None\n"
        f"DATABASE_URL=sqlite://{os.path.join(BASE_DIR, 'db.sqlite3')}"
    )
    env.read_env(io.StringIO(placeholder))
    service_account_json = get_or_create_service_account_json(BASE_DIR)
    credentials = service_account.Credentials.from_service_account_info(service_account_json)
else:
    raise Exception("No local .env or GOOGLE_CLOUD_PROJECT detected. No secrets found.")

SECRET_KEY = os.getenv('SECRET_KEY')

DJANGO_NINJA_TEMPLETEにutils.pyを追加

DJANGO_NINJA_TEMPLETE/utils.py
import json
import os

from google.cloud import secretmanager


def get_service_account_json():
    project_num = os.environ.get("PROJECTNUM")

    client = secretmanager.SecretManagerServiceClient()
    name = f"projects/{project_num}/secrets/service_account/versions/latest"
    response = client.access_secret_version(name=name)
    secret_string = response.payload.data.decode("UTF-8")
    return json.loads(secret_string)


def get_service_account_json_from_file(json_file_path):
    with open(json_file_path, "r") as json_file:
        return json.load(json_file)


def store_service_account_json_to_file(json_data, json_file_path):
    with open(json_file_path, "w") as json_file:
        json.dump(json_data, json_file)


def get_or_create_service_account_json(base_dir):
    json_file_path = os.path.join(base_dir, "static", "service_account.json")

    if os.path.isfile(json_file_path):
        return get_service_account_json_from_file(json_file_path)

    json_data = get_service_account_json()
    store_service_account_json_to_file(json_data, json_file_path)

    return json_data

GCPでサービスアカウントを作成し、シークレットキーを作成します
https://cloud.google.com/iam/docs/creating-managing-service-account-keys?hl=ja

Secret Managerを開き、『service_account』という名のシークレットを作成し、上記で作成したJSONの内容を追加してください。
https://console.cloud.google.com/security/secret-manager

Cloud Proxyを起動

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

次にstaticというフォルダを作成し、以下のコマンドを実行し、Djangoを起動します

terminal
python manage.py makemigrations
python manage.py migrate
python manage.py collectstatic
python manage.py runserver

立ち上がれば一旦OK!!

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?