本エントリでは、Docker ComposeでPostgreSQLを立ち上げるとき、特定のデータベース・スキーマ配下にテーブルを作成する方法を紹介します。
前提としてのpostgresイメージの持つ自動SQL実行機能
データベースをもつシステムをローカルで開発するにあたり、Docker Composeを使ってDBを立ち上げるプロジェクトも多いのではないでしょうか。 そのとき、当然プロジェクトメンバに同じ環境を使ってほしいため、DDLを自動的に実行すると便利です。
DBMSとしてPostgreSQLを利用する場合、Dockerのイメージとしてはpostgresを使うことが多いでしょう。
このpostgresイメージでは、初期化タイミングにおいて、イメージ内の/docker-entrypoint-initdb.d
に配置されたスクリプトを自動実行する機能があります。
If you would like to do additional initialization in an image derived from this one, add one or more .sql, .sql.gz, or *.sh scripts under /docker-entrypoint-initdb.d (creating the directory if necessary).
上記の通り、拡張子として.sql
/.sql.gz
/.sh
のファイルがあれば自動実行してくれます。
僕はv14のbullseysを使っていますが、以下のような実装になっています。
services: db: image: postgres:14.4 restart: always ports: - 5432:5432 environment: # デフォルトのデータベース指定 POSTGRES_DB: 'your_database' volumes: # PostgreSQL 起動時に、sqls ディレクトリ内の SQL を自動実行 - ./sqls:/docker-entrypoint-initdb.d
対象データベース
上記の初期化処理における「対象とする(PostgreSQLの)データベース」は何になるでしょうか。
これはPOSTGRES_DB
という環境変数で制御されます。
この環境変数がセットされていた場合は、当該のデータベースが自動的に作成されます。セットされていなかった場合は、POSTGRES_USER
と同名のデータベースが設定されます。
This optional environment variable can be used to define a different name for the default database that is created when the image is first started. If it is not specified, then the value of POSTGRES_USER will be used.
POSTGRES_USER
が設定されていない場合の当該環境変数のデフォルト値はpostgres
なので、何も意識しないとpostgres
という名前のデータベースを利用することになります。
対象スキーマ
PostgreSQLにおけるスキーマは、データベースの下位概念です。postgres
イメージでは、対象とするスキーマを環境変数で設定することはできません。
課題
ここで何が課題になるかというと、「特定スキーマ」配下にテーブルがあることを前提としたアプリケーションを開発しているとき、それをDocker Composeでどう実現するかです。
上記の通り、対象の「データベース」は環境変数で制御できるとして、スキーマまで制御するためにはどうすればよいのでしょうか。
対応策
スキーマの自動作成
スキーマは自動的に作成されない[^1]ため、初期化スクリプトの中で明示的に作成する必要があります。
/docker-entrypoint-initdb.d
配下に.sql
ファイルを作成し、以下のような記述をすることになるでしょう。
-- データベースを切り替えた上で、スキーマを作成 \c your_database CREATE SCHEMA your_schema;
\c
は新しいコネクションを作成するメタコマンドです。
ユーザのデフォルトスキーマの変更
これだけではまだyour_schema
というスキーマが作られただけの状態です。
当該スキーマを対象とするためには、初期化を行うユーザのデフォルトスキーマを変更する必要があります。
デフォルトのスーパーユーザであるpostgres
ユーザを利用する場合、以下のような記述になるでしょう。
ALTER USER postgres SET search_path TO your_schema;
これにより、postgres
ユーザについては明示的にスキーマを指定しない限り、your_schema
スキーマを前提として処理を実行していきいます。
まとめ
結果として、以下のような記述を初期化スクリプトで実行しておけば、その後段で実行されるDDLは対象スキーマで実行される状況を作れます。
\c your_database CREATE SCHEMA your_schema; ALTER USER postgres SET search_path TO your_schema;