あかんわ

覚えたことをブログに書くようにすれば多少はやる気が出るかと思ったんです

Mac OSX El CapitanでRuby on RailsからPostgreSQLを使う 前編

Mac OSX 10.11.4 El CapitanにPostgreSQL 9.5.1をインストールしようとして、試行錯誤する羽目に陥ったので記録しておきます。

RailsからPostgreSQLを使うための作業は、後編に書いています。

目次

いかにしてその心情に至ったか

Ruby on Railsチュートリアルを参考にしてWebアプリを作り、Herokuにデプロイしようとしているのですが、Herokuでは標準のデータベースであるPostgreSQLを使うので、MacにもPostgreSQLを入れて、production環境(Herokuにデプロイした状態)とdevelopment環境(自分のPCの開発環境)を同じにしようと考えました。

PostgreSQLMacにインストールする

まずは、HomebrewPostgreSQLをインストールします。
注:この時点で/usr/local/var/postgresディレクトリが既に存在している場合、バージョン違いによるエラーが生じる可能性があります。と言うか、私の環境ではエラーが起きました。エラーが起きた後のなんやかんやは、秘められた罠からの脱出に記載しています。

$brew install postgresql
==> Installing dependencies for postgresql: readline
==> Installing postgresql dependency: readline
==> Downloading https://homebrew.bintray.com/bottles/readline-6.3.8.el_capitan.bottle.tar.gz
######################################################################## 100.0%
==> Pouring readline-6.3.8.el_capitan.bottle.tar.gz
==> Caveats
This formula is keg-only, which means it was not symlinked into /usr/local.

OS X provides the BSD libedit library, which shadows libreadline.
In order to prevent conflicts when programs look for libreadline we are
defaulting this GNU Readline installation to keg-only.


Generally there are no consequences of this for you. If you build your
own software and it requires this formula, youll need to add to your
build variables:

    LDFLAGS:  -L/usr/local/opt/readline/lib
    CPPFLAGS: -I/usr/local/opt/readline/include

==> Summary
🍺  /usr/local/Cellar/readline/6.3.8: 40 files, 2.0M
==> Installing postgresql
==> Downloading https://homebrew.bintray.com/bottles/postgresql-9.5.1.el_capitan.bottle.tar.gz
######################################################################## 100.0%
==> Pouring postgresql-9.5.1.el_capitan.bottle.tar.gz
==> Caveats
If builds of PostgreSQL 9 are failing and you have version 8.x installed,
you may need to remove the previous version first. See:
  https://github.com/Homebrew/homebrew/issues/2510

To migrate existing data from a previous major version (pre-9.0) of PostgreSQL, see:
  http://www.postgresql.org/docs/9.5/static/upgrading.html

To migrate existing data from a previous minor version (9.0-9.4) of PosgresSQL, see:
  http://www.postgresql.org/docs/9.5/static/pgupgrade.html

  You will need your previous PostgreSQL installation from brew to perform `pg_upgrade`.
  Do not run `brew cleanup postgresql` until you have performed the migration.

To load postgresql:
  launchctl load ~/Library/LaunchAgents/homebrew.mxcl.postgresql.plist
Or, if you dont want/need launchctl, you can just run:
  postgres -D /usr/local/var/postgres
==> Summary
🍺  /usr/local/Cellar/postgresql/9.5.1: 3,118 files, 35M

インストールが終了したようなので、バージョンを確認してみます。

$postgres --version
postgres (PostgreSQL) 9.5.1

brew install postgresqlのSummaryに書いてあるとおり、バージョン9.5.1がインストールされたようです。

PostgreSQLの設定

PostgreSQLデータベースクラスタの作成と初期化

initdbコマンドで、データベースクラスタ(データベース格納領域)を作成し初期化します。
データベースクラスタを作成するディレクトリは任意の場所を選択できるようですが、今回の開発環境では一般的に使われている/usr/local/var/postgresディレクトリに作成します。
また、初期化の際には念のため、エンコーディングUTF-8に設定しておきます。

$initdb -E utf8 /usr/local/var/postgres                               
The files belonging to this database system will be owned by user "b0npu".
This user must also own the server process.

The database cluster will be initialized with locale "ja_JP.UTF-8".
initdb: could not find suitable text search configuration for locale "ja_JP.UTF-8"
The default text search configuration will be set to "simple".

Data page checksums are disabled.

initdb: directory "/usr/local/var/postgres" exists but is not empty
If you want to create a new database system, either remove or empty
the directory "/usr/local/var/postgres" or run initdb
with an argument other than "/usr/local/var/postgres".

UTF-8ロケール*1の初期化はできたようですが、表示された文字に、Data page checksums are disabledとかdirectory "/usr/local/var/postgres" exists but is not emptyとか不穏な文字が並んでいる事に不安が隠せません。
調べてみると、Data page checksums are disabled-kオプションによるデータページのチェックサムが有効化されていないために表示され、directory "/usr/local/var/postgres" exists but is not emptybrew install postgresqlの時点で、/usr/local/var/postgresがデータベースクラスタとして作成されているために表示されているようです。

なにわともあれ、データベースクラスタが初期化されたようなのでPostgreSQLサーバを起動して、動作確認を試みます。
注:PostgreSQLサーバの初回起動時にFATALエラーが出現したため、なんやかんやと再インストールすることにしました。 ここから先は、再インストール後の作業の記述です。なんやかんやの部分は、秘められた罠からの脱出に記載しています。

$postgres -D /usr/local/var/postgres 
LOG:  database system was shut down at 2016-04-05 05:17:18 JST
LOG:  MultiXact member wraparound protections are now enabled
LOG:  database system is ready to accept connections
LOG:  autovacuum launcher started

PostgreSQLサーバが無事に起動した*2ようなので、psqlコマンド、でPostgreSQLインタラクティブターミナルの動作確認*3がてらデータベースのリストを表示してみます。

$psql -l
                              List of databases
   Name    | Owner | Encoding |   Collate   |    Ctype    | Access privileges 
-----------+-------+----------+-------------+-------------+-------------------
 postgres  | b0npu | UTF8     | ja_JP.UTF-8 | ja_JP.UTF-8 | 
 template0 | b0npu | UTF8     | ja_JP.UTF-8 | ja_JP.UTF-8 | =c/b0npu         +
           |       |          |             |             | b0npu=CTc/b0npu
 template1 | b0npu | UTF8     | ja_JP.UTF-8 | ja_JP.UTF-8 | =c/b0npu         +
           |       |          |             |             | b0npu=CTc/b0npu
(3 rows)

psqlコマンドの動作確認もできましたのでPostgreSQLサーバを停止しようと思ったのですが、SIGTERMによる停止方法しか分からず、動作確認のために起動しただけのプログラムのpidを調べてkillするのも面倒なのでctrl+cで止めます。

^CLOG:  received fast shutdown request
LOG:  aborting any active transactions
LOG:  autovacuum launcher shutting down
LOG:  shutting down
LOG:  database system is shut down

停止できたようですが、LOG: received fast shutdown requestと表示されたのを見ると、ctrl+cによる停止は早計だった気がします。

PostgreSQLの起動と停止を簡単で安全にする

postgresコマンドでPostgreSQLサーバが起動できましたが、ユーティリティであるpg_ctlコマンドを使うことで、PostgreSQLサーバを安全で簡単に起動したり停止したりできるそうです。
また、postgresはデフォルトではPostgreSQLサーバをフォアグランドで起動しますが、pg_ctlはバックグラウンドで起動するため、PostgreSQLサーバの起動中に別のターミナルウインドウを開いたりする必要もなくなります。

環境変数PGDATAを設定して起動を楽にする

pg_ctlで楽をするため、シェルの設定ファイル(bash_profileとかzshrc*4とか)にPostgreSQL環境変数PGDATAを記述し、デフォルトのデータディレクトリの場所を設定します。

# PostgreSQLで使うデフォルトのデーベースディレクトリを環境変数に設定
export PGDATA=/usr/local/var/postgres

PGDATAが設定できたので、pg_ctlPostgreSQLサーバを起動してみます。

$pg_ctl start 
server starting

$LOG:  database system was shut down at 2016-04-05 05:27:49 JST
LOG:  MultiXact member wraparound protections are now enabled
LOG:  autovacuum launcher started
LOG:  database system is ready to accept connections

起動はできたようですが、サーバログのLOGが変な場所*5に表示されて戸惑いました。
-lオプションを使用してサーバログの出力先を指定していないと、このように表示される場合があるようです。
また、PGDATAを設定していない場合や、デフォルトのデータディレクトリ以外のデータベースクラスタを起動したい場合は、起動時に-Dオプションを使用してデータディレクトリを明示する必要があるようです。

なにわともあれ、起動の確認はできたのでサクッと停止します。

$pg_ctl stop    
waiting for server to shut down...LOG:  received fast shutdown request
LOG:  aborting any active transactions
.LOG:  autovacuum launcher shutting down
LOG:  shutting down
LOG:  database system is shut down
 done
server stopped

どうやら、安全なサーバの停止ができたようです( •̀ㅂ•́)و✧

postgresql.confでサーバログの出力先を設定する

変な場所にサーバログが表示されて戸惑うのを防ぐ*6ため、データディレクト/usr/local/val/postgresの中にある設定ファイルpostgresql.confを編集して、サーバログをテキストファイルに出力するように設定します。
pg_ctl-lオプションでサーバログの出力先を指定する方法もあるようですが、サーバを起動させる度にサーバログの出力先を入力するのも面倒なので、設定ファイルを活用します。

$vi /usr/local/val/postgres/postgresql.conf
# - Where to Log -

log_destination = 'stderr'    # Valid values are combinations of
                   # stderr, csvlog, syslog, and eventlog,
                   # depending on platform.  csvlog
                   # requires logging_collector to be on.

# This is used when logging to stderr:
logging_collector = on     # Enable capturing of stderr and csvlog
                   # into log files. Required to be on for
                   # csvlogs.
                   # (change requires restart)

# These are only used if logging_collector is on:
log_directory = 'pg_log'      # directory where log files are written,
                   # can be absolute or relative to PGDATA
log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log'   # log file name pattern,
                   # can include strftime() escapes
log_file_mode = 0600          # creation mode for log files,
                   # begin with 0 to use octal notation
  • log_destination標準エラー出力とかsyslogとかの出力先を指定する項目
  • logging_collector … log_destinationからテキストファイルへの出力を許可する項目
  • log_directory … ログファイルの格納先ディレクト*7を設定する
  • log_filename … ログファイルのファイル名を指定する項目
  • log_file_mode … ログファイルのパーミッションを指定する項目

postgresql.confの設定ができたので、PostgreSQLサーバを起動してサーバログのログファイルへの出力を確認します。

$pg_ctl start
server starting
LOG:  redirecting log output to logging collector process                                                               
HINT:  Future log output will appear in directory "pg_log".

サーバ起動時の表示が変わった事に少し喜びつつ、PostgreSQLサーバを停止します。

$pg_ctl stop 
waiting for server to shut down.... done
server stopped

サーバ停止時の表示も変わっていますので、後はログファイルが作成されていれば一段落です。

$ls /usr/local/var/postgres/pg_log
postgresql-2016-04-05_054032.log
$more /usr/local/var/postgres/pg_log/postgresql-2016-04-05_054032.log 
LOG:  database system was shut down at 2016-04-05 05:30:39 JST
LOG:  MultiXact member wraparound protections are now enabled
LOG:  autovacuum launcher started
LOG:  database system is ready to accept connections
LOG:  received fast shutdown request
LOG:  aborting any active transactions
LOG:  autovacuum launcher shutting down
LOG:  shutting down
LOG:  database system is shut down

できたーヽ(・ω・)/

後編に続きます。

参考:秘められた罠からの脱出

brew install postgresqlPostgreSQLをインストールしてinitdbでデータベースクラスタの初期化を実行した後、PostgreSQLを起動しようとしたらエラーに遭遇しました。

$postgres -D /usr/local/var/postgres         
FATAL:  database files are incompatible with server
DETAIL:  The data directory was initialized by PostgreSQL version 9.4, which is not compatible with this version 9.5.1.

FATAL?(・・;)

よくわかりませんでしたが、バージョン違いでエラーが起きていることは伝わってきたのでFATAL: database files are incompatible with serverでググってみると、こちらの議論に調べ方が色々と載っているのを見つけ、ここを参考にして調査することにしました。

とりあえずディレクトリの情報を表示してみます。

$ls /usr/local/var /usr/local/var/postgres
/usr/local/var:
cache    postgres

/usr/local/var/postgres:
PG_VERSION           pg_clog              pg_multixact         pg_subtrans          postgresql.conf
base                 pg_hba.conf          pg_notify            pg_xlog              postmaster.opts
global               pg_ident.conf        pg_stat_tmp          postgresql.auto.conf server.log

バージョン違いとか言われてる割に、postgresに関係しそうなディレクトリは1つしか無さそうですし、初めて見るディレクトリの中身を見ても正直よくわからないので、別のデータベースクラスタを作成してみることにします。
そういえば、initdbdirectory "/usr/local/var/postgres" exists but is not emptyの後にも、If you want to create a new database system, either remove or empty the directory "/usr/local/var/postgres" or run initdb with an argument other than "/usr/local/var/postgres".とか書いてましたわ。

$initdb -E utf-8 /usr/local/var/postgres9.5
The files belonging to this database system will be owned by user "b0npu".
This user must also own the server process.

The database cluster will be initialized with locale "ja_JP.UTF-8".
initdb: could not find suitable text search configuration for locale "ja_JP.UTF-8"
The default text search configuration will be set to "simple".

Data page checksums are disabled.

creating directory /usr/local/var/postgres9.5 ... ok
creating subdirectories ... ok
selecting default max_connections ... 100
selecting default shared_buffers ... 128MB
selecting dynamic shared memory implementation ... posix
creating configuration files ... ok
creating template1 database in /usr/local/var/postgres9.5/base/1 ... ok
initializing pg_authid ... ok
initializing dependencies ... ok
creating system views ... ok
loading system objects descriptions ... ok
creating collations ... ok
creating conversions ... ok
creating dictionaries ... ok
setting privileges on built-in objects ... ok
creating information schema ... ok
loading PL/pgSQL server-side language ... ok
vacuuming database template1 ... ok
copying template1 to template0 ... ok
copying template1 to postgres ... ok
syncing data to disk ... ok

WARNING: enabling "trust" authentication for local connections
You can change this by editing pg_hba.conf or using the option -A, or
--auth-local and --auth-host, the next time you run initdb.

Success. You can now start the database server using:

    pg_ctl -D /usr/local/var/postgres9.5 -l logfile start

なんかようさん出てきた(゚Д゚)

新しくデータベースクラスタ/usr/local/var/postgres9.5が作成され、初期化も出来たようなので、作成されたデータディレクトリの情報を確認してみます。

$ls /usr/local/var /usr/local/var/postgres9.5
/usr/local/var:
cache       postgres    postgres9.5

/usr/local/var/postgres9.5:
PG_VERSION           pg_dynshmem          pg_notify            pg_stat_tmp          postgresql.auto.conf
base                 pg_hba.conf          pg_replslot          pg_subtrans          postgresql.conf
global               pg_ident.conf        pg_serial            pg_tblspc
pg_clog              pg_logical           pg_snapshots         pg_twophase
pg_commit_ts         pg_multixact         pg_stat              pg_xlog

なんか、さっき見た/usr/local/var/postgresよりも中身が多い( ゚д゚)

これまでの調査で、PostgreSQLのインストールは出来ていて、データクラスタの作成も出来るけれども、/usr/local/var/postgresはバージョンが違うから使えなくて、バージョンが違う理由はおそらく私にはわからないという事が分かったので、環境構築作業を前に進めるための手っ取り早い方法を考えます。

『よろしいならば再インストールだ』

先ほどインストールしたばかりのPostgreSQLを、brew uninstall postgresqlします。

$brew uninstall postgresql
Uninstalling /usr/local/Cellar/postgresql/9.5.1... (3,118 files, 35M)

念のためディレクトリも削除します。

$rm -rf /usr/local/var/postgres
$rm -rf /usr/local/var/postgres9.5

掃除が終わったので、再インストールを試みます。

$brew install postgresql
==> Downloading https://homebrew.bintray.com/bottles/postgresql-9.5.1.el_capitan.bottle.tar.gz
Already downloaded: /Library/Caches/Homebrew/postgresql-9.5.1.el_capitan.bottle.tar.gz
==> Pouring postgresql-9.5.1.el_capitan.bottle.tar.gz
==> /usr/local/Cellar/postgresql/9.5.1/bin/initdb /usr/local/var/postgres
==> Caveats
If builds of PostgreSQL 9 are failing and you have version 8.x installed,
you may need to remove the previous version first. See:
  https://github.com/Homebrew/homebrew/issues/2510

To migrate existing data from a previous major version (pre-9.0) of PostgreSQL, see:
  http://www.postgresql.org/docs/9.5/static/upgrading.html

To migrate existing data from a previous minor version (9.0-9.4) of PosgresSQL, see:
  http://www.postgresql.org/docs/9.5/static/pgupgrade.html

  You will need your previous PostgreSQL installation from brew to perform `pg_upgrade`.
  Do not run `brew cleanup postgresql` until you have performed the migration.

To load postgresql:
  launchctl load ~/Library/LaunchAgents/homebrew.mxcl.postgresql.plist
Or, if you dont want/need launchctl, you can just run:
  postgres -D /usr/local/var/postgres
==> Summary
🍺  /usr/local/Cellar/postgresql/9.5.1: 3,118 files, 35M

最初にインストールした時は、依存関係にあるreadlineとやらもインストールされていましたが、今回はPostgeSQLのみがインストールされたようです。

慣例的に、データベースクラスタの初期化もしておきます。

$initdb -E utf-8 /usr/local/var/postgres                               
The files belonging to this database system will be owned by user "b0npu".
This user must also own the server process.

The database cluster will be initialized with locale "ja_JP.UTF-8".
initdb: could not find suitable text search configuration for locale "ja_JP.UTF-8"
The default text search configuration will be set to "simple".

Data page checksums are disabled.

initdb: directory "/usr/local/var/postgres" exists but is not empty
If you want to create a new database system, either remove or empty
the directory "/usr/local/var/postgres" or run initdb
with an argument other than "/usr/local/var/postgres".

やはりbrew install postgreqlの時点で、データベースクラスタが作成されているようで不穏な文字が並んでいますが、とりあえず初期化も終わったようなので、PostgreSQLサーバを起動してみます。

$postgres -D /usr/local/var/postgres 
LOG:  database system was shut down at 2016-04-05 05:17:18 JST
LOG:  MultiXact member wraparound protections are now enabled
LOG:  database system is ready to accept connections
LOG:  autovacuum launcher started

良かった、無事にPostgreSQLサーバが起動された(´;ω;`)

脱出のまとめ

initdb -E utf-8 /usr/local/var/postgresで初期化を試みた際の出力の最後の方に、If you want to create a new database system, either remove or empty the directory "/usr/local/var/postgres"と書かれているので、/usr/local/var/postgresの中身を削除して新しいデータベースクラスタを作成するだけで良かったかもしれませんが、自分の過去の行いか、若しくは、Mac OSXにデフォルトで作成されていたものだろうと推測しましたので、ディレクトリ自体の削除と再インストールを実施しました。
次からは、一般的に使われているディレクトリに罠が無いか確認してから作業します。

参考記事

PostgreSQLのインストールについては、こちらの記事を参考にさせていただきました。

開発環境

  • OSX 10.11.4 El Capitan
    - ターミナルエミュレータMacターミナル
    - シェル: zsh
    - パッケージマネージャ: Homebrew
  • リレーショナルデータベース
    - ORDBMS: PostgreSQL 9.5.1

*1:エンコーディングなんかの言語環境

*2:起動時にネットワーク受信接続の許可を求められたので許可してあります

*3:この時はPostgreSQLサーバがフォアグランドで起動したためPostgreSQLサーバを起動させたターミナルウインドウとは別のターミナルウインドウを開いて確認しました

*4:私はzshを使っているのでこちらに書きました

*5:$が表示されて入力待ちになったように見えた後

*6:サーバログの出力先を設定していても出力先のディレクトリが作成されていない場合はサーバの初回起動時に少し変な事になる場合があるようです

*7:環境変数のPGDATAを設定していればPGDATA配下のディレクト