やってみたこと
- 以前の記事でDjangoの開発環境を
docker-compose
を利用してコンテナで起動&DockerにPostgres環境を構築する方法を紹介しました。今回は、初期データ登録用のSQLを作成し、コンテナ起動時に自動で実行する手順を紹介します。
前提
- 前回までの記事はこちら
- DjangoチュートリアルをDockerから立ち上げてみた記事はこちら:Djangoの開発環境をdocker-composeを利用してコンテナで起動し、runserverコマンドでホスト側からアクセスする方法
- Djangoチュートリアルとpostgres環境を構築した記事はこちら:Djangoの開発環境をdocker-composeを利用してコンテナで起動&DockerにPostgres環境を構築する方法
- djangoチュートリアルでpollsアプリケーションを制作したmysiteプロジェクトを、以下ディレクトリ構造で配置(前回と同様)。
.
├── docker
│ ├── docker-compose.yml
│ └── Dockerfile
└── web
├── mysite
│ ├── mysite
│ ├── polls
│ ├── db.sqlite3
│ └── manage.py
└── requirements.txt
- djangoチュートリアルで作成したものをそのまま使っていますので、
settings.py
のDAEABASES
もそのままになっています。
settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
手順
①Dockerfileの準備
②docker-compose.ymlの準備
③Dockerコンテナの起動により自動実行
Dockerfileの準備
- Dockerfileは、前回記事と同様です。
# python:3.8の公式 image をベースの image として設定
FROM python:3.8
# 作業ディレクトリの作成
RUN mkdir /mysite
# 作業ディレクトリの設定(以後の RUN は WORKDIR で実行)
WORKDIR /mysite
# カレントディレクトリにある資産をコンテナ上の指定のディレクトリにコピーする
ADD web /mysite
# pipでrequirements.txtに指定されているパッケージを追加する
RUN pip install -r requirements.txt
# 起動(今回はなし)
# CMD python3 manage.py runserver 0.0.0.0:8000
-
requirements.txt
も前回記事同様、必要最低限のままにしています。
Django==4.1
requests
docker-compose.ymlの準備
-
docker-compose.yml
には以下のように記載します。
version: '3'
services:
mysite:
build:
context: ../
dockerfile: ./docker/Dockerfile
volumes:
- '../web:/mysite'
ports:
- "8000:8000"
container_name: docker_mysite
tty: true
working_dir: '/mysite'
db-sample1:
build:
context: ../
dockerfile: ./docker/sample1/Dockerfile
ports:
- "5438:5432"
container_name: mysite_sample1_db
environment:
POSTGRES_USER: user
POSTGRES_DB: sample
POSTGRES_PASSWORD: pass
volumes:
- postgres-data-volume:/var/lib/postgresql/data
- ./sql:/docker-entrypoint-initdb.d # ここを追加
volumes:
postgres-data-volume:
- これにより、Dockerコンテナ起動時に初回適用のSQLを自動的に実行することができます。
-
- ./sql:/docker-entrypoint-initdb.d
の行は、ホストマシンの./sql
ディレクトリ内にあるSQLファイルを、PostgreSQLコンテナの/docker-entrypoint-initdb.d
ディレクトリにマウントするように設定しています。 - 今回、
./sql
ディレクトリ内にあるSQLファイルは01_example.sql
で、テーブルを作成するコマンドを記載しました。
CREATE TABLE example01
(
id INTEGER PRIMARY KEY,
example_code varchar(255),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
deleted_at TIMESTAMPTZ
);
- ちなみに
docker-entrypoint-initdb.d
内に複数のスクリプトが存在する場合、名前の昇順で実行されます。依存関係がある場合は順番が大切になるので、ファイル名は01
とか頭に振っておくと良いです。 - サポートされている拡張子と動作は以下です。
-
.sh
: そのまま実行する -
.sql
:mysql
コマンドに流し込む -
.sql.gz
: 解凍してからmysql
コマンドに流し込む
-
Dockerコンテナの起動により自動実行
- Dockerコンテナが起動すると、
/docker-entrypoint-initdb.d
ディレクトリ内のSQLファイルが自動的にPostgreSQLによって実行されます。
$ docker compose up -d
- Dockerコンテナに入って、SQLが実行されているかDBを見てみましょう。
$ docker exec -it mysite_sample1_db bash
40befb0207ed:/# psql -U user -d sample
psql (11.18)
Type "help" for help.
sample=# \d
List of relations
Schema | Name | Type | Owner
--------+-------------+-------+-------
public | example01 | table | user
-
example01
テーブルが作成されていることがわかります。
ボリュームが残っている場合に、SQL実行は再度適用される?
- 2回目以降のコンテナ起動時にはSQLが再度実行されます。
- ただし、volumesに記載したボリュームが残っている場合、Dockerコンテナの起動時には既存のボリュームがマウントされます。ホスト上のファイルを更新した場合は古いボリュームを削除し、ボリュームのマウントからやり直す必要があります。
- したがって、初回実行する際には、上記の場合
postgres-data-volume
を削除する必要があります。ボリュームを削除するには、以下のコマンドを実行します。
$ docker volume rm postgres-data-volume
- ローカル環境といえど、削除して良いのかどうかはよく確認しましょう。場合によってはバックアップを取ることをお勧めします。
- 以下のコマンドで、Dockerホスト上で利用可能なすべてのボリュームのリストを表示できます。
$ docker volume ls
ボリュームを残したまま、再度SQLを実行したい場合は?
- 初回実行したいSQLが変わったら、一回一回ボリュームを削除する、という運用では大変ですよね。そのときは、以下の方法でSQL再適用が可能です。
- まず、DBのコンテナに入ります。
$ docker exec -it mysite_sample1_db bash
- その後、以下の
psql
コマンドで、マウントした01_example.sql
を実行します。-
psql
: PostgreSQLのコマンドラインクライアントで、SQLクエリを実行したり、PostgreSQLサーバーに接続したりするためのツールです。
-
$ psql -h localhost -U user -d sample -f /docker-entrypoint-initdb.d/01_example.sql
- 上記コマンドは以下を示しています。
-
-h localhost
: 接続先のホスト名を指定するオプション -
-U user
: 接続するユーザー名を指定するオプション -
-d sample
: 接続するデータベース名を指定するオプション -
-f /docker-entrypoint-initdb.d/01_example.sql
: SQLスクリプトを実行するオプション
-
- つまり、
user
というユーザーでsample
という名前のデータベースに対して、/docker-entrypoint-initdb.d/01_example.sql
に含まれるSQLクエリを実行することを意味します。 - これでボリュームを削除せずにSQLを再実行することができました。