とあるお兄さんの雑記

基本的に技術系の内容を書きますが、何を書くかは私の気分です。

DockerでPostgreSQLを立ち上げる

開発作業を行う際、Dockerのsql系イメージとDBUnitを使ってテストを作っていたので、練習がてらこちらの記事にも書いていきます。

バージョン関連

macOS Pro Monterey Apple M1
Docker 20.10.11, build dea9396
docker compose  v2.2.1
DBeaver 23.0.5

ディレクトリ構成

のちのちの記事でSpring Bootを使うので、それに見越したフォルダ構成にします。
おそらくみなさんの環境には何もないと思いますが、何はともあれ下記のようなフォルダ構成やファイルを今回の目標として進めていきます。

# DBUnitApplication/
└── docker
   ├── docker-compose.yml
   └── postgresql
      ├── Dockerfile
      ├── ddl
      │   └── book_ddl.sql
      └── dml
          └── book_dml.sql

docker-compose.ymlの中身

dockerディレクトリ配下にdocker-compose.ymlファイルを作成します。
中身は下記です。

version: '3'

services:
  postgresql:
    container_name: postgresql_container
    build: ./postgresql
    ports:
      - 5432:5432
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: passw0rd
      TZ: "Asia/Tokyo"
    restart: always

version

docker-composeで使用するバージョンを定義しています。詳細は公式ページとかをみてください(雑)。

services

アプリケーションを動かすための各要素。docker composeでは下記の例のように複数のコンテナを立てることができ、service以下に複数のコンテナを立てることができます。
ただ、今回はpostgresqlだけしかない状態です。

services
  db:
    〜〜
  web:
    〜〜
  app:

postgresql

正確にはservices内で作成するコンテナのことで、ここの名前はなんでもいいです。
今回はpostgresqlのイメージを使うので、postgresqlと書いただけでした。

container_name

コンテナを立ち上げた際のコンテナの名前です。postgresqlのコンテナなので、postgresql_containerとしています。

build

Dockerfileが置いてあるパスを指定します。今回はdocker-compose.ymlから見て、postgresqlディレクトリ配下のところに置いてあるDockerfileを参考にしています。

ports

ポートを指定します。指定の仕方はホスト:コンテナとなります
Dockerはコンテナを立てた後、そのコンテナと通信を行うためには外部から通信できるポートを指定しなければコンテナにアクセスすることができません。

今回、コンテナ内部でpostgresqlサーバを立てており、それはpostgresqlのデフォルトのポート番号5432で動いています。そのため、ホスト:コンテナのコンテナ部分はホスト:5432となります。

一方、ホスト部分は外部からあるポートで来たときに内部のpostgresqlサーバで5432に繋ぐようになっています。この時のホスト部分から繋ぐ番号はわかりやすく5432としておきましょう。
つまり、ホスト:5432ホスト部分が5432:5432となり、これで外部からポート番号5432で来た場合に、コンテナ内部のPostgresqlサーバにポート番号5432で繋ぐことができます。
(この辺りのポート番号の指定の仕方をしっかり理解しておきたい場合は、ホスト側の番号を変えると理解しやすくなるかと思います。)

environment

postgresqlのイメージを使う際には必須の設定になります。ここら辺の設定は他の記事を参考にしてください。

restart

コンテナを再起動するかどうかのオプションです。alwaysを設定した場合、コンテナが落ちた際は再起動するようになっています。
で、これが役に立つのは大体OSを再起動した時でしょうか。OSを再起動する場合はほとんどのアプリケーションを止めることになるので、OS再起動後にDocker側で自動でコンテナを再起動するようにするには、必要な設定になっています。

Dockerfileの中身

dockerディレクトリ > postgresqlディレクトリ配下にDockerfileを作成します。
中身は下記です。

FROM postgres:latest

COPY ./ddl/* /docker-entrypoint-initdb.d
COPY ./dml/* /docker-entrypoint-initdb.d

FROM イメージ名

FROM句でイメージ名を指定します。今回はpostgresqlの最新(latest)のイメージを利用します。

COPY 第一引数 第二引数

COPY句はDockerfileがあるパスから見て、第一引数にあるものをコンテナ内部の第二引数の部分にコピーする方法です。

ここでsql系のイメージを使う場合、コンテナが起動したと同時に、sql系のサーバに初期データなどを投入しておきたいなどがあるかと思います。
その場合、Dockerのsql系のイメージは大体docker-entrypoint-initdb.dというディレクトリがあります。
ここに必要なファイル(sqlファイル系)を配置するようにすると、コンテナ起動と同時に、必要な設定や初期データを自動で入れてくれます。

ddldmlフォルダの中身

そもそもddldmlについて話しておきましょう。

ddlとは、データ定義言語(DDL: Data Definition Language)のことで、SQLのCREATE TABLEステートメントなどを指します。
一方、dmlはデータ操作言語(DML: Data Manipulation Language)のことで、SELECT、UPDATE、DELETEステートメントなどを指します。

まぁ、一番最初のDBの枠を作るのがDDLで、具体的にデータの操作を行うのがDMLと覚えておけばいいでしょう。

ddlの中身

中身はシンプルで、ddlフォルダの中にbook_ddl.sqlファイルを置いてあるだけです。book_ddl.sqlの中身は下記になります。

-- DBの作成
create database db_books;

-- DBの選択
\connect db_books;

-- スキーマの作成
create schema books;

-- スキーマの選択
SET search_path = books;

-- テーブルの作成
create table book (
  id serial PRIMARY KEY NOT NULL,
  title varchar(100) NOT NULL,
  author varchar(10) NOT NULL,
  created timestamp  DEFAULT CURRENT_TIMESTAMP NOT NULL,
  updated timestamp  DEFAULT CURRENT_TIMESTAMP NOT NULL
);

最初のcreate schemaでbooksというスキーマを作成し、そのbooksというスキーマの中にbookというテーブルを作成しています。

具体的なsqlの型などはここでは割愛します。

dmlの中身

こちらも中身はシンプルで、dmlフォルダの中にbook_dml.sqlファイルを置いてあるだけです。book_dml.sqlの中身は下記になります。

-- DBの選択
\connect db_books;

-- スキーマの選択
SET search_path = books;

-- データの挿入
insert into book (title, author) values ('営繕かるかや怪異譚', '小野不由美');
insert into book (title, author) values ('営繕かるかや怪異譚 その弐', '小野不由美');
insert into book (title, author) values ('営繕かるかや怪異譚 その参', '小野不由美');

search_pathでbooksというスキーマを指定し、そのスキーマの中のbookテーブルにデータを入れています。

docker compose でpostgresqlを立ち上げる

さて、ここまでくればDockerを使って、postgresqlを立ち上げることができます。

ターミナルからdocker-compose.ymlファイルがあるディレクトリ(dockerディレクトリ)に移動し、下記でコンテナを立ち上げます。

# docker compose up -d --build

Sending build context to Docker daemon   1.05kB
Step 1/3 : FROM postgres:latest
 ---> bc5d09b9811d
Step 2/3 : COPY ./ddl/* /docker-entrypoint-initdb.d
 ---> Using cache
 ---> 884adf10e417
Step 3/3 : COPY ./dml/* /docker-entrypoint-initdb.d
 ---> Using cache
 ---> 10a346435f9b
Successfully built 10a346435f9b
Successfully tagged docker_postgresql:latest

Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them
[+] Running 2/2
 ⠿ Network docker_default          Created                  0.0s
 ⠿ Container postgresql_container  Started                  0.0s

docker ps(もしくはdocker container ls) として、コンテナがちゃんと起動しているか確認します。

# docker ps
CONTAINER ID   IMAGE               COMMAND                  CREATED         STATUS         PORTS                    NAMES
6df61fb84222   docker_postgresql   "docker-entrypoint.s…"   3 minutes ago   Up 3 minutes   0.0.0.0:5432->5432/tcp   postgresql_container

上記のように出てくれば、一旦は大丈夫です。

DBeaverからPostgresqlコンテナにつなげてみる

DBeaverを利用して、先ほど立ち上げたPostgresqlコンテナにつなげてみましょう。 (DBeaverと言っていますが、正直、繋がるのであればどんなクライアントツールでもいいと考えています。WindowsだとA5SQLが有名でしょうか??)

a5m2.mmatsubara.com

DBeaverは下記の公式ページからダウンロードしてください。

dbeaver.io

さて、DBeaverを開いたら、接続設定を行います。

① 左上の接続ボタンを押下

PostgreSQLを選択し、次へを押下

③ 下記項目を設定していきます。
Connect by:Host
Host:0.0.0.0
Port:5432
Database:postgres
ユーザー名:postgres
パスワード:passw0rd

いくつか注意点があります。
Port:DBeaverのPortでは、docker-compose.ymlのportsで設定した部分のポート番号を記載します。ここで注意しないといけないのは、ホスト:コンテナホストのポート番号を記載することです。
仮に5500:5432などと設定していた場合は、DBeaverのPortは5500を設定してください。

Database:特にdocker-compose.ymlやDockerfileで、DBの設定をしていなければ、デフォルトのpostgresで問題ありません。設定を変えていた場合、それに合わせて、変更が必要です。

ユーザー名:docker-compose.ymlで記載したユーザ名を記載します。今回はPOSTGRES_USERにpostgresを指定しているので、postgresになります。

パスワード:docker-compose.ymlで記載したパスワードを記載します。今回はPOSTGRES_PASSWORDにpassw0rdを指定しているので、postgresになります。

④ 設定し終わったら左下のテスト接続を押下します。
接続済み(下記画面)と出てきたら「OK」を押下し、(③の画像の)右下の「終了」を押下します。

さて、実際にDBeaverにデータが入っているか見てみましょう。

dmlで設定した3データがちゃんと入っていることが確認できましたね。

今回はここまでです。

まとめ

何はともあれ、Dockerの練習も兼ねてPostgreSQLをDockerで立てることができましたね。次回からはSpring Bootを導入して、実際にデータにアクセスしてみたいと思います。

また、これまでのものを整理すると下記のようになっています。

ディレクトリ構成

# DBUnitApplication/
└── docker
   ├── docker-compose.yml
   └── postgresql
      ├── Dockerfile
      ├── ddl
      │   └── book_ddl.sql
      └── dml
          └── book_dml.sql

docker-compose.ymlの中身

version: '3'

services:
  postgresql:
    container_name: postgresql_container
    build: ./postgresql
    ports:
      - 5432:5432
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: passw0rd
      TZ: "Asia/Tokyo"
    restart: always

Dockerfileの中身

FROM postgres:latest

COPY ./ddl/* /docker-entrypoint-initdb.d
COPY ./dml/* /docker-entrypoint-initdb.d

book_ddl.sqlの中身

-- DBの作成
create database db_books;

-- DBの選択
\connect db_books;

-- スキーマの作成
create schema books;

-- スキーマの選択
SET search_path = books;

-- テーブルの作成
create table book (
  id serial PRIMARY KEY NOT NULL,
  title varchar(100) NOT NULL,
  author varchar(10) NOT NULL,
  created timestamp  DEFAULT CURRENT_TIMESTAMP NOT NULL,
  updated timestamp  DEFAULT CURRENT_TIMESTAMP NOT NULL
);

dmlの中身

-- DBの選択
\connect db_books;

-- スキーマの選択
SET search_path = books;

-- データの挿入
insert into book (title, author) values ('営繕かるかや怪異譚', '小野不由美');
insert into book (title, author) values ('営繕かるかや怪異譚 その弐', '小野不由美');
insert into book (title, author) values ('営繕かるかや怪異譚 その参', '小野不由美');