Home About Contact
PostgreSQL , Docker , Kotlin Script

PostgreSQL を docker run する、そこに psql コマンドや Kotlin でアクセスする

PostgreSQL を Docker で動かして、そこに Kotlin Script からアクセスする覚え書きです。

環境:

$ lsb_release -a|grep Description
Description:	Ubuntu 24.04.1 LTS

$ docker --version
Docker version 27.2.0, build 3ab4256

まず、ローカルレポジトリにひとつも image が存在しないことを確認。

$ docker images
REPOSITORY   TAG       IMAGE ID   CREATED   SIZE

postgres を docker run する。

see: https://hub.docker.com/_/postgres

$ docker run --rm -d -p 5432:5432 --name my-postgres -e POSTGRES_PASSWORD=foobar postgres

ローカルレジストリに postgres イメージは pull されている。

$ docker images
REPOSITORY   TAG       IMAGE ID       CREATED      SIZE
postgres     latest    de869b203456   2 days ago   494MB

さらに docker ps すると postgres が起動していることも確認。 名前は my-postgres になっている。(先ほど --name でそれを指定したので。)

$ docker ps
CONTAINER ID   IMAGE      COMMAND                  CREATED              STATUS              PORTS                                       NAMES
5993a3338ab7   postgres   "docker-entrypoint.s…"   About a minute ago   Up About a minute   0.0.0.0:5432->5432/tcp, :::5432->5432/tcp   my-postgres

pokemon_db という名前のデータベースを作成する。

psql コマンドが存在しなければ入れる。

$ sudo apt install postgresql-client-common
$ sudo apt install postgresql-client-17

psql で Postgres のプロンプトに入る。

$ psql -U postgres -h localhost -p 5432 -d postgres
Password for user postgres:

postgres=#

そして データベース作成用の SQL コマンドを実行。

postgres=# CREATE DATABASE pokemon_db;
CREATE DATABASE

pokemon_db データベースにテーブル pokemons を作成して、 いくつかのポケモンを追加する Kotlin Script を用意。

// psql.main.kts

@file:Repository("https://repo1.maven.org/maven2/")
@file:DependsOn("org.postgresql:postgresql:42.7.5")
@file:DependsOn("com.zaxxer:HikariCP:6.2.1")

import com.zaxxer.hikari.HikariDataSource
import com.zaxxer.hikari.HikariConfig

data class Db(
    val driver: String,
    val url: String,
    val user: String,
    val password: String)

val toConfig: (Db)->HikariConfig = { db->
    HikariConfig().apply {
        setDriverClassName( db.driver )
        setJdbcUrl( db.url )
        setUsername(db.user)
        setPassword(db.password)
    }
}

val db = Db(
    "org.postgresql.Driver",
    "jdbc:postgresql://localhost/pokemon_db",
    "postgres",
    "foobar")

val ds = HikariDataSource(toConfig(db))
ds.connection.use { connection->
    connection.createStatement().use { st->
        val sql0 = listOf(
            "DROP TABLE IF EXISTS pokemons;",
            "CREATE TABLE pokemons(id SERIAL PRIMARY KEY, name VARCHAR(128));").joinToString("")
        st.executeUpdate(sql0)

        listOf(
            "INSERT INTO pokemons (name) VALUES('Pikachu');",
            "INSERT INTO pokemons (name) VALUES('Charmander');"
        ).forEach { sql->
            st.executeUpdate(sql)
        }
    }
}

実行する。

バージョンはこれ:

$ kotlin -version
Kotlin version 2.1.0-release-394 (JRE 17.0.2+8-86)
$ kotlin psql.main.kts

psql を使って pokemon_db テーブルが意図通り作成できたかを確かめる。

$ psql -U postgres -h localhost -p 5432 -d pokemon_db

pokemon_db=# \dt
          List of relations
 Schema |   Name   | Type  |  Owner
--------+----------+-------+----------
 public | pokemons | table | postgres
(1 row)

pokemon_db=# SELECT * FROM pokemons;
 id |    name
----+------------
  1 | Pikachu
  2 | Charmander
(2 rows)

pokemons データベースが作成されてそこにポケモンを入れることができました。

スキーマ変更 type コラムを追加

SQL はこれ:

ALTER TABLE pokemons ADD COLUMN type VARCHAR(128) DEFAULT 'Electric';

とりあえず全部 Electric を初期値として設定することにします。

$ psql -U postgres -h localhost -p 5432 -d pokemon_db

pokemon_db=# ALTER TABLE pokemons ADD COLUMN type VARCHAR(128) DEFAULT 'Electric';
ALTER TABLE
pokemon_db=# SELECT * FROM pokemons;
 id |    name    |   type   
----+------------+----------
  1 | Pikachu    | Electric
  2 | Charmander | Electric
(2 rows)

できました。

CharamanderFire なのでそこは修正しましょう。

pokemon_db=# UPDATE pokemons SET type='Fire' WHERE name='Charmander';
UPDATE 1

pokemon_db=# SELECT * FROM pokemons;
 id |    name    |   type
----+------------+----------
  1 | Pikachu    | Electric
  2 | Charmander | Fire
(2 rows)

変更できました。

バックアップしてからリストアする

ここで docker run していた Postgres を停止します。 その前にデータベースはバックアップしておき、 再度 docker run したときにリストアできるようにしておきましょう。

バックアップ pg_dump

pg_dump コマンドの説明はこちら

pokemon_db.dump ファイルにダンプデータを入れます。

$ pg_dump -U postgres -h localhost -p 5432 pokemon_db > pokemon_db.dump

内容を見てみるとプレーンテキストでコマンドが羅列されています。

$ head pokemon_db.dump
--
-- PostgreSQL database dump
--

-- Dumped from database version 17.3 (Debian 17.3-1.pgdg120+1)
-- Dumped by pg_dump version 17.3 (Ubuntu 17.3-1.pgdg24.04+1)

SET statement_timeout = 0;
SET lock_timeout = 0;
SET idle_in_transaction_session_timeout = 0;

Postgres を停止

それでは docker run していた Postgres を停めます。

docker ps で CONTAINER ID を確認。

$ docker ps
CONTAINER ID   IMAGE      COMMAND                  CREATED          STATUS          PORTS                                       NAMES
1916c497ac1e   postgres   "docker-entrypoint.s…"   59 minutes ago   Up 59 minutes   0.0.0.0:5432->5432/tcp, :::5432->5432/tcp   my-postgres

停止する。

$ docker stop 1916c497ac1e
1916c497ac1e

docker ps して Postgres が存在しないことを確認しましょう。

リストアする

docker run して postgres を起動:

$ docker run --rm -d -p 5432:5432 --name my-postgres -e POSTGRES_PASSWORD=foobar postgres

pokemon_db テーブルを用意:

$ psql -U postgres -h localhost -p 5432 -d postgres
postgres=# CREATE DATABASE pokemon_db;
CREATE DATABASE

ちなみに次のように -d postgres は省略しても同じ結果になる。省略すると postgres データベースが選択される。

$ psql -U postgres -h localhost -p 5432

または

$ psql -U postgres -h localhost

-p は省略可能。省略したら 5432 がデフォルトとして使用されるようだ。

環境変数PGDATABASE、PGHOST、PGPORT、PGUSERに適当な値を設定することで、このデフォルト値を上書きすることができるらしい。

先ほどバックアップとして pg_dump しておいたデータを標準入力から psql へ渡す。

$ cat pokemon_db.dump | psql -U postgres -h localhost -p 5432
...

データベース pokemon_db を作成しないで、 dump を投入してもリストアできないので注意!

リストアできているかを確認:

$ psql -U postgres -h localhost -p 5432 -d pokemon_db

pokemon_db=# SELECT * FROM pokemons;
 id |    name    |   type   
----+------------+----------
  1 | Pikachu    | Electric
  2 | Charmander | Fire
(2 rows)

OKです。

追伸

docker run するときに 次のようにすれば postgres ユーザのパスワードをなしで利用できます。

$ docker run --rm -d -p 5432:5432 --name my-postgre -e POSTGRES_HOST_AUTH_METHOD=trust postgres

You may also use "POSTGRES_HOST_AUTH_METHOD=trust" to allow all connections without a password. This is not recommended.

非推奨ですが、ローカルで開発するときにはとても重宝します。