はじめに
Docker Hub公式PostgreSQL( https://hub.docker.com/_/postgres/ )で初期化ずみデータベースコンテナを作ります。
意外と日本語で書かれたものがなかったのでメモを残します。
環境
- Ubuntu 16.04
- Docker 1.12.1
PostgreSQLはすでに別環境にあって、それをまるっと載せたデータベースコンテナを作る想定。
手順
Dockerfileの準備
- 空ディレクトリ
~docker/postgres
を作成し、その中に以下のように記述したDockerfileを配置。
FROM postgres:9.3
RUN localedef -i ja_JP -c -f UTF-8 -A /usr/share/locale/locale.alias ja_JP.UTF-8
ENV LANG ja_JP.UTF-8
COPY *.sql /docker-entrypoint-initdb.d/
Postgresのバージョンは今別環境で使っているものとあわせたので9.3に。
RUNとENVはlocaleのために必要。
COPYで同じディレクトリにおいた初期化用の *.sql を imageの所定のディレクトリにコピーしている。
- 初期化用SQLを
docker/postgres
に配置。
公式Docker HubのPostgreSQLを使うと、 コンテナを作ったときに /docker-entrypoint-initdb.d/
の下の *.sh, *.sql, *.sql.gz が実行されます。なので、初期化用のsqlを一緒においておきます。
こちらはユーザ作成とデータベース作成だけやるSQL。
create role user1 login password 'user1';
create database user1;
grant all privileges on database user1 to user1;
こちらは既存のPostgreSQLのDBから$ pg_dump -U postgres -Fp user1
して作成したダンプ。ファイルの先頭にuser1 dbにつなぐための \c user1;
だけ追加してある。
\c user1;
--
-- PostgreSQL database dump
--
SET statement_timeout = 0;
SET lock_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SET check_function_bodies = false;
SET client_min_messages = warning;
--
-- Name: user1; Type: SCHEMA; Schema: -; Owner: user1
--
CREATE SCHEMA user1;
ALTER SCHEMA user1 OWNER TO user1;
-- 後略
ちなみにsqlファイル名の先頭に01とか02をつけているのは、実行を順番にしたいため。コンテナ作成時の初期化スクリプトで for f in /docker-entrypoint-initdb.d/*; do
しているので、数字をつけたら順番にやってくれるかな、という姑息な手段。
docker builld
~/docker/postgres
でビルド
$ docker build -t xxx/postgres .
Sending build context to Docker daemon 6.656 kB
Step 1 : FROM postgres:9.3
---> db4057098cc9
Step 2 : RUN localedef -i ja_JP -c -f UTF-8 -A /usr/share/locale/locale.alias ja_JP.UTF-8
---> Running in 3ad41c50d769
---> 427b06ac1197
Removing intermediate container 3ad41c50d769
Step 3 : ENV LANG ja_JP.UTF-8
---> Running in 27b2492a5365
---> ff2f1175f3d5
Removing intermediate container 27b2492a5365
Step 4 : COPY *.sql /docker-entrypoint-initdb.d/
---> 1e02da327a9f
Removing intermediate container 23e15cd44a29
Successfully built 1e02da327a9f
コンテナ作成
$ docker run -d --name postgres xxx/postgres
2131dcf553de2f67c0d9ae990d99c811de1b2dd8aa399204a34e65a6760e0947
コンテナ作成時に docker-entrypoint.sh が実行されて、initdb等が行われます。同時に、 /docker-entrypoint-initdb.d の下にある、 *.sh, *.sql, *.sql.gz が順次実行されています。
なので長いsqlを流した場合は docker run でプロンプトが返ってきてもまだ初期化中だったりします。
docker logs -f postgres
で見ていました。
コンテナの起動を確認。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2131dcf553de xxx/postgres "/docker-entrypoint.s" 10 minutes ago Up 10 minutes 5432/tcp postgres
初期化スクリプトで失敗するとコンテナはstopします。logsで原因を調べてファイルを修正して、コンテナとイメージを削除して( docker rm コンテナ名
, docker rmi イメージ名
) build からやり直し。
接続確認
user1 データベースに user1ユーザで接続して確認。
$ docker run -it --rm --link postgres:postgres xxx/postgres psql -h postgres -U user1 -n user1
psql (9.3.14)
Type "help" for help.
user1=> \d
List of relations
Schema | Name | Type | Owner
--------+--------------+----------+-------
user1 | distributors | table | user1
user1 | films | table | user1
user1 | serial | sequence | user1
(3 rows)
無事初期化できたようです。
そのほか
ちょっと困ったことなど。
psqlで日本語入らない
docker run で動かしたpsqlで日本語が入らなかったのですよ。
軽くぐぐったら
https://pasero.net/~mako/blog/s/229
にあたって、とりあえずpsqlに-nオプションを足したら日本語入りました。でもreadlineないと超不便。
create role多すぎた
これは元のDBの構成のせいですが、roleが多すぎて、記憶に頼ってcreate roleをぽちぽち書いていたら足りないユーザがいて、何度も初期化の途中でコケるはめに。最後は面倒になってpg_dumpのファイルから以下のようにしてcreate role文を作りました。
$ grep -e '^GRANT' 02_restore.sql |awk '{print $7}'|sort |uniq| sed -e "s/\(.*\);/create role \1 login password '\1';/g"
PUBLICとかpostgresとかが入っちゃったら削る必要があります。