見出し画像

Django+Docker+PostgreSQLへの接続をpgfileで設定する

DjangoでDB接続設定を書く場合、 settings.py にDATABASEの設定を行うことになりますが、平文でパスワードを置いてしまうとGitHubでソース管理がしづらくなってしまいます。
.env に記載する方法もありますが、下記ページにある通り、pgpassに設定する方法を試したので、備忘録を兼ねて記録を残します。

今回の環境

  • python:3.9

  • django:4.0

django作業環境の作成

poetryを使用します。
djangoでのPostgreSQLへの接続は psycopg2 が必要なので、パッケージに追加しておきます。(psycopg3はdjango 4.0では未対応)

# 作業ディレクトリを任意の場所に作成します
mkdir ~/django-test

# poetryをインストールしていない場合
pip install poetry

poetry init # project.tomlを作成するための質問に答えます

# [tool.poetry]
# name = "django-test"
# version = "0.1.0"
# description = ""
# authors = ["DecoPon"]

# [tool.poetry.dependencies]
# python = "^3.9,<=3.10"

# [tool.poetry.dev-dependencies]

# [build-system]
# requires = ["poetry-core>=1.0.0"]
# build-backend = "poetry.core.masonry.api"

# packageを追加
poetry add django
poetry add psycopg2

# packageをインストールし、仮想環境を作成する
poetry install

djangoプロジェクトを作成します。

poetry run django-admin startproject mysite

# projectが作成されていると以下のようになっているはず
django-test
|-mysite
|-poetry.lock
|-pyproject.toml

今回はdocker-composeでpostgresqlとの連携を行うため、Dockerfileとdocker-compose.ymlを追加します。

Dockerfileはpostgresqlとの接続確認を行う為にpostgresql-clientをインストールしておきます。また、docker内のpython環境で先ほど作成したpoetry設定を流用してパッケージをインストールする為、poetryをインストールし、仮想環境ではなく、直接インストールする設定を入れておきます。

FROM python:3.9

RUN apt -y update && apt -y upgrade
RUN apt -y install postgresql-client

ENV PIP_NO_CACHE_DIR=off

RUN pip install poetry

WORKDIR /app
COPY ./pyproject.toml ./

RUN poetry config virtualenvs.create false
RUN poetry install

CMD ["bash"]

docker-compose.ymlを作成します。
(今回は検証なので、開発用としてwsgiなどは設定しません。)

version: "3.9"
services:
  web:
    build:
      context: .
    container_name: web
    restart: unless-stopped
    tty: true
    working_dir: /opt/apps
    volumes:
      - ./mysite:/opt/apps/
      - .pgpass:/root/.pgpass
      - .pg_service.conf:/root/.pg_service.conf
    entrypoint: "./entrypoint.sh"
    command: "python manage.py runserver 0.0.0.0:8000"
    ports:
      - "8000:8000"
    depends_on:
      - db
  db:
    image: postgres
    container_name: db
    environment:
      POSTGRES_USER: ${DB_USER}
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    ports:
      - ${DB_PORT}:5432

docker-compose.ymlでpostgresqlのパスワード等を含めたくないため、.envに切り出します。
.env

DB_USER=postgres
DB_PASSWORD=postgres
DB_HOST=db
DB_PORT=5432

ここまでで以下のようなフォルダ構成になっているはずです。

django-test
├── Dockerfile
├── docker-compose.yml
├── mysite
│   ├── manage.py
│   └── mysite
│       ├── __init__.py
│       ├── asgi.py
│       ├── settings.py
│       ├── urls.py
│       └── wsgi.py
├── poetry.lock
└── pyproject.toml

次に、PostgreSQLへの接続情報を追加します。
.pg_service.conf と .pgpass の2ファイルを追加します。
これらのファイルは通常、ホームディレクトリに配置する為、docker-compose.yml上でコンテナホーム(rootディレクトリ)にマウントしています。

.pg_service.conf

[DB]
host=db
user=postgres
dbname=postgres
port=5432

今回はdockerコンテナ同士での接続のため、 host には docker-compose.ymlで指定したサービス名を設定します。

.pgpass

# hostname:port:database:username:password の順番で記載する
db:5432:postgres:postgres:postgres

.pg_service.conf と .pgpass は上記リンクにある通り、 600 のパーミッションが設定されていなければ無視されます。

Unixシステムにおいて、.pgpassの権限はグループ、他者へのアクセスをすべて拒否しなければなりません。 これはchmod 0600 ~/.pgpassといったコマンドによって行います。 権限をこれよりも緩くすると、このファイルは無視されます。 Microsoft Windowsにおいては、このファイルが安全なディレクトリに格納されていることを前提としていますので、特別に行われる権限の検査はありません。

https://www.postgresql.jp/document/9.3/html/libpq-pgpass.html

今回はコンテナにマウントする為、ホスト側で変更しても良いですが、念の為、entrypointにより、処理するようにします。
entrypoint.sh を mysite 内(manage.pyと同じ階層)に作成します。

#!/bin/bash
set -e

chmod 600 /root/.pg_service.conf
chmod 600 /root/.pgpass

cmd="$@"
exec $cmd

ここまでで、以下のディレクトリ構成になります。

django-test
├── .env
├── .pg_service.conf
├── .pgpass
├── Dockerfile
├── docker-compose.yml
├── mysite
│   ├── db.sqlite3
│   ├── entrypoint.sh
│   ├── manage.py
│   └── mysite
├── poetry.lock
└── pyproject.toml

標準ではdjangoはsqlite3を使用する設定になっているので、PostgreSQLを使用するように設定を変更します。
django_tutorial/mysite/mysite/settings.py の以下の部分を編集します。

# 元
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}

# 変更後
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'OPTIONS': {
            'service': 'DB', #.pg_service.conf のサービス名
            'passfile': '/root/.pgpass', #パスワードファイル (.pgpass)パスを指定
        },
    }
}

コンテナを作成します。
ログを確認し、以下のように問題なければ、ctrl + c で表示を終了します。

docker compose up -d

[+] Running 2/2
 ⠿ Container db   Running                                                                                                                                                                                                   0.0s
 ⠿ Container web  Started

# ログを確認し、以下のような表示になっていればdjangoコンテナ(web)が正常に起動しています
docker compose logs -f web # -f オプションはログの常時表示
web  | You have 18 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
web  | Run 'python manage.py migrate' to apply them.
web  | April 24, 2022 - 03:12:22
web  | Django version 4.0.4, using settings 'mysite.settings'
web  | Starting development server at http://0.0.0.0:8000/

マイグレーションを行い、PostgreSQLにdjango関連のテーブルができていることを確認します。

# migration
docker compose exec web python manage.py migrate

# Output
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying auth.0012_alter_user_first_name_max_length... OK
  Applying sessions.0001_initial... OK

コンテナからPostgreSQLに接続し、テーブルができていることを確認します。

docker compose exec web psql -h db -p 5432 -U postgres -d postgres                                                                                             ✔  django-test   12:20:11# output
psql (13.5 (Debian 13.5-0+deb11u1), server 14.1 (Debian 14.1-1.pgdg110+1))
WARNING: psql major version 13, server major version 14.
         Some psql features might not work.
Type "help" for help.

# djangoテーブルが作成されていることを確認
postgres=# \dt
                   List of relations
 Schema |            Name            | Type  |  Owner   
--------+----------------------------+-------+----------
 public | auth_group                 | table | postgres
 public | auth_group_permissions     | table | postgres
 public | auth_permission            | table | postgres
 public | auth_user                  | table | postgres
 public | auth_user_groups           | table | postgres
 public | auth_user_user_permissions | table | postgres
 public | django_admin_log           | table | postgres
 public | django_content_type        | table | postgres
 public | django_migrations          | table | postgres
 public | django_session             | table | postgres
(10 rows)

WEBで調べても、settings.pyに直書きする方法ばかりヒットするので、備忘録を兼ねて作成しました。
おつかれさまでした。


この記事が気に入ったらサポートをしてみませんか?