コンテンツにスキップ

Tutorial - Simple Django Project

ここでは、Lambda + Neon + S3でDjangoプロジェクトを動かします。 Admin画面を確認することが目標です。

事前準備

rye, AWS, Neon

Rye

magic-pocketは、PyPIからインストール可能です。 ここでは、ryeを利用します。 他のツールを使う場合、コマンドを適宜調整してください。 ryeを使ったことがない場合、uvの方が良いかもしれません。 ryeからuvへの移行方法が分かり次第、ドキュメントはuvに変更される予定です。

Aws

AWSアカウントが必要です。

credentialsは、~/.aws/credentialsへの設定を想定しています。

boto3からAWSを操作しますが、credentialsを直接読み込むことはしないので、boto3の設定を参考に設定してください。

Neon

Neonアカウントが必要です。

APIキーは、NEON_API_KEYという環境変数で設定してください。

チュートリアルに沿えば、.envで設定できます。

Djangoプロジェクトの作成

プロジェクト名について

pocketをプロジェクト名に含めない
pocketというprefixをつけてリソースを作成するため、prefixかプロジェクト名か分からず、混乱します。
他のmagic-pocketプロジェクトとコンフリクトさせない
自分の名前などを入れてください。 プロジェクト名から自動生成させるS3バケット名(1)がコンフリクトしてエラーになります。 pocketなどの名前は動かないかもしれません(2)。
  1. pocketというプレフィックスが付くので、通常はコンフリクトしません。この値は、pocket.tomlで直接指定も可能ですが、チュートリアルでは、プロジェクト名で対応してください。
  2. 実際は、pocketという名称はS3の問題ではなく動きません。magic-pocketのpocketディレクトリよりも、プロジェクトディレクトリがimportで優先されるためです。
# global django (1)
rye install django
django-admin startproject `your-project-name`
cd `your-project-name`
rye pin 3.12
rye init --virtual
  1. django-adminコマンドを利用するため、グローバルにdjangoをインストールします。

Djangoのインストールとrunserver

# project django(1)
rye add django
python manage.py migrate
# runserver(2)
python manage.py runserver
  1. プロジェクトにdjangoを追加します。
  2. localhost:8000でdjangoが動いていることを確認してください。

django-environとpsycopgのインストール

rye add django-environ psycopg
Lambda環境はデフォルトでlinux/amd64です

macで開発している場合、rye add "psycopg[binary]"とする必要があるかもしれません。

maginc-pocketのインストール

rye add magic-pocket

pocket django initの実行

以下のコマンドは、シンプルなデプロイ設定を生成します。

実行前のコミットをお勧めします

settings.pyの差分確認(1)のため、git commitをしておくことをお勧めします。 チュートリアル通りに進めていれば、.gitignoreにはdb.sqlite3を追加してください。

コマンド実行時に生成される.envも、ついでに.gitignoreに追加しておくと良いでしょう。

  1. 以下に差分は記載しますが、手元で確認できたほうが安心かと思います。
rye run pocket django init

このコマンドにより、以下のファイルが生成されます。

  • pocket.toml, pocket.Dockerfile, .envが生成され、新規保存されます。
  • settings.pyが生成され、上書きされます。
チュートリアル通りに実行していない場合の注意点
djagno-environ

django-environがない場合、.envsettings.pyは作成されません。 環境変数としてしか取得できないデータがあるので、チュートリアルでは、django-environを利用したsettings.pyを作成することをお勧めします。

pocket.toml

ap-southeast-1リージョン(1)で、devとprodの2つのステージを持つプロジェクトの設定ファイルです。

  1. Neonが存在するリージョンを設定してください。
[general]
region = "ap-southeast-1" # (1)!
stages = ["dev", "prod"] # (2)!

[s3] # (3)!

[neon] # (4)!

[awscontainer] # (5)!
dockerfile_path = "pocket.Dockerfile" # (6)!

[awscontainer.handlers.wsgi] # (7)!
command = "pocket.django.lambda_handlers.wsgi_handler"
[awscontainer.handlers.management] # (8)!
command = "pocket.django.lambda_handlers.management_command_handler"
timeout = 600

[dev.awscontainer.handlers.wsgi] # (9)!
apigateway = {}
[prod.awscontainer.handlers.wsgi]
apigateway = {}

[awscontainer.secretsmanager.pocket_secrets] # (10)!
SECRET_KEY = { type = "password", options = { length = 50 } }
DJANGO_SUPERUSER_PASSWORD = { type = "password", options = { length = 16 } }
DATABASE_URL = { type = "neon_database_url" }

[awscontainer.django.storages] # (11)!
default = { store = "s3", location = "media" }
staticfiles = { store = "s3", location = "static", static = true, manifest = true }
  1. :man_raising_hand: ap-southeast-1リージョンでリソースは作成されます。Neonが使えるリージョンを指定してください。
  2. devprodの2つのステージが指定可能です。
  3. S3バケットを作成します。名前は指定されていないので、プロジェクト名とステージ名から自動生成されます。
  4. Neonデータベースが作成されます。名前はプロジェクト名とステージ名から自動生成されます。
  5. Lambdaコンテナイメージを作成します。ECRリポジトリ名はプロジェクト名とステージ名から自動生成されます。
  6. Lambdaコンテナを作成する、Dockerfileのパスを指定します。
  7. wsgiという名前で、wsgiを実行するLambda関数が作成されます。
  8. managementという名前で、マネジメントコマンドを実行するLambda関数が作成されます。timeoutは600秒です。
  9. devprodのwsgiにapigatewayが設定されます。URLはAWS側で自動生成されます。項目を分けているのは、apigateway = { domain = "example.com" }のように、ドメインを指定をするためです。Route53のホストゾーンがあれば、自動設定可能です。外部の設定を用いる場合、CloudFomationがDNSレコードの認証待ちになります。
  10. SECRET_KEY、DJANGO_SUPERUSER_PASSWORD、DATABASE_URL が自動生成され secretsmanager に保存されます
  11. S3 に default と static のディレクトリが作成され、settings.py を通じて簡単に、django の settings.STORAGES 形式で読み込めます。

pocket.Dockerfile

Lambda対応のDockerfileを生成します(1)。

  1. どういうライブラリが動かないのか、良く分かっていません。動かないライブラリがあれば、issueに投げてください。
ARG PYTHON_VERSION=3.12
FROM public.ecr.aws/docker/library/python:${PYTHON_VERSION}-slim AS base

FROM base AS builder
COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
ENV PYTHONDONTWRITEBYTECODE=1 \
    PYTHONUNBUFFERED=1 \
    VIRTUAL_ENV=/venv \
    UV_PROJECT_ENVIRONMENT=/venv \
    PATH="/venv/bin:${PATH}"
WORKDIR /app

RUN uv venv $VIRTUAL_ENV
COPY uv.lock pyproject.toml ./
RUN uv sync --frozen --no-dev --no-install-project

FROM base AS final
ENV PYTHONDONTWRITEBYTECODE=1 \
    PYTHONUNBUFFERED=1 \
    VIRTUAL_ENV=/venv \
    PATH="/venv/bin:${PATH}"
WORKDIR /app
COPY --from=builder /venv /venv
COPY . .

ENTRYPOINT [ "/venv/bin/python", "-m", "awslambdaric" ]

.env

ローカル環境用の設定ファイルです

このファイルは、ローカルでDjangoを動かすための設定ファイルです。 デプロイ時には、これらの変数はsecretsmanager経由で取得されるため、デプロイ環境を動かすだけなら、.envは不要です。

以下の内容で生成されます。

DEBUG=true
# secret (1)
SECRET_KEY=`random-secret-key`
DATABASE_URL=sqlite:///db.sqlite3
  1. DjangoのSECRET_KEY生成の仕組みを利用して、毎回異なる値が出力されます。

settings.py

以下の修正が適用されたsettings.pyが生成されます。

  • SECRET_KEY, ALLOWED_HOSTS, DATABASES, DEBUGを環境変数から読み込ませるように修正します。デプロイ時にはSecretsManager経由、ローカルでは.env経由で取得します。
  • STORAGES, CACHESpocket.tomlから読み込む形に修正します。

追加されるコードは以下になります。

from pocket.django.runtime import set_envs
from pocket.django.utils import get_caches, get_storages

STORAGES = get_storages()
CACHES = get_caches()

environ.Env.read_env(BASE_DIR / ".env")
env = environ.Env(
    SECRET_KEY=str,
    DEBUG=(bool, False),
    ALLOWED_HOSTS=(list, []),
)

set_envs()
SECRET_KEY = env.str("SECRET_KEY")
DEBUG = env.bool("DEBUG")
DATABASES = {"default": env.db()}
ALLOWED_HOSTS = env.list("ALLOWED_HOSTS")

deploy

NEON_API_KEYがローカル環境に必要です

deployコマンドを実行する環境には、NEON_API_KEYを設定する必要があります。(1)

$ NEON_API_KEY=key rye run pocket deploy --stage=dev

という形でCLI実行時に指定も可能ですが、magic-pocketはデフォルトで.envを見に行きます。 ここまでで、.envが出来ているはずなので、.envに設定するのが楽だと思います。

django-environとmagic-pocketの.env読み込み機能は別実装です

.envがあるので追加すれば良いのですが、このチュートリアルでsettings.py.envを読みこんでいるのは、django-environへの設定です。 magic-pocketは、django-environや上記settings.pyの設定がない場合でも、NEON_API_KEYを取得するためデフォルトで.envを利用します。

  1. Lambda環境では不要です。magic-pocketはデプロイ時にNEONのデータベース情報を読み込み、SecretsManagerに登録します。Lambda環境では、その値を環境変数として接続情報を取得できます。

dev

以下のコマンドでdev環境へのデプロイと、djangoの初期設定を行います。

pocket deploy --stage=dev
pocket django manage migrate --stage=dev
pocket django manage collectstatic --noinput --stage=dev
pocket django manage createsuperuser --username=admin --email=admin@example.com --noinput --stage=dev

SECRET_KEYDJANGO_SUPERUSER_PASSWORDDATABASE_URL は、自動生成されSecretsManagerに保存されます。その値はsettings.pyで取得されます。

自動生成されたシークレットは、以下で確認できます。

pocket resource awscontainer secretsmanager list --stage dev --show-values

prod

devをprodに変えるだけです。環境やシークレットは全て別になります。

pocket deploy --stage=prod
pocket django manage migrate --stage=prod
pocket django manage collectstatic --noinput --stage=prod
pocket django manage createsuperuser --username=admin --email=admin@example.com --noinput --stage=prod