CentOS7にpostgresqlを9.xと10.xを共存させた場合の注意点

## はじめに
近頃のLinuxは複数バージョンのアプリケーションを共存させ、簡単にデフォルトバージョン切り替えできるようにするための管理ツールalternativesが用意されている。

[UPDATE-ALTERNATIVES](http://man.linuxtool.net/centos7/u3/man/8_alternatives.html)

今回CentOS 7において、Postgresql 9.x がインストールされた環境で Postgresql 10.x を追加でインストールするとpostgresqlの関連コマンドが10.xものに切り替わらないという問題が発生した。 以降で調査の流れとその解決策を提示する。

## 環境
* OS: CentOS 7.6.1810 (Dockerコンテナ)

## 再現手順

### 再現環境準備

まずDockerコンテナとしてCentOSの環境を構築し、ログインする。

```shell
% docker pull centos
% docker images
REPOSITORY                                 TAG                 IMAGE ID            CREATED             SIZE
centos                                     latest              9f38484d220f        3 months ago        202MB

% docker run --rm  -it centos
[root@6c2ed6cf1a10 /]# cat /etc/redhat-release
CentOS Linux release 7.6.1810 (Core)
```

調査に利用するコマンドを事前にインストールしておく。

```shell
[root@dc85a6cd4673 /]# yum install -y which file
```

### Postgresql 9.x インストール
まず Postgresql 9.x をインストールする。

```shell
[root@6c2ed6cf1a10 /]# yum list | egrep '^postgresql(|10)(|-libs)\.x86_64'
postgresql.x86_64                         9.2.24-1.el7_5                 base
postgresql-libs.x86_64                    9.2.24-1.el7_5                 base

[root@6c2ed6cf1a10 /]# yum install -y postgresql
…

Installed:
  postgresql.x86_64 0:9.2.24-1.el7_5

Dependency Installed:
  postgresql-libs.x86_64 0:9.2.24-1.el7_5

Complete!
[root@6c2ed6cf1a10 /]# yum list | egrep '^postgresql(|10)(|-libs)\.x86_64'
postgresql.x86_64                         9.2.24-1.el7_5                 @base
postgresql-libs.x86_64                    9.2.24-1.el7_5                 @base
```

バージョンとインストールされたコマンドの実体を確認。
コマンドやドキュメントなど色々なものがインストールされるが、ここでは代表例としてpsqlコマンドで確認する。

```shell
[root@6c2ed6cf1a10 /]# psql -V
psql (PostgreSQL) 9.2.24

[root@6c2ed6cf1a10 /]# which psql
/usr/bin/psql

[root@6c2ed6cf1a10 /]# ls -l /usr/bin/psql
-rwxr-xr-x 1 root root 449320 Aug 23  2018 /usr/bin/psql

[root@6c2ed6cf1a10 /]# file /usr/bin/psql
/usr/bin/psql: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=235f9861cb4f57cf25eb086c3132e11c413b1a2e, stripped
```

9.xのコマンドであることが確認できる。
またコマンドがalternativesで管理されていないことも確認できる。

```shell
[root@6c2ed6cf1a10 /]# alternatives --list | grep pgsql

[root@6c2ed6cf1a10 /]# ls -l /etc/alternatives/pgsql*
ls: cannot access /etc/alternatives/pgsql*: No such file or directory

[root@6c2ed6cf1a10 /]# ls -l /var/lib/alternatives/pgsql*
ls: cannot access /var/lib/alternatives/pgsql*: No such file or directory
```

### Postgresql 10.x インストール

9.xがインストールされた状態で、続けて10.xをインストールする。
10.xはデフォルトのパッケージレポジトリには含まれていなかったので、以下の手順を参考にした。

https://weblabo.oscasierra.net/postgresql10-centos7-install/

まずはパッケージレポジトリを追加する。

```shell
[root@6c2ed6cf1a10 /]# yum -y localinstall https://download.postgresql.org/pub/repos/yum/10/redhat/rhel-7-x86_64/pgdg-
…
Installed:
  pgdg-redhat-repo.noarch 0:42.0-4

Complete!
```

10.xのパッケージ確認。

```shell
[root@6c2ed6cf1a10 /]# yum list | egrep '^postgresql(|10)(|-libs)\.x86_64'
postgresql.x86_64                         9.2.24-1.el7_5                 @base
postgresql-libs.x86_64                    9.2.24-1.el7_5                 @base
postgresql10.x86_64                       10.8-1PGDG.rhel7               pgdg10
postgresql10-libs.x86_64                  10.8-1PGDG.rhel7               pgdg10
```

10.xのパッケージインストール。

```shell
[root@6c2ed6cf1a10 /]# yum install -y postgresql10
…
Installed:
  postgresql10.x86_64 0:10.8-1PGDG.rhel7

Dependency Installed:
  libicu.x86_64 0:50.1.2-17.el7          postgresql10-libs.x86_64 0:10.8-1PGDG.rhel7          systemd-sysv.x86_64 0:219-62.el7_6.6

Dependency Updated:
  systemd.x86_64 0:219-62.el7_6.6                                   systemd-libs.x86_64 0:219-62.el7_6.6

Complete!
```

psqlコマンドでバージョン確認。

```shell
[root@6c2ed6cf1a10 /]# psql -V
psql (PostgreSQL) 9.2.24

[root@6c2ed6cf1a10 /]# which psql
/usr/bin/psql
[root@6c2ed6cf1a10 /]# ls -l /usr/bin/psql
-rwxr-xr-x 1 root root 449320 Aug 23  2018 /usr/bin/psql
```

alternativesで管理されるはずだがバージョンは9.xのまま。
コマンドの実体にも変化はない。

alternativesの管理状態を確認。
管理されているように見えるがコマンドは9.xのまま。

```shell
[root@6c2ed6cf1a10 /]# alternatives --list | grep pgsql
pgsql-createdb	auto	/usr/pgsql-10/bin/createdb
pgsql-clusterdbman	auto	/usr/pgsql-10/share/man/man1/clusterdb.1
pgsql-reindexdb	auto	/usr/pgsql-10/bin/reindexdb
pgsql-pg_basebackup	auto	/usr/pgsql-10/bin/pg_basebackup
pgsql-createdbman	auto	/usr/pgsql-10/share/man/man1/createdb.1
pgsql-createuserman	auto	/usr/pgsql-10/share/man/man1/createuser.1
pgsql-psqlman	auto	/usr/pgsql-10/share/man/man1/psql.1
pgsql-pg_dumpman	auto	/usr/pgsql-10/share/man/man1/pg_dump.1
pgsql-psql	auto	/usr/pgsql-10/bin/psql
pgsql-vacuumdb	auto	/usr/pgsql-10/bin/vacuumdb
pgsql-reindexdbman	auto	/usr/pgsql-10/share/man/man1/reindexdb.1
pgsql-pg_dumpallman	auto	/usr/pgsql-10/share/man/man1/pg_dumpall.1
pgsql-pg_restoreman	auto	/usr/pgsql-10/share/man/man1/pg_restore.1
pgsql-pg_dumpall	auto	/usr/pgsql-10/bin/pg_dumpall
pgsql-dropdbman	auto	/usr/pgsql-10/share/man/man1/dropdb.1
pgsql-dropuser	auto	/usr/pgsql-10/bin/dropuser
pgsql-ld-conf	auto	/usr/pgsql-10/share/postgresql-10-libs.conf
pgsql-pg_basebackupman	auto	/usr/pgsql-10/share/man/man1/pg_basebackup.1
pgsql-clusterdb	auto	/usr/pgsql-10/bin/clusterdb
pgsql-pg_dump	auto	/usr/pgsql-10/bin/pg_dump
pgsql-dropdb	auto	/usr/pgsql-10/bin/dropdb
pgsql-pg_restore	auto	/usr/pgsql-10/bin/pg_restore
pgsql-createuser	auto	/usr/pgsql-10/bin/createuser
pgsql-dropuserman	auto	/usr/pgsql-10/share/man/man1/dropuser.1
pgsql-vacuumdbman	auto	/usr/pgsql-10/share/man/man1/vacuumdb.1

[root@6c2ed6cf1a10 /]# ls -l /etc/alternatives/pgsql*
…
lrwxrwxrwx 1 root root 22 Jun 19 09:06 /etc/alternatives/pgsql-psql -> /usr/pgsql-10/bin/psql
…

[root@6c2ed6cf1a10 /]# head /var/lib/alternatives/pgsql*
…
==> /var/lib/alternatives/pgsql-psql <==
auto
/usr/bin/psql

/usr/pgsql-10/bin/psql
1000
…
```

alternativesはコマンドだけでなく、設定ファイルやmanのドキュメントなども管理していることがわかる。

### 問題対処

psqlコマンドで言えば、以下のようにリンクが生成され、10.xに紐づくようになっていることが期待される。

`/usr/bin/psql` -> `/etc/alternatives/pgsql-psql`  -> `/usr/pgsql-10/bin/psql`

しかし実際には`/usr/bin/psql`が9.xのバイナリとして存在してしまっているため、alternativesの設定通りに管理できていないと思われる。それを確かめるために`alternatives --auto`コマンドでシンボリックを生成させてみる。

このコマンドは`/var/alternatives`配下のコマンド毎の設定に基づきリンクの貼り直しを行ってくれる。

面倒なので、`/var/alternatives`配下のpostgresql関連の設定を全て再設定する。

```shell
[root@6c2ed6cf1a10 /]# for target in `alternatives --list | cut -f1 | grep pgsql`; do alternatives --verbose --auto ${target}; done
reading /var/lib/alternatives/pgsql-createdb
failed to link /usr/bin/createdb -> /etc/alternatives/pgsql-createdb: /usr/bin/createdb exists and it is not a symlink
reading /var/lib/alternatives/pgsql-clusterdbman
reading /var/lib/alternatives/pgsql-reindexdb
failed to link /usr/bin/reindexdb -> /etc/alternatives/pgsql-reindexdb: /usr/bin/reindexdb exists and it is not a symlink
reading /var/lib/alternatives/pgsql-pg_basebackup
reading /var/lib/alternatives/pgsql-createdbman
reading /var/lib/alternatives/pgsql-createuserman
reading /var/lib/alternatives/pgsql-psqlman
reading /var/lib/alternatives/pgsql-pg_dumpman
reading /var/lib/alternatives/pgsql-psql
failed to link /usr/bin/psql -> /etc/alternatives/pgsql-psql: /usr/bin/psql exists and it is not a symlink
reading /var/lib/alternatives/pgsql-vacuumdb
failed to link /usr/bin/vacuumdb -> /etc/alternatives/pgsql-vacuumdb: /usr/bin/vacuumdb exists and it is not a symlink
reading /var/lib/alternatives/pgsql-reindexdbman
reading /var/lib/alternatives/pgsql-pg_dumpallman
reading /var/lib/alternatives/pgsql-pg_restoreman
reading /var/lib/alternatives/pgsql-pg_dumpall
failed to link /usr/bin/pg_dumpall -> /etc/alternatives/pgsql-pg_dumpall: /usr/bin/pg_dumpall exists and it is not a symlink
reading /var/lib/alternatives/pgsql-dropdbman
reading /var/lib/alternatives/pgsql-dropuser
failed to link /usr/bin/dropuser -> /etc/alternatives/pgsql-dropuser: /usr/bin/dropuser exists and it is not a symlink
reading /var/lib/alternatives/pgsql-ld-conf
reading /var/lib/alternatives/pgsql-pg_basebackupman
reading /var/lib/alternatives/pgsql-clusterdb
failed to link /usr/bin/clusterdb -> /etc/alternatives/pgsql-clusterdb: /usr/bin/clusterdb exists and it is not a symlink
reading /var/lib/alternatives/pgsql-pg_dump
failed to link /usr/bin/pg_dump -> /etc/alternatives/pgsql-pg_dump: /usr/bin/pg_dump exists and it is not a symlink
reading /var/lib/alternatives/pgsql-dropdb
failed to link /usr/bin/dropdb -> /etc/alternatives/pgsql-dropdb: /usr/bin/dropdb exists and it is not a symlink
reading /var/lib/alternatives/pgsql-pg_restore
failed to link /usr/bin/pg_restore -> /etc/alternatives/pgsql-pg_restore: /usr/bin/pg_restore exists and it is not a symlink
reading /var/lib/alternatives/pgsql-createuser
failed to link /usr/bin/createuser -> /etc/alternatives/pgsql-createuser: /usr/bin/createuser exists and it is not a symlink
reading /var/lib/alternatives/pgsql-dropuserman
reading /var/lib/alternatives/pgsql-vacuumdbman
```

実態があるため登録できない。（失敗していないものは9.xでは用意されていないコマンドだと思われる。）
よって、一旦9.xを削除する。

```shell
[root@6c2ed6cf1a10 /]# yum list | egrep '^postgresql(|10)(|-libs)\.x86_64'
postgresql.x86_64                         9.2.24-1.el7_5                 @base
postgresql-libs.x86_64                    9.2.24-1.el7_5                 @base
postgresql10.x86_64                       10.8-1PGDG.rhel7               @pgdg10
postgresql10-libs.x86_64                  10.8-1PGDG.rhel7               @pgdg10

[root@6c2ed6cf1a10 /]# yum remove -y postgresql postgresql-libs
…
Removed:
  postgresql.x86_64 0:9.2.24-1.el7_5                                postgresql-libs.x86_64 0:9.2.24-1.el7_5

Complete!
[root@6c2ed6cf1a10 /]# yum list | egrep '^postgresql(|10)(|-libs)\.x86_64'
postgresql10.x86_64                       10.8-1PGDG.rhel7               @pgdg10
postgresql10-libs.x86_64                  10.8-1PGDG.rhel7               @pgdg10
postgresql.x86_64                         9.2.24-1.el7_5                 base
postgresql-libs.x86_64                    9.2.24-1.el7_5                 base
```

9.xを削除すると、実体(psqlコマンドであれば/usr/bin/psql)が消えるだけなので、この時点では10.xにはならない。

```shell
[root@6c2ed6cf1a10 /]# psql -V
bash: /usr/bin/psql: No such file or directory
[root@6c2ed6cf1a10 /]# ls -l /usr/bin/psql
ls: cannot access /usr/bin/psql: No such file or directory
```

実体が消えたところで、`alternatives --auto`コマンドでシンボリックを生成させてみる。

```shell
[root@6c2ed6cf1a10 /]# for target in `alternatives --list | cut -f1 | grep pgsql`; do alternatives --verbose --auto ${target}; done
reading /var/lib/alternatives/pgsql-createdb
reading /var/lib/alternatives/pgsql-clusterdbman
reading /var/lib/alternatives/pgsql-reindexdb
reading /var/lib/alternatives/pgsql-pg_basebackup
reading /var/lib/alternatives/pgsql-createdbman
reading /var/lib/alternatives/pgsql-createuserman
reading /var/lib/alternatives/pgsql-psqlman
reading /var/lib/alternatives/pgsql-pg_dumpman
reading /var/lib/alternatives/pgsql-psql
reading /var/lib/alternatives/pgsql-vacuumdb
reading /var/lib/alternatives/pgsql-reindexdbman
reading /var/lib/alternatives/pgsql-pg_dumpallman
reading /var/lib/alternatives/pgsql-pg_restoreman
reading /var/lib/alternatives/pgsql-pg_dumpall
reading /var/lib/alternatives/pgsql-dropdbman
reading /var/lib/alternatives/pgsql-dropuser
reading /var/lib/alternatives/pgsql-ld-conf
reading /var/lib/alternatives/pgsql-pg_basebackupman
reading /var/lib/alternatives/pgsql-clusterdb
reading /var/lib/alternatives/pgsql-pg_dump
reading /var/lib/alternatives/pgsql-dropdb
reading /var/lib/alternatives/pgsql-pg_restore
reading /var/lib/alternatives/pgsql-createuser
reading /var/lib/alternatives/pgsql-dropuserman
reading /var/lib/alternatives/pgsql-vacuumdbman
```

エラーは発生しない。

バージョンが10.xになったことを確認。

```shell
[root@6c2ed6cf1a10 /]# psql -V
psql (PostgreSQL) 10.8

[root@6c2ed6cf1a10 /]# which psql
/usr/bin/psql

[root@6c2ed6cf1a10 /]# ls -l /usr/bin/psql
lrwxrwxrwx 1 root root 28 Jun 19 09:18 /usr/bin/psql -> /etc/alternatives/pgsql-psql
```

alternativesを経由して10.xに紐づいていることがわかる。

## まとめ
alternativesで管理されていない9.xがインストースされている環境に10.xをインストールするとコマンド群が9.xを向いたままになってしまう。もし10.xのみ必要な場合は、一旦9.xを削除した上で、以下のコマンドを発行し、紐付けを有効化できる。

```shell
# for target in `alternatives --list | cut -f1 | grep pgsql`; do alternatives --verbose --auto ${target}; done
```

感の良い方は、単純に10.xを再インストールすれば良いだけではと思われると思うが、、、その通りである。

もし10.xのpostgresqlが稼働中で、再インストールはしたくないという状況であれば利用できるかもしれない。

## あとがき
なんでこんな実際には起きないだろうという状況の問題解決を書いたかというと、、、
実際に起こった問題を、簡単化しようとして、問題をすり替えてしまったからである。

実際に起こった問題は以下の通り。

1. 10.xがインストールされている状態で9.xをインンストール
2. 10.xを既に運用していたのに、コマンド群が9.xをさすようになってしまった
3. (10.xに戻すために)あわてて9.xを削除したところ、コマンド群が利用できなくなった
4. 10.xを再インストールすることなくコマンド群が利用できる状態にしたい

でも状況の説明が難しいし、問題簡単化すればいいかと思って問題の提示方法を変えてしまった。
それによって、その状況なら再インストールすれば良くない？という感じになってしまった。

まあ、alternativeってこんな仕組みなんだということが伝わればいいかなということで、ご勘弁いただければと思う。

## 参考URL
[RPMで複数バージョンのPostgreSQLをインストールしてみよう \| Let's Postgres](https://lets.postgresql.jp/documents/tutorial/new_rpm)