はじめに
昨今ではAWS上でRDBを利用する際、たいていの場合はRDSを使ってしまうので、EC2インスタンス内にPostgreSQLをインストールする事は少なくなりましたが、ちょっとした検証などでは利用することがあったりします。
Amazon Linux 2のyumリポジトリでインストール可能なバージョンはPostgreSQL9.2と、些か古いバージョンです。
本稿では、PostgreSQLの公式リポジトリを用いてPostgreSQL 12をインストールする手順と、これをAnsible Playbook化したものを紹介します。
なお、Ansible Playbookは下記Gitリポジトリから参照できるようにしてあります。
https://github.com/tmiki/server-config/tree/master/ansible/roles/common_postgresql12
本稿によって実現できること
- ローカルPCのVM上に構築したAmazon Linux 2に、PostgreSQL公式のyumリポジトリ ( https://yum.postgresql.org/repopackages.php ) をインストールする
- initdbコマンドによりPostgreSQLのデータベースを初期化する
- 作成したPostgreSQL環境に、作業用のユーザアカウント・作業用データベースを作成する
- 作業用のユーザアカウントで、PostgreSQLにTCP/IP接続できるようにする
- 上記までの作業を全てAnsible Playbookで実現する
検証した環境
- ホストOS
- Windows 10 Pro 10.0.17763 Build 17763
- Oracle VirtualBox 6.0.6 r130049 (Qt5.6.2)
- Vagrant 2.2.4
- ゲストOS
- Amazon Linux 2 cpe:2.3amazon:amazon_linux:2
- postgresql12-server.x86_64 12.1-2PGDG.rhel7
- ansible 2.9.1
- Python 2.7.14 (※amzn2-coreリポジトリでのサポートはまだしばらく続くと信じたい)
作業手順
作業ステップ
- PostgreSQLのyumリポジトリをOSにインストールする
- PostgreSQLのパッケージをインストールする
- initdbを実行する
- 作業用PostgreSQLユーザ・作業用データベースを作成する
- ゲストOSからTCP/IP経由で接続できるよう設定する
手順詳細
PostgreSQLのyumリポジトリをOSにインストールする
PostgreSQLが提供するyumリポジトリは下記からダウンロードすることができます。
https://yum.postgresql.org/repopackages.php
Amazon Linux 2は概ねCentOS 7をベースにしているので、CentOS 7用のリポジトリをインストールします。
https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm
ただし、/etc/redhat-releaseファイルが存在しないため、そのままインストールしようとするとエラーとなります。
パッケージの構成上、/etc/redhat-releaseファイルに依存しているためです。
$ sudo rpm -ivh https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm
Retrieving https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm
warning: /var/tmp/rpm-tmp.EKzLbz: Header V4 DSA/SHA1 Signature, key ID 442df0f8: NOKEY
error: Failed dependencies:
/etc/redhat-release is needed by pgdg-redhat-repo-42.0-5.noarch
/etc/redhat-releaseファイルへの依存関係を無視してインストールするため、「--nodeps」オプションを付けてインストールします。
$ sudo rpm -ivh --nodeps https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm
warning: /var/tmp/rpm-tmp.hLzMG7: Header V4 DSA/SHA1 Signature, key ID 442df0f8: NOKEY
Preparing... ################################# [100%]
Updating / installing...
1:pgdg-redhat-repo-42.0-5 ################################# [100%]
下記コマンドで、インストールが完了したことを確認します。
$ yum list installed | grep pgdg
pgdg-redhat-repo.noarch 42.0-5 installed
$ rpm -ql pgdg-redhat-repo
/etc/pki/rpm-gpg
/etc/pki/rpm-gpg/RPM-GPG-KEY-PGDG
/etc/yum.repos.d/pgdg-redhat-all.repo
なおこの状態では、リポジトリの設定ファイルの変数をうまく処理できずに、PostgreSQLのパッケージをインストールできません。
試しにpostgresql-12パッケージのインストールを試みると、下記のようにエラーとなります。
$ sudo yum install -y postgresql12
Loaded plugins: langpacks, priorities, update-motd
amzn2-core | 2.4 kB 00:00:00
amzn2extra-docker | 1.3 kB 00:00:00
amzn2extra-epel | 1.3 kB 00:00:00
epel/x86_64/metalink | 9.1 kB 00:00:00
https://download.postgresql.org/pub/repos/yum/10/redhat/rhel-2-x86_64/repodata/repomd.xml: [Errno 14] HTTPS Error 404 - Not Found
Trying other mirror.
One of the configured repositories failed (PostgreSQL 10 for RHEL/CentOS 2 - x86_64),
and yum doesn't have enough cached data to continue. At this point the only
safe thing yum can do is fail. There are a few ways to work "fix" this:
1. Contact the upstream for the repository and get them to fix the problem.
2. Reconfigure the baseurl/etc. for the repository, to point to a working
upstream. This is most often useful if you are using a newer
distribution release than is supported by the repository (and the
packages for the previous distribution release still work).
3. Run the command with the repository temporarily disabled
yum --disablerepo=pgdg10 ...
4. Disable the repository permanently, so yum won't use it by default. Yum
will then just ignore the repository until you permanently enable it
again or use --enablerepo for temporary usage:
yum-config-manager --disable pgdg10
or
subscription-manager repos --disable=pgdg10
5. Configure the failing repository to be skipped, if it is unavailable.
Note that yum will try to contact the repo. when it runs most commands,
so will have to try and fail each time (and thus. yum will be be much
slower). If it is a very temporary problem though, this is often a nice
compromise:
yum-config-manager --save --setopt=pgdg10.skip_if_unavailable=true
failure: repodata/repomd.xml from pgdg10: [Errno 256] No more mirrors to try.
https://download.postgresql.org/pub/repos/yum/10/redhat/rhel-2-x86_64/repodata/repomd.xml: [Errno 14] HTTPS Error 404 - Not Found
「/etc/yum.repos.d/pgdg-redhat-all.repo」ファイル内の「$releasever」という変数をうまく解決できないからだと思われます。
$ head /etc/yum.repos.d/pgdg-redhat-all.repo
# PGDG Red Hat Enterprise Linux / CentOS stable repositories:
[pgdg12]
name=PostgreSQL 12 for RHEL/CentOS $releasever - $basearch
baseurl=https://download.postgresql.org/pub/repos/yum/12/redhat/rhel-$releasever-$basearch
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-PGDG
sedコマンドで、これを下記のように換えます。
$ sudo sed -i 's/\$releasever/7/g' /etc/yum.repos.d/pgdg-redhat-all.repo
「/etc/yum.repos.d/pgdg-redhat-all.repo」ファイルの内容が書き換わったことを確認します。
$ head /etc/yum.repos.d/pgdg-redhat-all.repo
# PGDG Red Hat Enterprise Linux / CentOS stable repositories:
[pgdg12]
name=PostgreSQL 12 for RHEL/CentOS 7 - $basearch
baseurl=https://download.postgresql.org/pub/repos/yum/12/redhat/rhel-7-$basearch
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-PGDG
PostgreSQLのパッケージをインストールする
yumリポジトリの設定が完了したら、あとは普通にyumコマンドでPostgreSQLのパッケージをインストールします。
$ sudo yum install -y postgresql12 postgresql12-server
※途中省略
pgdg-redhat-repo-42.0-5.noarch has missing requires of /etc/redhat-release
Installing : postgresql12-libs-12.1-2PGDG.rhel7.x86_64 1/3
Installing : postgresql12-12.1-2PGDG.rhel7.x86_64 2/3
Installing : postgresql12-server-12.1-2PGDG.rhel7.x86_64 3/3
Verifying : postgresql12-libs-12.1-2PGDG.rhel7.x86_64 1/3
Verifying : postgresql12-server-12.1-2PGDG.rhel7.x86_64 2/3
Verifying : postgresql12-12.1-2PGDG.rhel7.x86_64 3/3
Installed:
postgresql12.x86_64 0:12.1-2PGDG.rhel7 postgresql12-server.x86_64 0:12.1-2PGDG.rhel7
Dependency Installed:
postgresql12-libs.x86_64 0:12.1-2PGDG.rhel7
Complete!
これでインストールは完了です。
initdbを実行する
インストール後、PostgreSQLのデータベースを初期化するため、initdbを実行します。
インストール直後は、下記のように「/var/lib/pgsql/12/data/」ディレクトリ配下は空となっています。
$ sudo ls -la /var/lib/pgsql/12/data/
total 0
drwx------ 2 postgres postgres 6 Nov 30 13:31 .
drwx------ 4 postgres postgres 33 Dec 29 16:59 ..
initdbを実行します。
ここでデフォルトのエンコーディングをUTF-8、ロケールをCに指定します。明示的にロケールを指定しない場合、ログインユーザの環境変数(LOCALEやLANGなど)からロケール情報が取得され、これが利用されます。おそらくそのままだと「en_US.UTF-8」が指定されます。
ソート時に意図したとおりにならない、といったことにつながりますので、ここで明示的にロケールとしてCを指定します。
initdbへの引数はコマンドラインから直接指定できないようなので、PGSETUP_INITDB_OPTIONS環境変数経由で指定します。
$ PGSETUP_INITDB_OPTIONS='--encoding=UTF-8 --locale=C' sudo /usr/pgsql-12/bin/postgresql-12-setup initdb
Initializing database ... OK
「/var/lib/pgsql/12/data/」配下に下記のようなファイルが作成されていることを確認します。
$ sudo ls -la /var/lib/pgsql/12/data/
total 56
drwx------ 20 postgres postgres 4096 Dec 29 17:02 .
drwx------ 4 postgres postgres 51 Dec 29 17:01 ..
drwx------ 5 postgres postgres 41 Dec 29 17:02 base
drwx------ 2 postgres postgres 4096 Dec 29 17:02 global
drwx------ 2 postgres postgres 6 Dec 29 17:02 log
drwx------ 2 postgres postgres 6 Dec 29 17:01 pg_commit_ts
drwx------ 2 postgres postgres 6 Dec 29 17:01 pg_dynshmem
-rw------- 1 postgres postgres 4269 Dec 29 17:01 pg_hba.conf
-rw------- 1 postgres postgres 1636 Dec 29 17:01 pg_ident.conf
drwx------ 4 postgres postgres 68 Dec 29 17:02 pg_logical
drwx------ 4 postgres postgres 36 Dec 29 17:01 pg_multixact
drwx------ 2 postgres postgres 18 Dec 29 17:01 pg_notify
drwx------ 2 postgres postgres 6 Dec 29 17:01 pg_replslot
drwx------ 2 postgres postgres 6 Dec 29 17:01 pg_serial
drwx------ 2 postgres postgres 6 Dec 29 17:01 pg_snapshots
drwx------ 2 postgres postgres 6 Dec 29 17:01 pg_stat
drwx------ 2 postgres postgres 6 Dec 29 17:01 pg_stat_tmp
drwx------ 2 postgres postgres 18 Dec 29 17:01 pg_subtrans
drwx------ 2 postgres postgres 6 Dec 29 17:01 pg_tblspc
drwx------ 2 postgres postgres 6 Dec 29 17:01 pg_twophase
-rw------- 1 postgres postgres 3 Dec 29 17:01 PG_VERSION
drwx------ 3 postgres postgres 60 Dec 29 17:01 pg_wal
drwx------ 2 postgres postgres 18 Dec 29 17:01 pg_xact
-rw------- 1 postgres postgres 88 Dec 29 17:01 postgresql.auto.conf
-rw------- 1 postgres postgres 26612 Dec 29 17:01 postgresql.conf
postgresql-12サービスを起動させます。
$ sudo systemctl enable --now postgresql-12
Created symlink from /etc/systemd/system/multi-user.target.wants/postgresql-12.service to /usr/lib/systemd/system/postgresql-12.service.
postgresql-12サービスがactiveになっていることを確認します。
$ systemctl status postgresql-12
● postgresql-12.service - PostgreSQL 12 database server
Loaded: loaded (/usr/lib/systemd/system/postgresql-12.service; enabled; vendor preset: disabled)
Active: active (running) since Sun 2019-12-29 17:18:34 UTC; 28s ago
Docs: https://www.postgresql.org/docs/12/static/
Process: 6019 ExecStartPre=/usr/pgsql-12/bin/postgresql-12-check-db-dir ${PGDATA} (code=exited, status=0/SUCCESS)
Main PID: 6056 (postmaster)
Tasks: 8
Memory: 17.3M
CGroup: /system.slice/postgresql-12.service
tq6056 /usr/pgsql-12/bin/postmaster -D /var/lib/pgsql/12/data/
tq6065 postgres: logger
tq6067 postgres: checkpointer
tq6068 postgres: background writer
tq6069 postgres: walwriter
tq6070 postgres: autovacuum launcher
tq6071 postgres: stats collector
mq6072 postgres: logical replication launcher
作業用PostgreSQLユーザ・作業用データベースを作成する
デフォルトでは「postgres」ユーザしか存在しません。
これはまた、Superuser権限を持ったユーザであり、通常運用するには適していません。
PostgreSQLの通常運用に用いるユーザとして、ここでは例として「vagrant」ユーザを作成します。パスワードは「postgresvagrant」とします。
また当該ユーザ用のデフォルトデータベースとして「vagrant」データベースを作成します。
PostgreSQL: Documentation: 12: CREATE USER
PostgreSQL: Documentation: 12: ALTER USER
### いったん、postgresユーザにsuする
$ sudo su - postgres
$ id
uid=26(postgres) gid=26(postgres) groups=26(postgres)
### psqlコマンドでPostgreSQLに接続して「vagrant」ユーザを作成し、パスワードを初期化
$ psql
psql (12.1)
Type "help" for help.
postgres=# create user vagrant;
CREATE ROLE
# alter user vagrant with password 'postgresvagrant';
ALTER ROLE
vagrantユーザ用のデフォルトデータベースを作成します。
PostgreSQL: Documentation: 12: CREATE DATABASE
postgres=# create database vagrant owner vagrant;
CREATE DATABASE
上記までの作業とは別のターミナルを開き、vagrantユーザでログインし、psqlコマンドでデータベースに接続できること、テーブルを作成できることを確認します。
### vagrantユーザであることを確認
$ id
uid=1000(vagrant) gid=1000(vagrant) groups=1000(vagrant),1101(docker)
### psqlコマンドを実行し、PostgreSQLに接続できることを確認
$ psql
psql (12.1)
Type "help" for help.
vagrant=>
### 適当なテーブルを作成し、対象のデータベースの操作権限があることを確認
vagrant=> create table sample_users (
vagrant(> user_id serial not null,
vagrant(> user_name text
vagrant(> );
CREATE TABLE
PostgreSQLの認証方式について
psqlコマンドでPostgreSQLに接続する際、UNIXドメインソケット経由で接続する場合はパスワードは不要となります。
デフォルトのpg_hba.conf上、下記のように設定されているからです。
まず接続方式「local」はUNIXドメインソケットでの接続を表しており、またこの方式での接続の際には「peer」という認証が行われます。
「peer」認証は、OSにログインしているユーザIDと、PostgreSQLユーザIDを取得し、両者が一致するかチェックする方式となります。
$ sudo grep "^local" /var/lib/pgsql/12/data/pg_hba.conf
local all all peer
local replication all peer
PostgreSQL: Documentation: 12: 20.1. The pg_hba.conf File
公式ドキュメントから、接続方式localについての説明を引用します。
local
This record matches connection attempts using Unix-domain sockets. Without a record of this type, Unix-domain socket connections are disallowed.
以下、認証方式「peer」の説明を引用します。
auth-method
Specifies the authentication method to use when a connection matches this record. The possible choices are summarized here; details are in Section 20.3.
※途中省略
peer
Obtain the client's operating system user name from the operating system and check if it matches the requested database user name. This is only available for local connections. See Section 20.9 for details.
ホストOSからTCP/IP経由で接続できるよう設定する
デフォルトのpostgresql.conf、およびpg_hba.confの設定上、OSローカルからの接続のみが許可される状態となっており、他のホストからの接続はそのままでは許可されません。
大きく以下の2つの設定を行うことにより、他ホストからPostgreSQLに対して直接接続できるようになります。
- postgresql.confを変更し、bindするIPアドレスを127.0.0.1から0.0.0.0に変更
- pg_hba.confを変更し、指定したIPアドレスからのTCP/IP接続に対してmd5認証を行うよう変更
まず、postgresql.confの設定から、bindするIPアドレスの設定を確認します。
デフォルトでは「localhost」、つまり127.0.0.1のみbindする状態となっています。
この設定を変更し、0.0.0.0でListenするようにします。
$ sudo grep -A 3 listen_addresses /var/lib/pgsql/12/data/postgresql.conf
#listen_addresses = 'localhost' # what IP address(es) to listen on;
# comma-separated list of addresses;
# defaults to 'localhost'; use '*' for all
# (change requires restart)
下記のように設定することで、bindするIPアドレスを0.0.0.0に変更することができます。
listen_addresses = '*'
つぎに、pg_hba.confに下記のエントリを追加します。ここで、ホストOSとゲストOSのネットワークセグメントは「192.168.255.0/24」であるものとします。
この設定は、接続方式「host」、つまりTCP/IP接続に対してmd5認証を行う、ということを意味しています。
接続可能なIPアドレスは「127.0.0.1/32」及び「192.168.255.0/24」となります。
# セキュリティ上、scram-sha-256で運用するのが好ましいですが、本稿では対象外とします。
PostgreSQL: Documentation: 12: 20.1. The pg_hba.conf File
host all all 127.0.0.1/32 md5
host all all 192.168.255.0/24 md5
postgresql.conf及びpg_hba.confの設定は、postgresql-12サービスのreload/restartが必要です。
下記のようにリロード/リスタートします。
### リロード
$ sudo systemctl reload postgresql-12
### リスタート
$ sudo systemctl restart postgresql-12
vagrantユーザから、TCP/IP接続でPostgreSQLに接続できることを確認します。
$ id
uid=1000(vagrant) gid=1000(vagrant) groups=1000(vagrant),1101(docker)
$ psql -h 127.0.0.1 -W
Password:
psql (12.1)
Type "help" for help.
vagrant=>
Ansible Playbook化する
上記までの設定作業を、Ansible Playbook化します。
まとめたものは下記にもあります。
https://github.com/tmiki/server-config/blob/master/ansible/roles/common_postgresql12/tasks/setup-AmazonLinux2.yml
PostgreSQLのyumリポジトリをOSにインストールする
まず、PostgreSQL公式のyumリポジトリをインストールする必要がありますが、「--nodeps」オプションが必須となります。
Ansibleのyumモジュール上、これに該当するオプションがどうやらなさそうだったので、commandモジュールで代替することとしました。
また、対象ファイル内の文字列を一括で置換するreplaceモジュールがあるので、sedコマンドをcommand/shellモジュールで実行する必要はありません。
yum – Manages packages with the yum package manager — Ansible Documentation
command – Execute commands on targets — Ansible Documentation
replace – Replace all instances of a particular string in a file using a back-referenced regular expression — Ansible Documentation
- name: Install a yum repository file of pgdg 1/2.
command: "rpm -ivh --nodeps https://download.postgresql.org/pub/repos/yum/12/redhat/rhel-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm"
args:
creates: /etc/yum.repos.d/pgdg-redhat-all.repo
warn: no
- name: Install a yum repository file of pgdg 2/2.
replace: dest=/etc/yum.repos.d/pgdg-redhat-all.repo regexp='\$releasever' replace='7'
PostgreSQLのパッケージをインストールする
次にpostgresql12、postgresql12-serverパッケージをインストールします。
併せて、python-psycopg2というモジュールをインストールしていますが、これはAnsibleのpostgresql_user、postgresql_dbモジュールの実行に必要なものとなります。
postgresql_user – Add or remove a user (role) from a PostgreSQL server instance — Ansible Documentation
postgresql_db – Add or remove PostgreSQL databases from a remote host — Ansible Documentation
- name: Install PostgreSQL 12 packages.
yum:
name:
- python-psycopg2
- postgresql12
- postgresql12-server
postgresql-12サービス用のhandlerを作る
handlers/main.ymlに、下記のようなハンドラを作っておきます。
- name: restart postgresql12 service
systemd: name=postgresql-12 state=restarted
- name: reload postgresql12 service
systemd: name=postgresql-12 state=reloaded
initdbを実行する
initdbはコマンドの実行であるため、commandモジュールを利用せざるを得ません。
冪等性を確保するため、PG_VERSIONファイルの有無を判別し、これが存在するときはコマンドを実行しないようにします。
initdb実行後、postgresql-12サービスをいったん起動させます。
- name: Perform the initdb command.
command: "/usr/pgsql-12/bin/postgresql-12-setup initdb"
environment:
PGSETUP_INITDB_OPTIONS: '--encoding=UTF-8 --locale=C'
args:
creates: /var/lib/pgsql/12/data/PG_VERSION
warn: no
- name: Start the PostgreSQL 12 service and make it running on rebooting
systemd:
name: postgresql-12
enabled: yes
state: started
ゲストOSからTCP/IP経由で接続できるよう設定する
postgresql.confとpg_hba.confを変更します。設定内容は、手動で変更した際の内容と同一です。
設定ファイルに変更があった場合、postgresql12サービスをreloadするよう、notifyを設定しておきます。
- name: Make the PostgreSQL server can be connected with TCP/IP via the VM dedicated local network segment. 1/2.
lineinfile:
path: /var/lib/pgsql/12/data/postgresql.conf
regexp: "^listen_addresses = .*$"
line: "listen_addresses = '*'"
backup: yes
notify:
restart postgresql12 service
- name: Make the PostgreSQL server can be connected with TCP/IP via the VM dedicated local network segment. 2/2.
lineinfile:
path: /var/lib/pgsql/12/data/pg_hba.conf
regexp: "host.*all.*all.*192.168.255.0/24"
line: "host\tall\t\tall\t\t192.168.255.0/24\tmd5"
backup: yes
notify:
reload postgresql12 service
- name: Make the PostgreSQL server can be connected with TCP/IP and md5 hash authN via the loopback interface.
lineinfile:
path: /var/lib/pgsql/12/data/pg_hba.conf
regexp: "host.*all.*all.*127.0.0.1/32.*ident"
line: "host\tall\t\tall\t\t127.0.0.1/32\t\tmd5"
backup: yes
notify:
reload postgresql12 service
作業用PostgreSQLユーザ・作業用データベースを作成する
vagrantユーザと、vagrantユーザ用のデータベースを作成します。
ここで、Ansibleのpostgresql_user、postgresql_dbモジュールを利用しています。
postgresql_user – Add or remove a user (role) from a PostgreSQL server instance — Ansible Documentation
postgresql_db – Add or remove PostgreSQL databases from a remote host — Ansible Documentation
- name: Create a PostgerSQL user named "{{ login_user_name }}" for the default OS user.
become: yes
become_user: postgres
postgresql_user:
login_unix_socket:
login_user: postgres
name: "{{ login_user_name }}"
password: "{{ login_user_name }}"
- name: Create a default database for the user named "{{ login_user_name }}".
become: yes
become_user: postgres
postgresql_db:
login_unix_socket:
login_user: postgres
name: "{{ login_user_name }}"
owner: "{{ login_user_name }}"
state: present
おわりに
PostgreSQL公式のyumリポジトリは、Amazon Linux 2をサポートしておらず、本稿で実施した方式は将来的に利用できなくなる可能性があります。
飽くまで、手元でちょっとした動作確認・検証等に利用する用途を想定しています。
いずれにせよ本番環境等、重要な環境で利用するのはお勧めしません。
実際のシステムではおそらくAmazon Aurora PostgreSQLを利用することになるかと思いますので、問題はないとは思いますが。