PostgreSQL 環境の設定 : 小林研 Rails Tips (45)

はじめに

Rails Tips の 45 回目です。Rails のアプリを作成する前に PostgreSQL を設定します。Rails ガイドではシステム側の設定が不要な SQLite3 を利用していますが、少し凝ったことをするとなると PostgreSQL くらいは使いたくなります。いつも設計関係のいろんなコマンドなどを忘れてしまうので、たまにこうやって記事にしておこうと思います。

railsguides.jp

PostgreSQL をインストールする

Rails ガイドでは 3.1.2 の「SQLite3 をインストールする」ですが、ここでは PostgreSQL をインストールします。こちらは homebrew でインストールしました。PostgreSQL はバージョンごとにパッケージが異なり、最新版は postgresql@16 になっています。現在、単に postgresql とした場合は postgresql@14 が入るようになっており、@16 は /opt/homebrew/bin などにはパスが自動的にリンクされません。こちらの info でも postgresql@16 は keg-only でパスは設定されないので、自分で張るように指示されています。

==> postgresql@16: stable 16.1 (bottled) [keg-only]
Object-relational database system
https://www.postgresql.org/
/opt/homebrew/Cellar/postgresql@16/16.1_3 (3,796 files, 68.4MB)
  Poured from bottle using the formulae.brew.sh API on 2024-01-13 at 21:36:56
From: https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/p/postgresql@16.rb
License: PostgreSQL
==> Dependencies
Build: pkg-config ✔
Required: gettext ✔, icu4c ✔, krb5 ✔, lz4 ✔, openssl@3 ✔, readline ✔, zstd ✔
==> Caveats
This formula has created a default database cluster with:
  initdb --locale=C -E UTF-8 /opt/homebrew/var/postgresql@16
For more details, read:
  https://www.postgresql.org/docs/16/app-initdb.html

postgresql@16 is keg-only, which means it was not symlinked into /opt/homebrew,
because this is an alternate version of another formula.

If you need to have postgresql@16 first in your PATH, run:
  fish_add_path /opt/homebrew/opt/postgresql@16/bin

For compilers to find postgresql@16 you may need to set:
  set -gx LDFLAGS "-L/opt/homebrew/opt/postgresql@16/lib"
  set -gx CPPFLAGS "-I/opt/homebrew/opt/postgresql@16/include"

For pkg-config to find postgresql@16 you may need to set:
  set -gx PKG_CONFIG_PATH "/opt/homebrew/opt/postgresql@16/lib/pkgconfig"

To start postgresql@16 now and restart at login:
  brew services start postgresql@16
Or, if you don't want/need a background service you can just run:
  LC_ALL="C" /opt/homebrew/opt/postgresql@16/bin/postgres -D /opt/homebrew/var/postgresql@16

ほとんどのマシンはこのバージョンに上げていたのですが、今この記事を書いている持ち歩き用のマシンは普段開発をしていないので、postgresql でインストールした @14 のままでした。せっかくなので、このマシンも他のマシンと同様に @16 にアップグレードしてみます。校務支援システムでお世話になっている BPS 株式会社の TechRacho にこのアップグレードの記事が書いてありましたので、これを参考に上げていきましょう。

techracho.bpsinc.jp

まず、@14 → @15 へのアップグレードをするために postgresql@15 のパッケージをインストールします。

brew install postgresql@15

ちなみに、15 の info は以下のようになっています。

==> postgresql@15: stable 15.5 (bottled) [keg-only]
Object-relational database system
https://www.postgresql.org/
/opt/homebrew/Cellar/postgresql@15/15.5_3 (3,700 files, 63MB)
  Poured from bottle using the formulae.brew.sh API on 2024-01-13 at 16:38:00
From: https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/p/postgresql@15.rb
License: PostgreSQL
==> Dependencies
Build: pkg-config ✔
Required: gettext ✔, icu4c ✔, krb5 ✔, lz4 ✔, openssl@3 ✔, readline ✔, zstd ✔
==> Caveats
This formula has created a default database cluster with:
  initdb --locale=C -E UTF-8 /opt/homebrew/var/postgresql@15
For more details, read:
  https://www.postgresql.org/docs/15/app-initdb.html

postgresql@15 is keg-only, which means it was not symlinked into /opt/homebrew,
because this is an alternate version of another formula.

If you need to have postgresql@15 first in your PATH, run:
  fish_add_path /opt/homebrew/opt/postgresql@15/bin

For compilers to find postgresql@15 you may need to set:
  set -gx LDFLAGS "-L/opt/homebrew/opt/postgresql@15/lib"
  set -gx CPPFLAGS "-I/opt/homebrew/opt/postgresql@15/include"

For pkg-config to find postgresql@15 you may need to set:
  set -gx PKG_CONFIG_PATH "/opt/homebrew/opt/postgresql@15/lib/pkgconfig"

To start postgresql@15 now and restart at login:
  brew services start postgresql@15
Or, if you don't want/need a background service you can just run:
  LC_ALL="C" /opt/homebrew/opt/postgresql@15/bin/postgres -D /opt/homebrew/var/postgresql@15

一方、現状の postgresql@14 はこんな感じです。

==> postgresql@14: stable 14.10 (bottled)
Object-relational database system
https://www.postgresql.org/
/opt/homebrew/Cellar/postgresql@14/14.10_1 (3,317 files, 46MB) *
  Poured from bottle using the formulae.brew.sh API on 2023-12-04 at 11:37:50
From: https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/p/postgresql@14.rb
License: PostgreSQL
==> Dependencies
Build: pkg-config ✔
Required: icu4c ✔, krb5 ✔, lz4 ✔, openssl@3 ✔, readline ✔
==> Caveats
This formula has created a default database cluster with:
  initdb --locale=C -E UTF-8 /opt/homebrew/var/postgresql@14
For more details, read:
  https://www.postgresql.org/docs/14/app-initdb.html

To restart postgresql@14 after an upgrade:
  brew services restart postgresql@14
Or, if you don't want/need a background service you can just run:
  /opt/homebrew/opt/postgresql@14/bin/postgres -D /opt/homebrew/var/postgresql@14

この二つの情報から以下のコマンドでデータベースを upgrade します。

$ /opt/homebrew/Cellar/postgresql@15/15.5_3/bin/pg_upgrade \
                   -b /opt/homebrew/Cellar/postgresql@14/14.10_1/bin \
                   -d /opt/homebrew/var/postgresql@14 \
                   -B /opt/homebrew/Cellar/postgresql@15/15.5_3/bin \
                   -D /opt/homebrew/var/postgresql@15

サーバ稼働中のまま実行してしまったので以下のエラーが出ました。

旧クラスタで稼働中のpostmasterがあるようです。
そのpostmasterをシャットダウンしたのちにやり直してください。
失敗しました、終了しています

サーバを止めます。

$ brew services stop postgresql
Stopping `postgresql@14`... (might take a while)
==> Successfully stopped `postgresql@14` (label: homebrew.mxcl.postgresql@14)

再度実行したところ、以下のように無事に転送が成功しました。

整合性チェックを実行しています。
-----------------------------
Checking cluster versions                                   ok
Checking database user is the install user                  ok
Checking database connection settings                       ok
Checking for prepared transactions                          ok
Checking for system-defined composite types in user tables  ok
Checking for reg* data types in user tables                 ok
Checking for contrib/isn with bigint-passing mismatch       ok
Creating dump of global objects                             ok
Creating dump of database schemas
                                                            ok
Checking for presence of required libraries                 ok
Checking database user is the install user                  ok
Checking for prepared transactions                          ok
Checking for new cluster tablespace directories             ok

この後pg_upgradeが失敗した場合は、続ける前に新しいクラスタを
initdbで再作成する必要があります。

アップグレードを実行しています。
------------------
Analyzing all rows in the new cluster                       ok
Freezing all rows in the new cluster                        ok
Deleting files from new pg_xact                             ok
Copying old pg_xact to new server                           ok
Setting oldest XID for new cluster                          ok
Setting next transaction ID and epoch for new cluster       ok
Deleting files from new pg_multixact/offsets                ok
Copying old pg_multixact/offsets to new server              ok
Deleting files from new pg_multixact/members                ok
Copying old pg_multixact/members to new server              ok
Setting next multixact ID and offset for new cluster        ok
Resetting WAL archives                                      ok
Setting frozenxid and minmxid counters in new cluster       ok
Restoring global objects in the new cluster                 ok
Restoring database schemas in the new cluster
                                                            ok
Copying user relation files
                                                            ok
Setting next OID for new cluster                            ok
Sync data directory to disk                                 ok
Creating script to delete old cluster                       ok
Checking for extension updates                              ok

アップグレードが完了しました
----------------
オプティマイザーの統計は、pg_upgrade では転送されません。そのため
新サーバーを起動した後、以下を行うことを検討してください。
    /opt/homebrew/Cellar/postgresql@15/15.5_3/bin/vacuumdb --all --analyze-in-stages

このスクリプトを実行すると、旧クラスタのデータファイル ./delete_old_cluster.shが削除されます:

次に、そのまま @15 → @16 へのアップグレードをするために postgresql@16 のパッケージをインストールします。

brew install postgresql@16

上と同じように pg_upgrade を実施します。

/opt/homebrew/Cellar/postgresql@16/16.1_3/bin/pg_upgrade \
                   -b /opt/homebrew/Cellar/postgresql@15/15.5_3/bin \
                   -d /opt/homebrew/var/postgresql@15 \
                   -B /opt/homebrew/Cellar/postgresql@16/16.1_3/bin \
                   -D /opt/homebrew/var/postgresql@16
整合性チェックを実行しています。
-----------------------------
Checking cluster versions                                     ok
Checking database user is the install user                    ok
Checking database connection settings                         ok
Checking for prepared transactions                            ok
Checking for system-defined composite types in user tables    ok
Checking for reg* data types in user tables                   ok
Checking for contrib/isn with bigint-passing mismatch         ok
Checking for incompatible "aclitem" data type in user tables  ok
Creating dump of global objects                               ok
Creating dump of database schemas
                                                              ok
Checking for presence of required libraries                   ok
Checking database user is the install user                    ok
Checking for prepared transactions                            ok
Checking for new cluster tablespace directories               ok

この後pg_upgradeが失敗した場合は、続ける前に新しいクラスタを
initdbで再作成する必要があります。

アップグレードを実行しています。
------------------
Setting locale and encoding for new cluster                   ok
Analyzing all rows in the new cluster                         ok
Freezing all rows in the new cluster                          ok
Deleting files from new pg_xact                               ok
Copying old pg_xact to new server                             ok
Setting oldest XID for new cluster                            ok
Setting next transaction ID and epoch for new cluster         ok
Deleting files from new pg_multixact/offsets                  ok
Copying old pg_multixact/offsets to new server                ok
Deleting files from new pg_multixact/members                  ok
Copying old pg_multixact/members to new server                ok
Setting next multixact ID and offset for new cluster          ok
Resetting WAL archives                                        ok
Setting frozenxid and minmxid counters in new cluster         ok
Restoring global objects in the new cluster                   ok
Restoring database schemas in the new cluster
                                                              ok
Copying user relation files
                                                              ok
Setting next OID for new cluster                              ok
Sync data directory to disk                                   ok
Creating script to delete old cluster                         ok
Checking for extension updates                                ok

アップグレードが完了しました
----------------
オプティマイザーの統計は、pg_upgrade では転送されません。そのため
新サーバーを起動した後、以下を行うことを検討してください。
    /opt/homebrew/Cellar/postgresql@16/16.1_3/bin/vacuumdb --all --analyze-in-stages
このスクリプトを実行すると、旧クラスタのデータファイルが削除されます:
    ./delete_old_cluster.sh

アップデートされたので、サーバを起動してみます。

brew services start postgresql@16
==> Successfully started `postgresql@16` (label: homebrew.mxcl.postgresql@16)

前述したように postgresql@16 は keg only なので、パスは自動で設定されません。このため、config.fish には以下のように PATH を設定しました。また、LDFLAGS, CPPFLAGS, PKG_CONFIG_PATH なども指示通りに設定します。

# homebrew
set -gx PATH ~/bin /Library/TeX/texbin /opt/homebrew/opt/postgresql@16/bin /opt/homebrew/bin /usr/local/bin /usr/local/sbin ~/.cargo/bin $PATH

set -gx LDFLAGS "-L/opt/homebrew/opt/postgresql@16/lib"
set -gx CPPFLAGS "-I/opt/homebrew/opt/postgresql@16/include"
set -gx PKG_CONFIG_PATH "/opt/homebrew/opt/postgresql@16/lib/pkgconfig"

シェルを起動して psql の場所を尋ねると以下のように @16 のものが検出されました。

which psql
/opt/homebrew/opt/postgresql@16/bin/psql

ubuntu などの場合には postgres という専用ユーザが作成されますが、homebrew 版では利便性のためにログインユーザのアカウントが自動的に設定されています。そのため、psql template1 とするだけで、template1 データベースにアクセスできます。

$ psql template1
psql (16.1 (Homebrew))
"help"でヘルプを表示します。

template1=#

\du とすると既存のユーザが表示されます。16 だと日本語で表示されるのですね。

template1=# \du
                                        ロール一覧
  ロール名  |                                     属性
------------+------------------------------------------------------------------------------
 hkob       | スーパーユーザー, ロール作成可, DB作成可, レプリケーション可, RLS のバイパス
 rails7test | DB作成可
 webcit     | DB作成可

今回の blog ように blog ユーザを作成してみます。

create user blog;
alter user blog with password 'パスワード';
alter user blog createdb;

再度ユーザを確認すると正しく作成されていることがわかります。

template1=# \du
                                        ロール一覧
  ロール名  |                                     属性
------------+------------------------------------------------------------------------------
 blog       | DB作成可
 hkob       | スーパーユーザー, ロール作成可, DB作成可, レプリケーション可, RLS のバイパス
 rails7test | DB作成可
 webcit     | DB作成可

Ubuntu などでは通常、pg_hba.conf を修正して権限設定が必要です。しかし、homebrew 版は基本的に開発用として考えられているため、localhost からのアクセスについては、許可という形の設定になっています。もし macOS 自体をサーバにするという場合にはこのあたりはちゃんと閉じる必要があると思います。

# "local" is for Unix domain socket connections only
local   all             all                                     trust
# IPv4 local connections:
host    all             all             127.0.0.1/32            trust
# IPv6 local connections:
host    all             all             ::1/128                 trust
# Allow replication connections from localhost, by a user with the
# replication privilege.
local   replication     all                                     trust
host    replication     all             127.0.0.1/32            trust
host    replication     all             ::1/128                 trust

おわりに

とりあえず blog というユーザを作成したので、このユーザを元に明日は rails アプリの作成に入ります。