【環境構築】PythonとNext.jsで分断型Webサイトの下準備

2023年3月17日

ChatGPT、激アツですね。
ここ最近はAIに頼りっきりな私です。
情報の鮮度は落ちやすく賞味期限が短くなっているのを日々感じます。

ちょっと前まで参考にしていた記事も、ときを経てそのとおりに環境構築すると「やれ、依存関係が」とか「やれ、そのバージョンは非推奨だぜ」などと罵倒されるわけです。

なので時代の潮流にうまく乗るとすれば
・体系的にキャッチアップするには「ググる」
・補完してくれる秘書としてAI(ChatGPT)
という距離感で学習を進めるのが効率が良いように感じてます。

さて、今回は

サーバーサイドはPython
フロントサイドはNext.js(React)

というサーバー側とフロント側を分断した形でWebサイトの基盤を構築していこうと思います。
様々な記事を参考にしながら、不都合があったり、情報が不足する箇所をChatGPTという秘書に相談しながら進めたものになります。

Docker関連ファイルの準備

docker-compose.yml

version: "3"

services:
  app:
    build:
      context: .
    ports:
      - "8080:8000"
    volumes:
      - ./app:/app
    command: sh -c "python manage.py migrate &&
      python manage.py runserver 0.0.0.0:8000"
    environment:
      - FRONT_URI=http://localhost:3000
      - ALLOWED_HOST=localhost
      - DB_HOST=db
      - DB_NAME=app
      - DB_USER=postgres
      - DB_PASS=supersecretpassword
    depends_on:
      - db

  db:
    image: postgres:10-alpine
    environment:
      - POSTGRES_DB=app
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=supersecretpassword
      - POSTGRES_HOST_AUTH_METHOD=trust

  next:
    build:
      context: .
      dockerfile: "./Dockerfile-nodejs"
    volumes:
      - ./frontend:/frontend
    command: sh -c "npm run dev"
    ports:
      - "3000:3000"

Dockerfile

FROM python@sha256:73c7d5d218ff9e2d76f41edcc1bd4f71961f7551ea7b2e39ab8b4793cede21b4

ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1

COPY ./requirements.txt /requirements.txt
RUN apk add --update --no-cache postgresql-client jpeg-dev
RUN apk add --update --no-cache --virtual .tmp-build-deps \
    gcc libc-dev linux-headers postgresql-dev musl-dev zlib zlib-dev
RUN pip install -r /requirements.txt
RUN apk del .tmp-build-deps

RUN mkdir /app
WORKDIR /app
COPY ./app /app

RUN mkdir -p /vol/web/media
RUN mkdir -p /vol/web/static
RUN adduser -D user
RUN chown -R user:user /vol/
RUN chmod -R 755 /vol/web
USER user

CMD sh -c "python manage.py migrate --settings app.prod_settings && python manage.py runserver 0.0.0.0:8000 --settings app.prod_settings"

補足
M1のMacを使用しているPythonはamd64製を取得するよう固定しています。

以下はDockerファイルで何をしているかの補足

ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
環境変数を設定しています。これらは、Pythonのバイトコード生成を無効にし、Pythonの標準出力をバッファリングしないようにするものです。
COPY ./requirements.txt /requirements.txt
ホストマシンのrequirements.txtファイルをDockerコンテナ内にコピーしています・
RUN apk add --update --no-cache postgresql-client jpeg-dev
RUN apk add --update --no-cache --virtual .tmp-build-deps \
    gcc libc-dev linux-headers postgresql-dev musl-dev zlib zlib-dev
コンテナ内に必要なパッケージをインストールしています。ここでは、PostgreSQLクライアント、JPEGライブラリ、PostgreSQL開発ヘッダ、Zlibなどが含まれています。
RUN pip install -r /requirements.txt
requirements.txtに含まれるパッケージをpipを使用してインストールしています。
RUN mkdir /app
WORKDIR /app
COPY ./app /app
アプリケーション用のディレクトリを作成し、そこにアプリケーションをコピーしています。
RUN mkdir -p /vol/web/media
RUN mkdir -p /vol/web/static
マウント用のディレクトリを作成しています。ここでは、アプリケーションで使用されるメディアファイルと静的ファイル用のディレクトリを作成しています。
RUN adduser -D user
ユーザーを追加しています。
RUN chown -R user:user /vol/
作成したボリュームを新規ユーザーに所有権を付与しています。
RUN chmod -R 755 /vol/web
ボリュームのパーミッションを変更して、ユーザーに書き込みと実行の権限を与えています。
SER user
CMD sh -c "python manage.py migrate --settings app.prod_settings && python manage.py runserver 0.0
最後に、コンテナの実行時に実行されるコマンドを設定しています。ここでは、マイグレーションを実行して、サーバーを起動しています。

Dockerfile-nodejs

FROM node:16.8.0-alpine

RUN npm config set unsafe-perm true
RUN npm install -g npm@7.15.1
RUN npm install -g create-next-app
RUN mkdir /frontend

WORKDIR /frontend
COPY ./frontend /frontend

CMD sh -c "npm run start"

補足
nextのインストールの際にnodeやnpmのバージョンで怒られることがあるので両者ともにバージョンを指定します。

Makefile

.PHONY:
	app test migrate pro admin django react 

api:
	docker-compose run --rm app sh -c "python manage.py startapp api"

migrate:
	docker-compose run --rm app sh -c "python manage.py makemigrations --settings app.dev_settings"
	docker-compose run --rm app sh -c "python manage.py migrate --settings app.dev_settings"

admin:
	docker-compose run --rm app sh -c "python manage.py createsuperuser --settings app.dev_settings"

django:
	docker-compose run --rm app sh -c "django-admin startproject app ."

next:
	docker-compose run --rm next sh -c "npx create-next-app . --ts"

django-test:
	docker-compose run --rm app sh -c "python manage.py test --settings app.dev_settings"

一つコマンドを掻い摘んで補足しておく。

docker-compose run --rm app sh -c "python manage.py createsuperuser --settings app.dev_settings"
docker-compose runは、Docker Composeを使用してDockerコンテナ内でコマンドを実行するためのコマンドです。
--rmは、コマンドが終了したらDockerコンテナを削除するように指示します。
appは、Docker Composeファイルで定義されたアプリケーションのサービス名です。
sh -cは、Dockerコンテナ内でシェルコマンドを実行するためのオプションです。
"python manage.py createsuperuser --settings app.dev_settings"は、Djangoのmanage.pyファイルを使用して、Djangoアプリケーション内でcreatesuperuserコマンドを実行するためのシェルコマンドです。 --settingsフラグは、app.dev_settingsという設定ファイルを使用するようにDjangoに指示します。
つまり、このコマンドはDocker Composeを使用してDjangoアプリケーションのコンテナ内で、createsuperuserコマンドを実行し、app.dev_settings設定ファイルを使用して新しいスーパーユーザーを作成することを目的としています。

コマンド実行

まずは必要なディレクトリから

mkdir app
mkdir frontend

そしてDocker関連ファイルのビルド

docker-compose build
docker-compose updocker-compose build の違い

docker-compose up: すでにビルドされたイメージを使用してコンテナを起動します。ビルドされたイメージがない場合は、自動的に docker-compose build を実行してからコンテナを起動します。

docker-compose build: ビルド設定に基づいて、Dockerfileを使ってイメージをビルドします。ビルドされたイメージはローカルにキャッシュされ、次回の docker-compose up の実行時に再利用されます。

つまり、docker-compose up はビルドされたイメージがあればすぐにコンテナを起動し、なければビルドを自動的に実行してからコンテナを起動します。一方、 docker-compose build は必ずイメージをビルドし、ローカルにキャッシュされたイメージを再利用せずにビルドを実行します。

ビルド時に何かしらのエラーでこけた際、Docker関連ファイルを修正後は下記コマンドでイメージを一旦すべて削除する。ライブラリが一部だけ入る状態はよろしくない。他のエラーを招く。
そして再度buildする。

docker-compose down --rmi all --volumes

Dockerで各コンテナのイメージができあがったら、あとは各コンテン上で必要なコマンドを流し込んでいく。

Next.jsのプロジェクトを作成

make next

Djangoのプロジェクトを作成

make django

作成されたDjangoプロジェクト配下にアプリケーションを追加

 make app

ここまでエラーなくできたら後は実行。

docker-compose up -d

あとはローカルのブラウザで
http://localhost:3000/

でフロントサイドのNext.jsの画面が立ち上がる

http://localhost:8080/

でサーバーサイドのPython(Django)の画面が立ち上がる

おつかれさまでした!