nikkie-ftnextの日記

イベントレポートや読書メモを発信

Djangoの開発でWebアプリとDB(postgreSQL)の両方をdocker compose upで動かす

はじめに

祝・壮瞥町コラボ👏 英国コラボもきっとあるよね? nikkieです。

DBだけでなく、Djangoアプリもdocker compose upで動かすというテーマに取り組みました。
まだまだ突き詰められる余地があるのですが、一度セーブポイントを作ります

目次

これまで:DBだけdocker compose up

これまではDBのDockerイメージだけをdocker compose up -dしてきました。
WebアプリはDockerを使わずに、Pythonの環境(仮想環境利用)でpython manage.py runserverを叩きます。

DBを立ち上げるためのdocker-compose.ymlはこちら

version: '3.9'

services:
  db:
    image: postgres:15.3
    environment:
      - POSTGRES_DB=badapp
      - POSTGRES_USER=developer
      - POSTGRES_PASSWORD=mysecretpassword
    volumes:
      - ./data/db:/var/lib/postgresql/data
    ports:
      - "5432:5432"

ここから始めて、docker compose up -dでWebアプリもDBも立ち上がるようにします。

ドキュメントの例

Dockerのドキュメントには有志による日本語版が存在します。
https://matsuand.github.io/docs.docker.jp.onthefly/
日本語版ではこちら

英語版では以下にあたるようです: https://github.com/docker/awesome-compose/tree/e6b1d2755f2f72a363fc346e52dce10cace846c8/official-documentation-samples/django

この例では

  • DjangoをインストールしたDockerイメージをビルドし
  • それをweb、postgreSQLイメージをdbとしてdocker-compose.ymlを定義

します。
そしてdocker-compose run webDjango開発コマンドを渡して、プロジェクト(さらにアプリケーション)と作っていきます1
例はロケットの画面を出して終了します。

仮想環境で動かしていたDjangoアプリをdocker compose upで動かせるようにする

以下のエントリのソースコードSQLインジェクションできちゃうDjangoアプリ)を元にします

目指すのはdocker compose up -dDjangoアプリもDBも立ち上がる状態。

マルチステージビルドする、でしょ!

ドキュメントの例よりもサイズが小さく取り回しやすいDockerイメージを作るべく、マルチステージビルドしていきます。

FROM python:3.11-bookworm as builder
WORKDIR /code
COPY requirements.lock /code/
RUN pip install --no-cache-dir -r requirements.lock

FROM python:3.11-bookworm
WORKDIR /code
COPY --from=builder /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages
COPY bad_sql_injection /code/
  • requirements.lockに沿って依存ライブラリをインストールしたイメージに、DjangoアプリのソースコードをCOPYしました
  • 本当はslimイメージを使いたいのですが、psycopg22が動かなかったのでslimでないイメージにしています(宿題)

docker-compose.yml

元々あったservicesのdbの定義に加えて、webも定義します

version: '3.9'

services:
  db:
    image: postgres:15.3
    environment:
      - POSTGRES_DB=badapp
      - POSTGRES_USER=developer
      - POSTGRES_PASSWORD=mysecretpassword
    volumes:
      - ./data/db:/var/lib/postgresql/data
    ports:
      - "5432:5432"
+  web:
+    build:
+      context: .
+      dockerfile: Dockerfile
+    command: ["python", "manage.py", "runserver", "0.0.0.0:8000"]
+    ports:
+      - "8000:8000"
+    depends_on:
+      - db

これで動きました。
docker compose upしてから http://127.0.0.1:8000/todolist/ にアクセスします

宿題事項

ですが、動いているのは私の環境だから(Dockerを導入する前に仮想環境で動かしているから)です。
リポジトリをcloneした人の手元でdocker compose upで済ますにはいくつか宿題が残っています。

  • django-environを使っていますが、.envファイルもイメージの中にCOPYしてしまっています
    • リポジトリをcloneした人も.envファイルを作ればいいのですが、他の解き方も模索したいです
  • 私の環境はDBにmigrate済みでした
    • docker compose run webpython manage.py migrateを都度叩く必要があります
  • 私の環境には、postgreSQLが参照しているファイルがすでにあります(migrateしたDBスキーマやデータがある)
    • postgreSQLが参照するフォルダ(docker-compose.ymlのvolumes)を消してから立ち上げると、うまくいったりいかなかったりします(ガチャだ!!)
    • DBが参照するファイルができあがる前にwebが動くとDBへの接続エラーとなり、DBは立ち上がったがwebは立ち上がりに失敗し落ちた状態になります
    • この状態からはdocker compose downdocker compose upを繰り返してwebもdbも両方立ち上がった状態に持っていっています(もっといいやり方が絶対あるはず!)

エントリ執筆時点で試行錯誤中でして、「これ!」という解決策が見つかったら別途エントリを執筆予定です

終わりに

ドキュメントに沿って、Django製WebアプリとDBをdocker compose upで動かしました。

  • クイックスタートのドキュメントを参考に動かした
  • サイズの小さなイメージがほしくてマルチステージビルドを実施
  • 別の開発者が環境構築するとき、DBのボリュームがない状態から始めて、DB -> Webアプリの順で立ち上げ、アプリにmigrateする手順の自動化が宿題事項

立ち上げる順番の指定や、Webアプリが立ち上がった後のコマンド実行を引き続き調べていきます!


  1. 何年も前にRailsチュートリアルをDockerで試みたときのことを思い出しました
  2. psycopg3も登場しています。https://pypi.org/project/psycopg/ 3にしたほうがいいのかな?